Fix some minor issues and re-enable building of DE, ES, FR, and IT locale data (help...
[oweals/cde.git] / cde / programs / dtwm / WmFunction.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.4
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$TOG: WmFunction.c /main/19 1998/04/20 13:00:48 mgreess $"
33 #endif
34 #endif
35 /*
36  * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 HEWLETT-PACKARD COMPANY 
37  * (c) Copyright 1993, 1994 International Business Machines Corp.
38  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  * (c) Copyright 1993, 1994 Novell, Inc.
40  */
41
42 /*
43  * Included Files:
44  */
45
46 #include "WmGlobal.h"
47 #ifndef WSM
48 #include <signal.h>
49 #endif
50 #include <stdio.h>
51 #include <X11/Xos.h>
52 #include "WmICCC.h"
53 #ifdef WSM
54 #include "WmWrkspace.h"  /* for ClientInWorkspace() test */
55 #include <Dt/EnvControlP.h>  /* for restoring **environ before an exec() */
56 #include "WmResNames.h"
57 #include <Dt/Message.h>
58 #include <Dt/Help.h>
59 #endif /* WSM */
60 #ifdef PANELIST
61 #include <Dt/DtStrDefs.h>
62 #include "WmPanelP.h"
63 #include "WmSignal.h"
64 #endif /* PANELIST */
65
66 /*
67  * include extern functions
68  */
69 #include "WmFunction.h"
70 #include "WmCEvent.h"
71 #ifdef WSM
72 #include "WmHelp.h"
73 #endif /* WSM */
74 #include "WmCDInfo.h"
75 #include "WmColormap.h"
76 #include "WmError.h"
77 #include "WmEvent.h"
78 #include "WmFeedback.h"
79 #ifdef WSM
80 #include "WmIPC.h"
81 #endif /* WSM */
82 #include "WmIPlace.h"
83 #include "WmIconBox.h"
84 #include "WmKeyFocus.h"
85 #include "WmMenu.h"
86 #ifdef WSM
87 #include "WmPresence.h"
88 #endif /* WSM */
89 #include "WmProperty.h"
90 #include "WmProtocol.h"
91 #include "WmResParse.h"
92 #include "WmWinConf.h"
93 #include "WmWinInfo.h"
94 #include "WmWinList.h"
95 #include "WmWinState.h"
96 #include "WmXSMP.h"
97
98 #include <Xm/RowColumnP.h> /* for MS_LastManagedMenuTime */
99 extern XmMenuState _XmGetMenuState();
100
101 extern int putenv ();
102 extern char * getenv ();
103 #ifndef PORT_NOVFORK
104 extern pid_t vfork();
105 #endif /* PORT_NOVFORK */
106
107 static unsigned int GetEventInverseMask(XEvent *event);
108
109 #ifdef WSM
110
111 #if (defined(USL) || defined(__uxp__) || defined(linux)) && !defined(_NFILE)
112 #define _NFILE FOPEN_MAX
113 #endif
114 #define CLOSE_FILES_ON_EXEC() \
115 {int ifx; for (ifx=3; ifx < _NFILE; ifx++) (void) fcntl (ifx, F_SETFD, 1);}
116
117 #endif /* WSM */
118 /*
119  * Global Variables:
120  */
121
122 /*
123  * The 'dirty' variables are used to keep track of the transient window
124  * that has been lowered via "f.lower freeFamily".
125  */
126 static ClientData *dirtyStackEntry = NULL;
127 static ClientData *dirtyLeader = NULL;
128
129 #ifdef WSM
130 \f
131 /***********************<->*************************************
132  *
133  *  F_Action (args, pCD, event)
134  *
135  *
136  *  Description:
137  *  -----------
138  *  This is the window manager function handler for invoking actions.
139  *
140  *
141  *  Inputs:
142  *  ------
143  *  args = action function and arguments
144  *
145  *  pCD = pointer to the ClientData for the whole front panel
146  *
147  *  event = X event that invoked the function (key, button, or menu/NULL)
148  *
149  *
150  *  Outputs:
151  *  -------
152  *  RETURN = if True then further button binding/function processing can
153  *           be done for the event that caused this function to be called.
154  *
155  *  Comments:
156  *  -------
157  *  The pCD->controlWindow is a temporary area used solely for
158  *  this function invocation--it stores the pCW of the control
159  *  that want the function to happen.
160  ******************************<->***********************************/
161
162 Boolean
163 F_Action (String actionName, ClientData *pCD, XEvent *event)
164 {
165
166     WmActionArg *pAP = (WmActionArg *) actionName;
167
168     /* make sure the command runs on the right display. */
169     if (wmGD.pActiveSD->displayString)
170     {
171         putenv(wmGD.pActiveSD->displayString);
172     }
173
174     if (wmGD.dtSD)
175     {
176         WmFrontPanelSetBusy (True);
177     }
178
179     
180     DtActionInvoke (wmGD.pActiveSD->screenTopLevelW1,
181                     pAP->actionName, pAP->aap, pAP->numArgs,
182                     pAP->szExecParms, NULL, NULL, 1, NULL, NULL);
183     
184     /*
185      * Restore original DISPLAY environment variable 
186      */
187     if(wmGD.pActiveSD->displayString && wmGD.displayString)
188     {
189         putenv(wmGD.displayString);
190     }
191
192     return (True);
193     
194 } /* END OF FUNCTION F_Action */
195 #endif /* WSM */
196
197 \f
198 /******************************<->*************************************
199  *
200  *  F_Beep (args, pCD, event)
201  *
202  *
203  *  Description:
204  *  -----------
205  *  This is the window manager function handler for beeping.
206  *
207  *
208  *  Inputs:
209  *  ------
210  *  args = function arguments (specified in .mwmrc file)
211  *
212  *  pCD = pointer to the client data for the client window to which the
213  *        function is to be applied
214  *
215  *  event = X event that invoked the function (key, button, or menu/NULL)
216  *
217  *
218  *  Outputs:
219  *  -------
220  *  RETURN = if True then further button binding/function processing can
221  *           be done for the event that caused this function to be called.
222  *
223  ******************************<->***********************************/
224
225 Boolean F_Beep (String args, ClientData *pCD, XEvent *event)
226 {
227
228     /* !!! what is a good value for percent (the second arg) !!! */
229     XBell (DISPLAY, 0);
230
231     return (True);
232
233 } /* END OF FUNCTION F_Beep */
234
235
236 \f
237 /*
238  * Handle Special case where the dirty window is the top most
239  * transient window.  When this is the case, raising the window
240  * that was on top (the window just below the dirty window) will
241  * fail because Mwm stack database is out of sync.  So the solution
242  * is to restack the dirty transient relative to the second to the
243  * top transient.  This function is used to support freeFamily stacking.
244  */
245 ClientData * FindSecondToTopTransient (pcd)
246 ClientData *pcd;
247 {
248     ClientData *pcdNext;
249     static ClientData *second;
250
251     pcdNext = pcd->transientChildren;
252     while (pcdNext)
253     {
254         if (pcdNext->transientChildren)
255         {
256             if (!pcdNext->transientChildren->transientChildren)
257             {
258                 second = pcdNext;
259             }
260             FindSecondToTopTransient (pcdNext);
261         }
262         pcdNext = pcdNext->transientSiblings;
263         if (pcdNext && !pcdNext->transientSiblings)
264         {
265             second = pcdNext;
266         }
267     }
268
269     return (second);
270
271 } /* END OF FUNCTION */
272
273
274 \f
275 Boolean ForceLowerWindow (ClientData *pcd)
276 {
277 #if 0
278     Window stackWindow;
279     WmScreenData *pSD = (ACTIVE_WS)->pSD;
280 #endif
281     XWindowChanges changes;
282     Boolean restack = False;
283 #ifdef WSM
284     Window stackWindow;
285     WmScreenData *pSD = (ACTIVE_WS)->pSD;
286     unsigned int mask;
287     ClientListEntry     *pCLE;
288
289     /* 
290      * Find lowest window in this workspace. We'll stack this transient
291      * below it.
292      */
293     pCLE = pSD->lastClient;
294     stackWindow = None;
295     mask = CWStackMode;
296     while (pCLE != NULL)
297     {
298         if ((pCLE->pCD != pcd) &&
299             (ClientInWorkspace (ACTIVE_WS, pCLE->pCD)))
300         {
301             if ((pCLE->type == MINIMIZED_STATE) &&
302                 (pCLE->pCD->clientState == MINIMIZED_STATE))
303             {
304                 stackWindow = ICON_FRAME_WIN(pCLE->pCD);
305             }
306             else if ((pCLE->type == NORMAL_STATE) &&
307                      ((pCLE->pCD->clientState == NORMAL_STATE) ||
308                       (pCLE->pCD->clientState == MAXIMIZED_STATE)))
309             {
310                 stackWindow = pCLE->pCD->clientFrameWin;
311             }
312
313             if (stackWindow != None)
314             {
315                 mask |= CWSibling;
316                 changes.sibling = stackWindow;
317                 break;
318             }
319         }
320         if (stackWindow == None)
321         {
322             pCLE = pCLE->prevSibling;
323         }
324     }
325 #endif /* WSM */
326 #if 0
327     if (pSD->lastClient->type == MINIMIZED_STATE)
328     {
329         stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
330     }
331     else
332     {
333         stackWindow = pSD->lastClient->pCD->clientFrameWin;
334     }
335 #endif
336
337     changes.stack_mode = Below;
338 #ifdef WSM
339     if (mask)
340     {
341         XConfigureWindow (DISPLAY, pcd->clientFrameWin, mask, &changes);
342     }
343 #else /* WSM */
344     XConfigureWindow (DISPLAY, pcd->clientFrameWin, CWStackMode,
345                       &changes);
346 #endif /* WSM */
347
348     return (restack);
349 }
350
351
352 \f
353 /*************************************<->*************************************
354  *
355  *  F_Lower (args, pCD, event)
356  *
357  *
358  *  Description:
359  *  -----------
360  *  This is the window manager function handler for bottoming a client window
361  *  or icon.
362  *
363  *
364  *  Inputs:
365  *  ------
366  *  args = function arguments (specified in .mwmrc file)
367  *
368  *  pCD = pointer to the client data for the client window to which the
369  *        function is to be applied
370  *
371  *  event = X event that invoked the function (key, button, or menu/NULL)
372  *
373  *
374  *  Outputs:
375  *  -------
376  *  RETURN = if True then further button binding/function processing can
377  *           be done for the event that caused this function to be called.
378  *
379  *************************************<->***********************************/
380
381 Boolean F_Lower (String args, ClientData *pCD, XEvent *event)
382 {
383     ClientListEntry *pEntry;
384     ClientListEntry *pNextEntry;
385     ClientListEntry *pStackEntry;
386     String string = args;
387     int flags = STACK_NORMAL;
388 #ifdef WSM
389     WmWorkspaceData *pWS = ACTIVE_WS;
390 #endif /* WSM */
391
392     if (string)
393     {
394         /* process '-client' argument */
395         if (string[0] == '-')
396         {
397             string = &string[1];
398             string = (String) GetString ((unsigned char **) &string);
399
400             pStackEntry = NULL;
401             pNextEntry = ACTIVE_PSD->lastClient;
402             while (pNextEntry &&
403                    (pEntry = FindClientNameMatch (pNextEntry, False,
404                                                         string, F_GROUP_ALL)))
405             {
406                 pNextEntry = pEntry->prevSibling;
407 #ifdef WSM
408                 if (ClientInWorkspace (pWS, pEntry->pCD))
409                 {
410 #endif /* WSM */
411                 Do_Lower (pEntry->pCD, pStackEntry, STACK_NORMAL);
412                 pStackEntry = pEntry;
413 #ifdef WSM
414                 }
415 #endif /* WSM */
416             }
417         }
418         /* process family stacking stuff */
419         else if (*string)
420         {
421             unsigned int  slen, len, index;
422
423             slen = strlen(args) - 2;            /* subtract '\n' and NULL */
424             for (index = 0; index < slen; string = &args[index+1])
425             {
426                 if ((string = (String) GetString ((unsigned char **) &string)) == NULL)
427                    break;
428                 len = strlen(string);
429                 if (!strcmp(string,"within"))
430                 {
431                     flags |= STACK_WITHIN_FAMILY;
432                 }
433                 else if (!strcmp(string,"freeFamily"))
434                 {
435                     flags |= STACK_FREE_FAMILY;
436                 }
437                 index += len;
438             }
439 #ifdef WSM
440             if (ClientInWorkspace (pWS, pCD))
441             {
442 #endif /* WSM */
443             Do_Lower (pCD, (ClientListEntry *) NULL, flags);
444 #ifdef WSM
445             }
446 #endif /* WSM */
447         }
448     }
449     else if (pCD)
450     {
451 #ifdef WSM
452             if (ClientInWorkspace (pWS, pCD))
453             {
454 #endif /* WSM */
455         Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
456 #ifdef WSM
457             }
458 #endif /* WSM */
459     }
460
461     /*
462      * If caused by button press, event may ALSO cause focus to be
463      * passed to this client - prepare to disable focusAutoRaise.
464      */
465     if (pCD && event && (event->type == ButtonPress))
466       pCD->focusAutoRaiseDisablePending = True;
467
468     wmGD.passButtonsCheck = False;
469     return (True);
470
471 } /* END OF FUNCTION F_Lower */
472
473
474 \f
475 /*************************************<->*************************************
476  *
477  *  Do_Lower (pCD, pStackEntry)
478  *
479  *
480  *  Description:
481  *  -----------
482  *  This is the window manager function handler for lowering the client window
483  *  so that it does not obscure any other window above the stack entry
484  *  window.
485  *
486  *
487  *  Inputs:
488  *  ------
489  *  pCD = pointer to the client data of the window (or icon) to be lowered.
490  * 
491  *  pStackEntry = pointer to client list entry for window that is to be 
492  *      below the lowered window (if NULL, window is lowered to the bottom
493  *      of the  stack).
494  *
495  *************************************<->***********************************/
496
497 void Do_Lower (ClientData *pCD, ClientListEntry *pStackEntry, int flags)
498 {
499     Boolean restackTransients;
500     ClientData *pcdLeader;
501     WmWorkspaceData *pWS = ACTIVE_WS;
502 #ifdef WSM
503     Boolean bLeaderRestacked;
504 #endif /* WSM */
505
506 #ifdef PANELIST
507     if (pCD->pECD)
508     {
509         /*
510          * Window has been reparented into the front panel. 
511          * Don't follow through on window stacking change.
512          */
513         return;
514     }
515     else 
516 #else /* PANELIST */
517 #endif /* PANELIST */
518 #ifdef WSM
519     if (ClientInWorkspace(pWS, pCD)  && 
520         (!pStackEntry || ClientInWorkspace (pWS, pStackEntry->pCD)))
521     {
522         /* 
523          * Both clients are in the current workspace. Set
524          * client indices so that the access macros work.
525          */
526         SetClientWsIndex (pCD);
527         if (pStackEntry)
528         {
529             SetClientWsIndex (pStackEntry->pCD);
530         }
531     }
532     else
533     {
534         /*
535          * One or both of the clients are not in the current workspace
536          * Do nothing.
537          */
538         return;
539     }
540 #endif /* WSM */
541
542     pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
543
544     if ((pcdLeader->clientState == MINIMIZED_STATE) && !P_ICON_BOX(pcdLeader))
545     {
546         /*
547          * If a dirtyStackEntry exists, return it to its original place 
548          * in the stack (for all stacking types)
549          */
550         if (dirtyStackEntry)
551         {
552             if (dirtyStackEntry->transientChildren ||
553                 dirtyStackEntry->transientLeader)
554                 RestackTransients (dirtyStackEntry);
555             dirtyStackEntry = NULL;
556             dirtyLeader = NULL;
557         }
558
559         /*
560          * Only restack the icon if it is not currently lowered.
561          */
562
563         if (pStackEntry)
564         {
565             if (pStackEntry->prevSibling != &pcdLeader->iconEntry)
566             {
567                 StackWindow (pWS, &pcdLeader->iconEntry, True /*above*/,
568                     pStackEntry);
569                 MoveEntryInList (pWS, &pcdLeader->iconEntry, True /*above*/,
570                     pStackEntry);
571             }
572         }
573         else
574         {
575             if (ACTIVE_PSD->lastClient != &pcdLeader->iconEntry)
576             {
577                 StackWindow (pWS, &pcdLeader->iconEntry, 
578                              False /*on bottom*/, (ClientListEntry *) NULL);
579                 MoveEntryInList (pWS, &pcdLeader->iconEntry, 
580                              False /*on bottom*/, (ClientListEntry *) NULL);
581             }
582         }
583     }
584     else /* NORMAL_STATE, MAXIMIZED_STATE, adoption */
585     {
586 #ifdef WSM
587         /*
588          * Handle restacking of primary/secondary windows
589          * within the transient window tree.
590          */
591         bLeaderRestacked = False;
592         if ((pcdLeader->transientChildren) &&
593             (!pcdLeader->secondariesOnTop) &&
594             (!wmGD.bSuspendSecondaryRestack))
595         {
596             if (pCD == pcdLeader)
597             {
598                 /*
599                  * Lower requested on the leader itself, insure it's
600                  * at the bottom.
601                  */
602                 bLeaderRestacked = BumpPrimaryToBottom (pcdLeader);
603             }
604             else if (pCD->transientChildren)
605             {
606                 /*
607                  * Lower requested on the leader of a subtree. Insure
608                  * that this subtree leader is at the bottom of the
609                  * subtree.
610                  */
611                 bLeaderRestacked = BumpPrimaryToBottom (pCD);
612             }
613             else if (pCD->transientLeader)
614             {
615                 ClientData *pcdLdr;
616
617                 /*
618                  * Lower requested on a transient. Insure all the
619                  * subtree leaders up to the top are at the bottom
620                  * of their respective transient subtrees.
621                  */
622                 for (pcdLdr = pCD->transientLeader;
623                         pcdLdr; 
624                                 pcdLdr = pcdLdr->transientLeader)
625                 {
626                     bLeaderRestacked |= BumpPrimaryToBottom (pcdLdr);
627                 }
628             }
629
630         }
631 #endif /* WSM */
632         /*
633          * If this is a transient window then put it below its
634          * sibling transient windows.
635          */
636
637         restackTransients = False;
638         if (pCD->transientLeader)
639         {
640
641             /*
642              * If freeFamily stacking, then put dirty transient window
643              * (if any) back in place before force lowering current window
644              * to the bottom of the global window stack.  Then return.
645              */
646
647             if (flags & STACK_FREE_FAMILY)
648             {
649                 /* Restore dirty transient if not current window. */
650                 if ((dirtyStackEntry) &&
651                     (dirtyStackEntry != pCD))
652                 {
653                     RestackTransients (dirtyStackEntry);
654                 }
655
656                 dirtyStackEntry = pCD;
657                 dirtyLeader = pcdLeader;
658
659                 ForceLowerWindow (pCD);
660                 return;
661             }
662
663             /*
664              * Reach here only if NOT doing a f.lower freeFamily (see
665              * return; statement above).  Put current transient below
666              * its sibling transient windows.
667              */
668             restackTransients = PutTransientBelowSiblings (pCD);
669         }
670
671         /*
672          * If doing a regular f.lower and you have a dirty window, then
673          * clean up dirty transient window.
674          */
675
676         if (dirtyStackEntry)
677         {
678             /* 
679              * If lowering a window in the same family as the dirty
680              * transient window, then just restack before lowering.
681              * Else, restore the dirty transient in place before
682              * lowering the current window.  Clear dirtyStack.
683              */
684             if (dirtyLeader == pcdLeader)
685             {
686                 restackTransients = True;
687             }
688             else
689             {
690                 RestackTransients (dirtyStackEntry);
691             }
692
693             dirtyStackEntry = NULL;
694         }
695
696         /*
697          * Only restack the window or transient window tree if it is
698          * not currently lowered and the window is not a system
699          * modal window.
700          */
701
702         if (pStackEntry)
703         {
704             if ((pStackEntry->prevSibling != &pcdLeader->clientEntry) &&
705                 !(wmGD.systemModalActive &&
706                   (pcdLeader == wmGD.systemModalClient)))
707             {
708                 StackWindow (pWS, &pcdLeader->clientEntry, True /*above*/,
709                     pStackEntry);
710                 MoveEntryInList (pWS, &pcdLeader->clientEntry, True /*above*/,
711                     pStackEntry);
712             }
713 #ifdef WSM
714             else if ((restackTransients) || (bLeaderRestacked))
715 #else /* WSM */
716             else if (restackTransients)
717 #endif /* WSM */
718             {
719                 RestackTransients (pCD);
720             }
721         }
722         else
723         {
724             if ((pWS->pSD->lastClient != &pcdLeader->clientEntry) &&
725                 !(wmGD.systemModalActive &&
726                   (pcdLeader == wmGD.systemModalClient)) &&
727                 !(flags & STACK_WITHIN_FAMILY))
728             {
729                 StackWindow (pWS, &pcdLeader->clientEntry, False /*on bottom*/,
730                     (ClientListEntry *) NULL);
731                 MoveEntryInList (pWS, &pcdLeader->clientEntry,
732                     False /*on bottom*/, (ClientListEntry *) NULL);
733             }
734 #ifdef WSM
735             else if ((restackTransients) || (bLeaderRestacked))
736 #else /* WSM */
737             else if (restackTransients)
738 #endif /* WSM */
739             {
740                 RestackTransients (pCD);
741             }
742         }
743     }
744
745 } /* END OF FUNCTION Do_Lower */
746
747
748 \f
749 /*************************************<->*************************************
750  *
751  *  F_CircleDown (args, pCD, event)
752  *
753  *
754  *  Description:
755  *  -----------
756  *  This is the window manager function handler for moving the client window
757  *  on top of stack to the bottom.
758  *
759  *
760  *  Inputs:
761  *  ------
762  *  args = function arguments (specified in .mwmrc file)
763  *
764  *  pCD = pointer to the client data for the client window to which the
765  *        function is to be applied
766  *
767  *  event = X event that invoked the function (key, button, or menu/NULL)
768  *
769  *
770  *  Outputs:
771  *  -------
772  *  RETURN = if True then further button binding/function processing can
773  *           be done for the event that caused this function to be called.
774  *
775  *************************************<->***********************************/
776
777 Boolean F_Circle_Down (String args, ClientData *pCD, XEvent *event)
778 {
779     unsigned long types;
780     unsigned long windowType;
781     ClientListEntry *pNextEntry;
782     ClientData *pcdNext;
783
784
785     /*
786      * Go down through the client list looking for a window of an
787      * appropriate type that is obscuring lower windows.
788      */
789
790     types = (unsigned long)args;
791     pNextEntry = ACTIVE_PSD->clientList;
792     while (pNextEntry)
793     {
794         /*
795          * Only check out the window if it is onscreen.
796          */
797
798         pcdNext = pNextEntry->pCD;
799         if (((pNextEntry->type == NORMAL_STATE) &&
800              (pcdNext->clientState != MINIMIZED_STATE)) ||
801             ((pNextEntry->type == MINIMIZED_STATE) &&
802              (pcdNext->clientState == MINIMIZED_STATE)))
803         {
804             if (pcdNext->clientState == MINIMIZED_STATE)
805             {
806                 windowType = F_GROUP_ICON;
807             }
808             else
809             {
810                 windowType = F_GROUP_WINDOW;
811                 if (pcdNext->transientLeader || pcdNext->transientChildren)
812                 {
813                     windowType |= F_GROUP_TRANSIENT;
814                 }
815             }
816             if (types & windowType)
817             {
818                 if (CheckIfClientObscuringAny (pcdNext))
819                 {
820                     /*
821                      * This window (or window tree) is obscuring another window
822                      * on the screen.  Lower the window.
823                      */
824
825 #ifdef WSM
826                     wmGD.bSuspendSecondaryRestack = True;
827 #endif /* WSM */
828                     F_Lower (NULL, pcdNext, (XEvent *) NULL);
829 #ifdef WSM
830                     wmGD.bSuspendSecondaryRestack = False;
831 #endif /* WSM */
832                     break;
833                 }
834             }
835         }
836         pNextEntry = pNextEntry->nextSibling;
837     }
838
839     return (True);
840
841 } /* END OF FUNCTION F_Circle_Down */
842
843
844 \f
845 /*************************************<->*************************************
846  *
847  *  F_Circle_Up (args, pCD, event)
848  *
849  *
850  *  Description:
851  *  -----------
852  *  This is the window manager function handler for moving the client window
853  *  on the bottom of the stack to the top.
854  *
855  *
856  *  Inputs:
857  *  ------
858  *  args = function arguments (specified in .mwmrc file)
859  *
860  *  pCD = pointer to the client data for the client window to which the
861  *        function is to be applied
862  *
863  *  event = X event that invoked the function (key, button, or menu/NULL)
864  *
865  *
866  *  Outputs:
867  *  -------
868  *  RETURN = if True then further button binding/function processing can
869  *           be done for the event that caused this function to be called.
870  *
871  *************************************<->***********************************/
872
873 Boolean F_Circle_Up (String args, ClientData *pCD, XEvent *event)
874 {
875     unsigned long types;
876     unsigned long windowType;
877     ClientListEntry *pNextEntry;
878     ClientData *pcdNext;
879
880
881     /*
882      * Go up through the client list looking for a window of an
883      * appropriate type that is obscured by higher windows.
884      */
885
886     types = (unsigned long)args;
887     pNextEntry = ACTIVE_PSD->lastClient;
888     while (pNextEntry)
889     {
890         /*
891          * Only check out the window if it is onscreen.
892          */
893
894         pcdNext = pNextEntry->pCD;
895         if (((pNextEntry->type == NORMAL_STATE) &&
896              (pcdNext->clientState != MINIMIZED_STATE)) ||
897             ((pNextEntry->type == MINIMIZED_STATE) &&
898              (pcdNext->clientState == MINIMIZED_STATE)))
899         {
900             if (pcdNext->clientState == MINIMIZED_STATE)
901             {
902                 windowType = F_GROUP_ICON;
903             }
904             else
905             {
906                 windowType = F_GROUP_WINDOW;
907                 if (pcdNext->transientLeader || pcdNext->transientChildren)
908                 {
909                     windowType |= F_GROUP_TRANSIENT;
910                 }
911             }
912             if (types & windowType)
913             {
914                 if (CheckIfClientObscuredByAny (pcdNext))
915                 {
916                     /*
917                      * This window (or window tree) is obscured by another
918                      * window on the screen.  Raise the window.
919                      */
920
921 #ifdef WSM
922                     wmGD.bSuspendSecondaryRestack = True;
923 #endif /* WSM */
924                     F_Raise (NULL, pcdNext, (XEvent *) NULL);
925 #ifdef WSM
926                     wmGD.bSuspendSecondaryRestack = False;
927 #endif /* WSM */
928                     break;
929                 }
930             }
931         }
932         pNextEntry = pNextEntry->prevSibling;
933     }
934
935     return (True);
936
937
938 } /* END OF FUNCTION F_Circle_Up */
939
940
941 \f
942 /*************************************<->*************************************
943  *
944  *  F_Focus_Color (args, pCD, event)
945  *
946  *
947  *  Description:
948  *  -----------
949  *  This is the window manager function handler for setting the colormap
950  *  focus to a client window or reinstalling the default colormap.
951  *
952  *************************************<->***********************************/
953
954 Boolean F_Focus_Color (String args, ClientData *pCD, XEvent *event)
955 {
956
957     if (wmGD.colormapFocusPolicy == CMAP_FOCUS_EXPLICIT)
958     {
959         if (pCD)
960         {
961             /*
962              * The window selected for the colormap focus is a top-level client
963              * window.  If there are subwindow colormaps then determine if the
964              * selection was in one of the subwindows.
965              */
966
967             if (pCD->clientState == MINIMIZED_STATE)
968             {
969                 /* !!! colormap for client supplied icon window !!! */
970                 pCD = NULL;
971             }
972         }
973
974         SetColormapFocus (ACTIVE_PSD, pCD);
975     }
976
977     return (True);
978
979 } /* END OF FUNCTION F_Focus_Color */
980
981
982 \f
983 /*************************************<->*************************************
984  *
985  *  F_Exec (args, pCD, event)
986  *
987  *
988  *  Description:
989  *  -----------
990  *  This is the window manager function handler for executing a command
991  *  (with /bin/sh).
992  *
993  *************************************<->***********************************/
994
995 Boolean F_Exec (String args, ClientData *pCD, XEvent *event)
996 {
997     int   status;
998     int   pid;
999     int   w;
1000 #ifndef WSM
1001     void (*intStat) ();
1002     void (*quitStat) ();
1003 #endif /* WSM */
1004     char *shell;
1005     char *shellname;
1006
1007
1008     /* make sure the f.exec command runs on the right display. */
1009     if (wmGD.pActiveSD->displayString)
1010       {
1011         putenv(wmGD.pActiveSD->displayString);
1012       }
1013     
1014 #ifdef PANELIST
1015     if (wmGD.dtSD)
1016     {
1017         /*
1018          * Start the busy indicator, waiting for a pushbutton window
1019          * for the given duration
1020          */
1021        WmFrontPanelSetBusy (True);
1022     }
1023 #endif /* PANELIST */
1024
1025     /*
1026      * Fork a process to exec a shell to run the specified command:
1027      */
1028
1029 #ifdef PORT_NOVFORK
1030     if ((pid = fork ()) == 0)
1031 #else
1032     if ((pid = vfork ()) == 0)
1033 #endif
1034     {
1035
1036 #ifndef NO_SETPGRP
1037 #if defined(SVR4) || defined(__OSF1__) || defined(__osf__) || defined(linux)
1038         setsid();
1039 #else
1040 #ifdef SYSV
1041         setpgrp();
1042 #else
1043         int tpid;
1044
1045         tpid = getpid();
1046         setpgrp(tpid, tpid);
1047 #endif /* SYSV */
1048 #endif /* SVR4 */
1049 #endif /* NO_SETPGRP */
1050 #ifdef WSM 
1051         /*
1052          * Clean up window manager resources.
1053          * The X file descriptor should be automatically closed.
1054          */
1055
1056         /*
1057          * Fix up signal handling.
1058          */
1059         RestoreDefaultSignalHandlers ();
1060
1061         /*
1062          * Fix up the child application's environment NOT to
1063          * inherit the XFILESEARCHPATH, XBMLANGPATH, NLSPATH, etc.
1064          * used by dtwm.
1065          */
1066          _DtEnvControl(DT_ENV_RESTORE_PRE_DT);
1067
1068          CLOSE_FILES_ON_EXEC();
1069 #endif /* WSM */
1070
1071         /*
1072          * Exec the command using $MWMSHELL if set or 
1073          * $SHELL if set and $MWMSHELL not set or sh.
1074          */
1075
1076         if (((shell = getenv ("MWMSHELL")) != NULL) ||
1077             ((shell = getenv ("SHELL")) != NULL))
1078
1079         {
1080             shellname = strrchr (shell, '/');
1081             if (shellname == NULL)
1082             {
1083                 /*
1084                 If the shell pathname obtained from SHELL or MWMSHELL does not
1085                 have a "/" in the path and if the user expects this shell to be
1086                 obtained using the PATH variable rather than the current
1087                 directory, then we must call execlp and not execl
1088                 */
1089                 shellname = shell;
1090                 execlp (shell, shellname, "-c", args, 0);
1091             }
1092             else
1093             {
1094                 shellname++;
1095                 execl (shell, shellname, "-c", args, 0);
1096             }
1097         }
1098
1099         /*
1100          * There is no SHELL environment variable or the first execl failed.
1101          * Try /bin/sh .
1102          */
1103 #ifdef SVR4
1104         execl ("/usr/bin/sh", "sh", "-c", args, 0);
1105 #else
1106         execl ("/bin/sh", "sh", "-c", args, 0);
1107 #endif
1108
1109
1110         /*
1111          * Error - command could not be exec'ed.
1112          */
1113
1114         _exit (127);
1115     }
1116
1117     else if (pid == -1)
1118       return(True);
1119
1120     /*
1121      * Have the window manager wait for the shell to complete.
1122      */
1123
1124 #ifndef WSM
1125     intStat = (void (*)())signal (SIGINT, SIG_IGN);
1126     quitStat = (void (*)())signal (SIGQUIT, SIG_IGN);
1127 #endif /* WSM */
1128
1129 #ifdef WSM
1130     /*
1131      * Don't need to wait because WSM sets SIGCLD handler
1132      */
1133 #else /* WSM */
1134     while ((w = wait (&status)) != pid && (w != -1));
1135
1136     if (w == -1)
1137     {
1138         status = -1;
1139     }
1140 #endif /* WSM */
1141
1142 #ifndef WSM
1143     signal (SIGINT, intStat);
1144     signal (SIGQUIT, quitStat);
1145 #endif /* WSM */
1146
1147     /*
1148      * Restore original DISPLAY environment variable value
1149      * so a restart will start on the same screen
1150      */
1151
1152     if(wmGD.pActiveSD->displayString &&
1153        wmGD.displayString)
1154     {
1155         putenv(wmGD.displayString);
1156     }
1157
1158
1159     return (True);
1160
1161
1162 } /* END OF FUNCTION F_Exec */
1163
1164
1165 \f
1166 /*************************************<->*************************************
1167  *
1168  *  F_Quit_Mwm (args, pCD, event)
1169  *
1170  *
1171  *  Description:
1172  *  -----------
1173  *  This is the window manager function handler for terminating the window
1174  *  manager.
1175  *
1176  *************************************<->***********************************/
1177
1178 Boolean F_Quit_Mwm (String args, ClientData *pCD, XEvent *event)
1179 {
1180     if (wmGD.showFeedback & WM_SHOW_FB_QUIT)
1181     {
1182         ConfirmAction (ACTIVE_PSD, QUIT_MWM_ACTION);
1183     }
1184     else
1185     {
1186         Do_Quit_Mwm(False);
1187     }
1188     
1189     return (False);
1190
1191 } /* END OF FUNCTION F_Quit_Mwm */
1192
1193
1194 \f
1195 /*************************************<->*************************************
1196  *
1197  *  Do_Quit_Mwm (diedOnRestart)
1198  *
1199  *
1200  *  Description:
1201  *  -----------
1202  *  Callback to do the f.quit_mwm function.
1203  *
1204  *************************************<->***********************************/
1205
1206 void Do_Quit_Mwm (Boolean diedOnRestart)
1207 {
1208     int scr;
1209     ClientListEntry *pNextEntry;
1210
1211
1212     /*
1213      * Close the X connection to get all the X resources cleaned up.
1214      * !!! maybe windows should be reparented / rebordered  before closing? !!!
1215      * !!! clean up the _MOTIF_WM_INFO property on the root window !!!
1216      */
1217
1218
1219     if (DISPLAY)
1220     {
1221         XSetInputFocus(DISPLAY, PointerRoot, RevertToPointerRoot, CurrentTime);
1222         for (scr = 0; scr < wmGD.numScreens; scr++)
1223         {
1224             if (wmGD.Screens[scr].managed)
1225             {
1226 #ifdef WSM
1227                 SaveResources(&wmGD.Screens[scr]);
1228 #endif /* WSM */
1229                 pNextEntry = wmGD.Screens[scr].lastClient;
1230                 while (pNextEntry)
1231                 {
1232                     if (pNextEntry->type == NORMAL_STATE)
1233                     {
1234                         if (!(pNextEntry->pCD->clientFlags & 
1235                               CLIENT_WM_CLIENTS))
1236                         {
1237                             ReBorderClient (pNextEntry->pCD, diedOnRestart);
1238                         }
1239                     }
1240                     pNextEntry = pNextEntry->prevSibling;
1241                 }
1242 #if defined(PANELIST)
1243                 UnParentControls (&wmGD.Screens[scr], False);
1244 #endif /* PANELIST */
1245
1246 #ifndef WSM
1247                 XDeleteProperty(DISPLAY, wmGD.Screens[scr].rootWindow,
1248                                 wmGD.xa_MWM_INFO);
1249 #endif /* WSM */
1250             }
1251         }
1252 #ifdef WSM
1253         /* shut down the messaging connection */
1254         dtCloseIPC();
1255 #endif /* WSM */
1256         ResignFromSM();
1257         XSync (DISPLAY, False);
1258         XCloseDisplay (DISPLAY);
1259     }
1260     
1261     if(diedOnRestart)
1262     {
1263         exit (WM_ERROR_EXIT_VALUE);
1264     }
1265     else
1266     {
1267         exit (0);
1268     }
1269
1270 } /* END OF FUNCTION Do_Quit_Mwm */
1271
1272 \f
1273 /*************************************<->*************************************
1274  *
1275  *  ReBorderClient (pCD, reMapClient)
1276  *
1277  *
1278  *  Description:
1279  *  -----------
1280  *  Restores X border for client window and reparents the
1281  *  window back to the root.
1282  *
1283  *
1284  *  Inputs:
1285  *  -------
1286  *  pCD = pointer to the client data for the window to be re-bordered.
1287  *
1288  *************************************<->***********************************/
1289
1290 void ReBorderClient (ClientData *pCD, Boolean reMapClient)
1291 {
1292     int x, y;
1293     int xoff, yoff;
1294     XWindowChanges windowChanges;
1295
1296     while (pCD)
1297     {
1298         if (pCD->iconWindow && (pCD->clientFlags & ICON_REPARENTED) &&
1299             (!(reMapClient)))
1300         {
1301             XUnmapWindow (DISPLAY, pCD->iconWindow);
1302 #ifdef WSM
1303             XReparentWindow (DISPLAY, pCD->iconWindow, 
1304                 ROOT_FOR_CLIENT(pCD), pCD->pWsList->iconX, 
1305                 pCD->pWsList->iconY);
1306 #else /* WSM */
1307             XReparentWindow (DISPLAY, pCD->iconWindow, 
1308                 ROOT_FOR_CLIENT(pCD), pCD->iconX, pCD->iconY);
1309 #endif /* WSM */
1310         }
1311
1312         if (!(reMapClient))
1313         {
1314             if (pCD->maxConfig)
1315             {
1316                 x = pCD->maxX;
1317                 y = pCD->maxY;
1318             }
1319             else
1320             {
1321                 if(wmGD.positionIsFrame)
1322                 {
1323                     CalculateGravityOffset (pCD, &xoff, &yoff);
1324                     x = pCD->clientX - xoff;
1325                     y = pCD->clientY - yoff;
1326                 }
1327                 else
1328                 {
1329                     x = pCD->clientX;
1330                     y = pCD->clientY;
1331                 }
1332             }
1333             XUnmapWindow(DISPLAY, pCD->clientFrameWin);
1334             XReparentWindow (DISPLAY, pCD->client, 
1335                              ROOT_FOR_CLIENT(pCD), x, y);
1336         }
1337         else
1338         {
1339             XMapWindow(wmGD.display, pCD->client);
1340         }
1341
1342         if (pCD->transientChildren)
1343         {
1344             ReBorderClient (pCD->transientChildren, reMapClient);
1345         }
1346
1347         if (!(reMapClient))
1348         {
1349             /*
1350              * restore X border
1351              */
1352             windowChanges.x = x;
1353             windowChanges.y = y;
1354             windowChanges.border_width = pCD->xBorderWidth;
1355             XConfigureWindow (DISPLAY, pCD->client, 
1356                               CWBorderWidth | CWX | CWY, &windowChanges);
1357         }
1358
1359         if (pCD->transientLeader)
1360         {
1361             pCD = pCD->transientSiblings;
1362         }
1363         else
1364         {
1365             pCD = NULL;
1366         }
1367     }
1368
1369 } /* END OF FUNCTION ReBorderClient */
1370
1371
1372 \f
1373 /*************************************<->*************************************
1374  *
1375  *  F_Focus_Key (args, pCD, event)
1376  *
1377  *
1378  *  Description:
1379  *  -----------
1380  *  This is the window manager function handler for setting the keyboard
1381  *  focus to a particular client window.
1382  *
1383  *
1384  *  Inputs:
1385  *  ------
1386  *  args = (immediate value) focus flags
1387  *
1388  *  pCD = pointer to the client data
1389  *
1390  *  event = X event that invoked the function (key, button, or menu/NULL)
1391  *
1392  *************************************<->***********************************/
1393
1394 Boolean F_Focus_Key (String args, ClientData *pCD, XEvent *event)
1395 {
1396     long focusFlags = (long)args;
1397
1398
1399     if (pCD && (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
1400     {
1401         Do_Focus_Key (pCD, GetFunctionTimestamp ((XButtonEvent *)event),
1402             (focusFlags | ALWAYS_SET_FOCUS));
1403     }
1404
1405     return (True);
1406
1407 } /* END OF FUNCTION F_Focus_Key */
1408
1409 \f
1410 /*************************************<->*************************************
1411  *
1412  *  FindSomeReasonableClient
1413  *
1414  *  Description:
1415  *  -----------
1416  *  Find a client, any client to set the focus to, return client or NULL.
1417  *  This code is ripped off from AutoResetKeyFocus(). 
1418  *  
1419  *************************************<->***********************************/
1420
1421 static Window FindSomeReasonableClient(void)
1422 {
1423    ClientData *pcdNoFocus=NULL;
1424
1425     ClientListEntry *pNextEntry;
1426     ClientData *pCD;
1427     ClientData *pcdLastFocus = (ClientData *) NULL;
1428     ClientData *pcdFocus;
1429     Window focusWindow = (Window) NULL;
1430
1431     /*
1432      * Scan through the list of clients to find a window to get the focus.
1433      */
1434
1435     pNextEntry = ACTIVE_PSD->clientList;
1436
1437     while (pNextEntry)
1438     {
1439         pCD = pNextEntry->pCD;
1440         if (!wmGD.systemModalActive ||
1441             (wmGD.systemModalClient == pCD))
1442         {
1443             if ((pNextEntry->type != MINIMIZED_STATE) &&
1444                 (pCD->clientState != MINIMIZED_STATE) &&
1445 #ifdef WSM
1446                 (ClientInWorkspace (ACTIVE_WS, pCD)) &&
1447 #endif /* WSM */
1448                 (pCD != pcdNoFocus))
1449             {
1450                 if (pCD->transientChildren)
1451                 {
1452                     pcdFocus = FindLastTransientTreeFocus (pCD, pcdNoFocus);
1453                 }
1454                 else
1455                 {
1456                     pcdFocus = pCD;
1457                 }
1458                 if (pcdFocus &&
1459                     ((pcdLastFocus == NULL) ||
1460                      (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
1461                 {
1462                     pcdLastFocus = pcdFocus;
1463                 }
1464             }
1465         }
1466         pNextEntry = pNextEntry->nextSibling;
1467     }
1468
1469     /*
1470      * Set the focus window if one is found
1471      */
1472
1473 #ifdef WSM
1474     if (pcdLastFocus && 
1475         ClientInWorkspace (ACTIVE_WS, pcdLastFocus))
1476 #else /* WSM */
1477     if (pcdLastFocus)
1478 #endif /* WSM */
1479       focusWindow = pcdLastFocus->client;
1480
1481     /*
1482      * If a client window could not be found, then just put focus
1483      * on any icon.
1484      */
1485
1486     if (focusWindow == (Window) NULL)
1487     {
1488         pNextEntry = ACTIVE_PSD->clientList;
1489
1490         while (pNextEntry)
1491         {
1492             pCD = pNextEntry->pCD;
1493
1494 #ifdef WSM
1495           if (ClientInWorkspace (ACTIVE_WS, pCD))
1496           {
1497 #endif /* WSM */
1498             if ((pNextEntry->type == MINIMIZED_STATE) ||
1499                 (pCD->clientState == MINIMIZED_STATE))
1500             {
1501                 focusWindow = ICON_FRAME_WIN(pCD);
1502                 break;
1503             }
1504 #ifdef WSM
1505           }
1506 #endif /* WSM */
1507             pNextEntry = pNextEntry->nextSibling;
1508         }
1509     }
1510
1511     return (focusWindow);
1512
1513 } /* END OF FUNCTION FindSomeReasonableClient */
1514
1515
1516
1517 \f
1518 /*************************************<->*************************************
1519  *
1520  *  Do_Focus_Key (pCD, focusTime, flags)
1521  *
1522  *
1523  *  Description:
1524  *  -----------
1525  *  This function is used to set the focus to a window.  The focus indication
1526  *  is not changed until the FocusIn event is received.
1527  *
1528  *
1529  *  Inputs:
1530  *  ------
1531  *  pCD = pointer to the client data
1532  *
1533  *  focusTime = focus change time
1534  *
1535  *  flags = wm focus change flags
1536  *
1537  *************************************<->***********************************/
1538
1539 void Do_Focus_Key (ClientData *pCD, Time focusTime, long flags)
1540 {
1541     ClientData *pcdFocus;
1542     Window focusWindow;
1543
1544
1545     /* Clear the replay flag */
1546     wmGD.replayEnterEvent = False;
1547
1548     pcdFocus = pCD;
1549 #ifdef WSM
1550     /* 
1551      * Make sure the client is in the current workspace
1552      */
1553     if ((pCD) &&
1554         (ClientInWorkspace (ACTIVE_WS, pCD)))
1555 #else /* WSM */
1556     if (pCD)
1557 #endif /* WSM */
1558     {
1559         if (pCD->clientState == MINIMIZED_STATE)
1560         {
1561             focusWindow = ICON_FRAME_WIN(pCD);
1562         }
1563         else if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1564         {
1565             /*
1566              * Set the keyboard focus to the indicated client window.
1567              * If the window has an application modal subordinate then
1568              * set the input focus to that window if the focus isn't
1569              * already owned by a subordinate.
1570              */
1571
1572             if (IS_APP_MODALIZED(pCD))
1573             {
1574                 ClientData *pcdFocusLeader,*currFocusLeader;
1575
1576                 /*
1577                  * Handle case where a modal window exists when Mwm starts up.
1578                  * wmGD.keyboardFocus is NULL, give focus to the modal dialog.
1579                  */
1580
1581                 if (wmGD.keyboardFocus)
1582                 {
1583                     currFocusLeader = wmGD.keyboardFocus->transientLeader;
1584                 }
1585                 else
1586                 {
1587                     currFocusLeader = (ClientData *) NULL;
1588                 }
1589
1590                 /*
1591                  * Find focus leader for pCD
1592                  */
1593
1594                 pcdFocusLeader = pCD;
1595                 while (pcdFocusLeader->transientLeader &&
1596                        (pcdFocusLeader != currFocusLeader))
1597                 {
1598                     pcdFocusLeader = pcdFocusLeader->transientLeader;
1599                 }
1600
1601                 if (pcdFocusLeader == currFocusLeader)
1602                 {
1603                     pcdFocus = wmGD.keyboardFocus;
1604                     flags = 0;
1605                 }
1606                 else
1607                 {
1608                     pcdFocus = FindTransientFocus (pcdFocusLeader);
1609                 }
1610             }
1611
1612             /*
1613              * !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  
1614              * We must look at why FindTransientFocus is
1615              * returning a NULL pcd.  The old code simply set
1616              *  focusWindow = pcdFocus->client;
1617              * !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  !!!  
1618              *
1619              * 11/26/96 rswiston - In tracking down CDExc22816, we
1620              * discovered that pCD could get tricked into thinking
1621              * it had modal transients when in fact all its transients
1622              * had been withdrawn (fixed in WithdrawTransientChildren()).
1623              * As a result, FindTransientFocus() returns wmGD.keyboardFocus;
1624              * if nobody has the focus, FindTransientFocus() returns NULL.
1625              */
1626             if (pcdFocus)
1627             {
1628                 focusWindow = pcdFocus->client;
1629             }
1630             else
1631             {
1632                 focusWindow = (wmGD.keyboardFocus) ?
1633                     wmGD.keyboardFocus->client : ACTIVE_PSD->wmWorkspaceWin;
1634             }
1635         }
1636         else
1637         {
1638             /*
1639              * If the focus policy is "pointer" don't set the focus to a
1640              * window if it has an application modal subordinate.
1641              */
1642
1643             if (IS_APP_MODALIZED(pCD))
1644             {
1645                 pcdFocus = NULL;
1646                 focusWindow = ACTIVE_PSD->wmWorkspaceWin;
1647
1648                 /* Replay this later when the modal window is removed. */
1649                 wmGD.replayEnterEvent = True;
1650             }
1651             else
1652             {
1653                 focusWindow = pcdFocus->client;
1654             }
1655         }
1656     }
1657     else
1658     {
1659         /*
1660          * Set up the default (non client specific) keyboard input focus.
1661          */
1662
1663         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1664         {
1665             focusWindow = PointerRoot;
1666         }
1667         else
1668         {
1669             /*
1670              * The WORKSPACE_IF_NULL flag is used to prevent client
1671              * windows from flashing when deiconifying a client.
1672              */
1673
1674             if (WORKSPACE_IF_NULL & flags)
1675             {
1676                 focusWindow = ACTIVE_PSD->wmWorkspaceWin;
1677             }
1678             else
1679             {
1680                 /* find some reasonable client so that focus is not lost */
1681
1682                 focusWindow = FindSomeReasonableClient();
1683                 if (focusWindow == (Window)NULL)
1684                 {
1685                     focusWindow = ACTIVE_PSD->wmWorkspaceWin;
1686                 }
1687             }
1688         }
1689     }
1690
1691     if ((pcdFocus != wmGD.keyboardFocus) || (flags & ALWAYS_SET_FOCUS))
1692     {
1693         if (pcdFocus)
1694         {
1695             /*
1696              * Set the focus and/or send a take focus client message.  This
1697              * is not done if a client area button press was done to set
1698              * set the focus and the window is a globally active input
1699              * style window (See ICCCM).
1700              */
1701
1702             if ( (flags & CLIENT_AREA_FOCUS)                           &&
1703                  (pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS)    &&
1704                 ! pcdFocus->inputFocusModel                            &&
1705                  (pcdFocus == pCD)                                     &&
1706                  (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
1707                 !(pcdFocus->clientState == MINIMIZED_STATE)
1708                )
1709             {
1710               /*
1711                * We get here if:
1712                * 1. User clicked in the client area   AND
1713                * 2. Input model is Globally Active    AND
1714                * 3. Keyboard focus policy is explicit
1715                */
1716
1717               /* this window has WM_TAKE_FOCUS set and InputField false. */
1718               /* just send a message.                                    */
1719               SendClientMsg (pcdFocus->client, 
1720                              (long) wmGD.xa_WM_PROTOCOLS,
1721                              (long) wmGD.xa_WM_TAKE_FOCUS, 
1722                              focusTime, NULL, 0);
1723             }
1724             else
1725             {
1726                 if ((pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS) &&
1727                     !(pcdFocus->clientState == MINIMIZED_STATE))
1728                 {
1729                   /*
1730                    * Locally Active Input Model - Send a take focus message to the client.
1731                    */
1732
1733                   SendClientMsg (pcdFocus->client, 
1734                                  (long) wmGD.xa_WM_PROTOCOLS,
1735                                  (long) wmGD.xa_WM_TAKE_FOCUS, 
1736                                  focusTime, NULL, 0);
1737                 }
1738
1739                 /*
1740                  * Don't set the input focus if the window has input_field set
1741                  * to False or has expressed an interest in WM_TAKE_FOCUS
1742                  * (ie. 'No Input', 'Globally Active', or 'Locally Active'),
1743                  * and the user click in the client area.  If the user clicks
1744                  * on the titlebar or traverses to this window via f.next_key,
1745                  * set the focus so that the user can access the window menu
1746                  * and accelerators.
1747                  */
1748
1749                 if ( wmGD.enforceKeyFocus       ||  /* res - default == True. */
1750                      (flags & ALWAYS_SET_FOCUS) ||
1751                     !(flags & CLIENT_AREA_FOCUS)||  /* clicked on frame? */
1752                      pcdFocus->inputFocusModel  ||  /* Pass.|Glob. Active */
1753                      (pcdFocus->clientState == MINIMIZED_STATE)
1754                    )
1755                 {
1756                   if ( !(flags & CLIENT_AREA_FOCUS) &&
1757                        !pcdFocus->inputFocusModel &&
1758                        !(pcdFocus->clientState == MINIMIZED_STATE))
1759                   {
1760                    /* the window doesn't want the focus - set it to the frame */
1761                    /* user clicked on the frame but we don't want the focus */
1762                    /* set it to the client's frame */
1763                    XSetInputFocus (DISPLAY, pcdFocus->clientBaseWin,
1764                                 RevertToPointerRoot, focusTime);
1765                   }
1766                   else if ( !(flags & CLIENT_AREA_FOCUS)                   &&
1767                        !(pcdFocus->protocolFlags & PROTOCOL_WM_TAKE_FOCUS) &&
1768                         pcdFocus->inputFocusModel
1769                      )
1770                   {
1771                     XSetInputFocus (DISPLAY, focusWindow,
1772                                     RevertToPointerRoot, focusTime);
1773                   }
1774                   else
1775                   {
1776                     XSetInputFocus (DISPLAY, focusWindow,
1777                                       RevertToParent, focusTime);
1778                   }
1779                 }
1780                 else
1781                 {
1782                   /*
1783                    * We've decided that the window shouldn't get the focus,
1784                    * so don't change the focus.
1785                    */
1786                   pcdFocus = wmGD.nextKeyboardFocus;
1787                 }
1788             }
1789         }
1790         else
1791         {
1792             XSetInputFocus (DISPLAY, focusWindow, RevertToPointerRoot,
1793                                         focusTime);
1794         }
1795
1796         wmGD.nextKeyboardFocus = pcdFocus;
1797     }
1798
1799
1800 } /* END OF FUNCTION Do_Focus_Key */
1801
1802
1803 #ifdef WSM
1804 \f
1805 /***********************<->*************************************
1806  *
1807  *  F_Goto_Workspace (args, pCD, event)
1808  *
1809  *  Description:
1810  *  -----------
1811  *  This is the window manager function handler for switching
1812  *  to another workspace by name.
1813  *
1814  *  Inputs:
1815  *  ------
1816  *  args = action function and arguments
1817  *
1818  *  pCD = pointer to the ClientData
1819  *
1820  *  event = X event that invoked the function (key, button, or menu/NULL)
1821  *
1822  *  Outputs:
1823  *  -------
1824  *  Always False
1825  *
1826  *  Comments:
1827  *  -------
1828  ******************************<->***********************************/
1829 Boolean
1830 F_Goto_Workspace (String args, ClientData *pCD, XEvent *event)
1831 {
1832     WmScreenData *pSD = ACTIVE_PSD;
1833     int iwsx;
1834     XmString xms;
1835
1836     /* 
1837      * Compare argument against both resource name 
1838      * and workspace title, take the first match.
1839      */
1840     xms = XmStringCreate (args, XmFONTLIST_DEFAULT_TAG);
1841     for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
1842     {
1843         if (!strcmp(pSD->pWS[iwsx].name, args) ||
1844             XmStringCompare (xms, pSD->pWS[iwsx].title))
1845         {
1846             break;
1847         }
1848     }
1849
1850     XmStringFree (xms);
1851
1852     /* check bounds */
1853     if (iwsx >= pSD->numWorkspaces)
1854     {
1855         Warning (((char *)GETMESSAGE(26, 4, 
1856                 "Invalid workspace name specified for f.goto_workspace")));
1857     }
1858     else
1859     {
1860         ChangeToWorkspace (&pSD->pWS[iwsx]);
1861
1862     }
1863
1864     return (False);
1865 }  /* END OF FUNCTION F_Goto_Workspace */
1866
1867 #endif /* WSM */
1868
1869 #ifdef WSM
1870 \f
1871 /******************************<->*************************************
1872  *
1873  *  Boolean F_Help (String args, ClientData *pCD, XEvent *event)
1874  *
1875  *  Description:
1876  *  -----------
1877  *  Invoke help on the workspace manager
1878  *
1879  *  Inputs:
1880  *  ------
1881  *  args - incoming values
1882  *  pCD  - associated client data structure
1883  *  event - what triggered this call
1884  * 
1885  *  Outputs:
1886  *  -------
1887  *  Return - True if the call occurs; false otherwise.
1888  *
1889  *  Comments:
1890  *  --------
1891  *
1892  ******************************<->***********************************/
1893 Boolean
1894 F_Help (String args, ClientData *pCD, XEvent *event)
1895 {
1896 #ifdef PANELIST
1897     Boolean rval;
1898
1899     rval = WmDtHelp(args);
1900     return (rval);
1901 #endif /* PANELIST */    
1902     
1903
1904 }  /* END OF FUNCTION F_Help */
1905
1906 \f
1907 /******************************<->*************************************
1908  *
1909  *  Boolean F_Help_Mode (String args, ClientData *pCD, XEvent *event)
1910  *
1911  *  Description:
1912  *  -----------
1913  *  Invoke item help on the frontpanel
1914  *
1915  *  Inputs:
1916  *  ------
1917  *  args - NULL
1918  *  pCD  - associated client data structure ??
1919  *  event - what triggered this call
1920  * 
1921  *  Outputs:
1922  *  -------
1923  *  Return - True if the call occurs; false otherwise.
1924  *
1925  *  Comments:
1926  *  --------
1927  *
1928  ******************************<->***********************************/
1929 Boolean
1930 F_Help_Mode (String args, ClientData *pCD, XEvent *event)
1931 {
1932 #ifdef PANELIST
1933     /*
1934      * Help mode event processing interferes
1935      * with slide up windows. Don't continue
1936      * if windows are sliding.
1937      */
1938     if (wmGD.iSlideUpsInProgress == 0)
1939     {
1940         (void) WmDtHelpMode();
1941     }
1942     return (False);
1943 #endif /* PANELIST */    
1944
1945 }  /* END OF FUNCTION F_Help_Mode */
1946
1947 #endif /* WSM */
1948 \f
1949 /******************************<->*************************************
1950  *
1951  *  F_Next_Key (args, pCD, event)
1952  *
1953  *
1954  *  Description:
1955  *  -----------
1956  *  This is the window manager function handler for setting the keyboard
1957  *  input focus to the next window in the set of managed windows.
1958  *
1959  *
1960  *  Inputs:
1961  *  ------
1962  *  args = (immediate value) window type flags
1963  *
1964  *  pCD = pointer to the client data
1965  *
1966  *  event = X event that invoked the function (key, button, or menu/NULL)
1967  *
1968  *************************************<->***********************************/
1969
1970 Boolean F_Next_Key (String args, ClientData *pCD, XEvent *event)
1971 {
1972 #ifdef ROOT_ICON_MENU
1973     Boolean focused = False;
1974 #endif /*  ROOT_ICON_MENU */
1975     if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1976     {
1977 #ifdef ROOT_ICON_MENU
1978         focused = 
1979 #endif /*  ROOT_ICON_MENU */
1980         FocusNextWindow ((unsigned long)args,
1981                          GetFunctionTimestamp ((XButtonEvent *)event));
1982 #ifdef ROOT_ICON_MENU
1983         if (focused && wmGD.iconClick &&
1984             event && event->type == KeyPress &&
1985             wmGD.nextKeyboardFocus &&
1986             wmGD.nextKeyboardFocus->clientState == MINIMIZED_STATE &&
1987             !P_ICON_BOX(wmGD.nextKeyboardFocus))
1988         {
1989             /*
1990              * Post system menu from the icon
1991              */
1992             F_Post_SMenu (args, wmGD.nextKeyboardFocus, event);
1993             return (False);
1994         }
1995 #endif /*  ROOT_ICON_MENU */
1996     }
1997
1998     return (True);
1999
2000 } /* END OF FUNCTION F_Next_Key */
2001
2002
2003 \f
2004 /*************************************<->*************************************
2005  *
2006  *  F_Prev_Cmap (args, pCD, event)
2007  *
2008  *
2009  *  Description:
2010  *  -----------
2011  *  This is the window manager function handler installing the previous
2012  *  colormap in the list of client window colormaps.
2013  *
2014  *************************************<->***********************************/
2015
2016 Boolean F_Prev_Cmap (String args, ClientData *pCD, XEvent *event)
2017 {
2018     if (pCD == NULL)
2019     {
2020         pCD = ACTIVE_PSD->colormapFocus;
2021     }
2022
2023     if (pCD && (pCD->clientCmapCount > 0) &&
2024         ((pCD->clientState == NORMAL_STATE) ||
2025          (pCD->clientState == MAXIMIZED_STATE)))
2026     {
2027         if (--(pCD->clientCmapIndex) < 0)
2028         {
2029             pCD->clientCmapIndex = pCD->clientCmapCount - 1;
2030         }
2031         pCD->clientColormap = pCD->clientCmapList[pCD->clientCmapIndex];
2032         if (ACTIVE_PSD->colormapFocus == pCD)
2033         {
2034 #ifndef OLD_COLORMAP /* colormap */
2035             /*
2036              * We just re-ordered the colormaps list,
2037              * so we need to re-run the whole thing.
2038              */
2039             pCD->clientCmapFlagsInitialized = 0;
2040             ProcessColormapList (ACTIVE_PSD, pCD);
2041 #else /* OSF original */
2042             WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2043 #endif
2044         }
2045     }
2046
2047     return (True);
2048
2049 } /* END OF FUNCTION F_Prev_Cmap */
2050
2051
2052 \f
2053 /*************************************<->*************************************
2054  *
2055  *  F_Prev_Key (args, pCD, event)
2056  *
2057  *
2058  *  Description:
2059  *  -----------
2060  *  This is the window manager function handler for setting the keyboard
2061  *  input focus to the previous window in the set of managed windows.
2062  *
2063  *
2064  *  Inputs:
2065  *  ------
2066  *  args = (immediate value) window type flags
2067  *
2068  *  pCD = pointer to the client data
2069  *
2070  *  event = X event that invoked the function (key, button, or menu/NULL)
2071  *
2072  *************************************<->***********************************/
2073
2074 Boolean F_Prev_Key (String args, ClientData *pCD, XEvent *event)
2075 {
2076 #ifdef ROOT_ICON_MENU
2077     Boolean focused = False;
2078 #endif /*  ROOT_ICON_MENU */
2079     if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2080     {
2081 #ifdef ROOT_ICON_MENU
2082         focused = 
2083 #endif /*  ROOT_ICON_MENU */
2084         FocusPrevWindow ((unsigned long)args,
2085                             GetFunctionTimestamp ((XButtonEvent *)event));
2086 #ifdef ROOT_ICON_MENU
2087         if (focused && wmGD.iconClick &&
2088             event && event->type == KeyPress &&
2089             wmGD.nextKeyboardFocus &&
2090             wmGD.nextKeyboardFocus->clientState == MINIMIZED_STATE &&
2091             !P_ICON_BOX(wmGD.nextKeyboardFocus))
2092         {
2093             /*
2094              * Post system menu from the icon
2095              */
2096             F_Post_SMenu (args, wmGD.nextKeyboardFocus, event);
2097             return (False);
2098         }
2099 #endif /*  ROOT_ICON_MENU */
2100
2101     }
2102
2103     return (True);
2104
2105 } /* END OF FUNCTION F_Prev_Key */
2106
2107 #ifdef PANELIST
2108 \f
2109 /***********************<->*************************************
2110  *
2111  *  F_Post_FpMenu (args, pCD, event)
2112  *
2113  *
2114  *  Description:
2115  *  -----------
2116  *  This is the window manager function handler for posting
2117  *  the Front Panel window menu.
2118  *
2119  *  Inputs:
2120  *  ------
2121  *  args = arguments (none)
2122  *
2123  *  pCD = pointer to the FP ClientData
2124  *
2125  *  event = X button press that invoked the function
2126  *
2127  ******************************<->***********************************/
2128
2129 Boolean
2130 F_Post_FpMenu (String args, ClientData *pCD, XEvent *event)
2131 {
2132     static MenuSpec *fpMenuSpec = (MenuSpec *)NULL;
2133
2134     if (event->type != ButtonPress)
2135         return False;
2136
2137     if (!fpMenuSpec)
2138     {
2139         WmScreenData *pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;
2140         MenuSpec *oldSpec;
2141         Widget tmpWidget;
2142         char *newMenuName;
2143
2144         newMenuName = pCD ? pCD->systemMenu : "DtPanelMenu";
2145
2146         for (oldSpec = pSD->menuSpecs;
2147              oldSpec != (MenuSpec *)NULL;
2148              oldSpec = oldSpec->nextMenuSpec)
2149         {
2150             if (oldSpec->name && (strcmp(oldSpec->name, newMenuName) == 0))
2151                 break;
2152         }
2153         if (!oldSpec)
2154             return False;
2155
2156         fpMenuSpec = DuplicateMenuSpec(oldSpec);
2157
2158         /*
2159          * TEMPORARILY modify pSD so the new menu will be
2160          * created on DISPLAY1 instead of DISPLAY.
2161          */
2162         fpMenuSpec->nextMenuSpec = pSD->menuSpecs;
2163         pSD->menuSpecs = fpMenuSpec;
2164         tmpWidget = pSD->screenTopLevelW;
2165         pSD->screenTopLevelW = pSD->screenTopLevelW1;
2166
2167         (void)MAKE_MENU (pSD, pCD, newMenuName,
2168                          F_CONTEXT_NORMAL, F_CONTEXT_NORMAL,
2169                          (MenuItem *) NULL, FALSE);
2170
2171         /* Restore pSD */
2172         pSD->screenTopLevelW = tmpWidget;
2173         pSD->menuSpecs = fpMenuSpec->nextMenuSpec;
2174     }
2175
2176     PostMenu (fpMenuSpec, pCD, event->xbutton.x_root, event->xbutton.y_root,
2177               event->xbutton.button, F_CONTEXT_NORMAL, POST_AT_XY, event);
2178
2179     _XmGetMenuState(XtParent(fpMenuSpec->menuWidget))
2180         ->MS_LastManagedMenuTime = event->xbutton.time;
2181
2182     return False;
2183 }
2184
2185 \f
2186 /***********************<->*************************************
2187  *
2188  *  F_Push_Recall (args, pCD, event)
2189  *
2190  *
2191  *  Description:
2192  *  -----------
2193  *  This is the window manager function handler for invoking/topping
2194  *  push_recall clients.
2195  *
2196  *
2197  *  Inputs:
2198  *  ------
2199  *  args = arguments
2200  *
2201  *  pCD = pointer to the ClientData 
2202  *
2203  *  event = X event that invoked the function (key, button, or menu/NULL)
2204  *
2205  *
2206  *  Outputs:
2207  *  -------
2208  *  RETURN = if True then further button binding/function processing can
2209  *           be done for the event that caused this function to be called.
2210  *
2211  *  Comments:
2212  *  -------
2213  ******************************<->***********************************/
2214
2215 Boolean
2216 F_Push_Recall (String args, ClientData *pCD, XEvent *event)
2217 {
2218     WmPushRecallArg *pPRP;
2219     WmScreenData *pSD;
2220     WmFpPushRecallClientData *pPRCD;
2221
2222     pPRP = (WmPushRecallArg *) args;
2223     pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;
2224
2225     if (pPRP->ixReg  < pSD->numPushRecallClients)
2226     {
2227         /* get slot for this client */
2228         pPRCD = &(pSD->pPRCD[pPRP->ixReg]);
2229
2230         /*
2231          * If the client is already running, then top it in this workspace,
2232          * else invoke the function to start it.
2233          */
2234         if (pPRCD->pCD)
2235         {
2236             /* Client is managed already. */ 
2237             if (!(ClientInWorkspace (pSD->pActiveWS, pPRCD->pCD)))
2238             {
2239                 WorkspaceID *wsRemoveList;
2240                 int sizeRemoveList;
2241
2242                 /* 
2243                  * Move client to current workspace 
2244                  */
2245                 wsRemoveList = GetListOfOccupiedWorkspaces (pPRCD->pCD, 
2246                                         &sizeRemoveList);
2247                 RemoveClientFromWorkspaces (pPRCD->pCD, wsRemoveList,
2248                                         sizeRemoveList);
2249                 XtFree ((char *)wsRemoveList);
2250                 AddClientToWorkspaces (pPRCD->pCD, &(pSD->pActiveWS->id), 1);
2251                 SetClientWsIndex(pPRCD->pCD);
2252                 SetClientState(pPRCD->pCD, 
2253                     pPRCD->pCD->clientState & ~UNSEEN_STATE, CurrentTime);
2254             }
2255
2256             /* Make this client visible */
2257 #ifdef WSM
2258                     wmGD.bSuspendSecondaryRestack = True;
2259 #endif /* WSM */
2260             F_Normalize_And_Raise (NULL, pPRCD->pCD, event);
2261 #ifdef WSM
2262                     wmGD.bSuspendSecondaryRestack = False;
2263 #endif /* WSM */
2264         }
2265         else 
2266         {
2267             struct timeval tvNow;
2268             struct timezone tz;
2269             Boolean bWaiting = False;
2270
2271             if (pPRCD->tvTimeout.tv_sec != 0)
2272             {
2273                 gettimeofday (&tvNow, &tz);
2274
2275                 if ((pPRCD->tvTimeout.tv_sec > tvNow.tv_sec) ||
2276                     ((pPRCD->tvTimeout.tv_sec == tvNow.tv_sec) &&
2277                      (pPRCD->tvTimeout.tv_usec > tvNow.tv_usec)))
2278                 {
2279                     /* still waiting for client to start */
2280                     bWaiting = True;
2281                 }
2282             }
2283
2284             if (!bWaiting)
2285             {
2286                 long clientTimeout;
2287                 Arg al[5];
2288                 int ac;
2289                 WmPanelistObject  pPanelist;
2290
2291                 pPanelist = (WmPanelistObject) pSD->wPanelist;
2292
2293                 /* invoke the function to start the client */
2294                 pPRP->wmFunc ( pPRP->pArgs, pCD, event);
2295
2296                 if (pPanelist && panel.busy_light_data)
2297                 {
2298                     /* set timeout value */
2299                     ac = 0;
2300                     XtSetArg (al[ac], 
2301                         XmNclientTimeoutInterval, &clientTimeout);      ac++; 
2302                     XtGetValues (panel.busy_light_data->icon, (ArgList)al, ac);
2303                 }
2304
2305                 /*
2306                  * ClientTimeout is in milliseconds, timeval values
2307                  * are in seconds and microseconds.
2308                  */
2309                 gettimeofday (&(pPRCD->tvTimeout), &tz);
2310
2311                 pPRCD->tvTimeout.tv_sec += clientTimeout / 1000;
2312                 pPRCD->tvTimeout.tv_usec += 
2313                     (clientTimeout % 1000) * 1000;
2314
2315                 pPRCD->tvTimeout.tv_sec += pPRCD->tvTimeout.tv_usec / 1000000;
2316                 pPRCD->tvTimeout.tv_usec %= 1000000;
2317             }
2318         }
2319     }
2320
2321     return (True);
2322
2323 } /* END OF FUNCTION F_Push_Recall */
2324 #endif /* PANELIST */
2325
2326 \f
2327 /*************************************<->*************************************
2328  *
2329  *  F_Pass_Key (args, pCD, event)
2330  *
2331  *
2332  *  Description:
2333  *  -----------
2334  *  This is a function stub for the f.pass_key window manager function.
2335  *
2336  *
2337  *  Inputs:
2338  *  ------
2339  *  args = (immediate value) window type flags
2340  *
2341  *  pCD = pointer to the client data
2342  *
2343  *  event = X event that invoked the function (key, button, or menu/NULL)
2344  *
2345  *************************************<->***********************************/
2346
2347 Boolean F_Pass_Key (args, pCD, event)
2348     String args;
2349     ClientData *pCD;
2350     XEvent *event;
2351
2352 {
2353     if (wmGD.passKeysActive)
2354     {
2355         /*
2356          * Get out of pass keys mode.
2357          */
2358
2359         wmGD.passKeysActive = False;
2360         wmGD.passKeysKeySpec = NULL;
2361     }
2362     else
2363     {
2364         /*
2365          * Get into pass keys mode.
2366          */
2367
2368         wmGD.passKeysActive = True;
2369     }
2370
2371     return (False);
2372
2373 } /* END OF FUNCTION F_Pass_Key */
2374
2375
2376 \f
2377 /*************************************<->*************************************
2378  *
2379  *  F_Maximize (args, pCD, event)
2380  *
2381  *
2382  *  Description:
2383  *  -----------
2384  *  This is the window manager function handler for maximizing a client
2385  *  window.
2386  *
2387  *************************************<->***********************************/
2388
2389 Boolean F_Maximize (String args, ClientData *pCD, XEvent *event)
2390 {
2391     if (pCD && (pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
2392     {
2393         SetClientStateWithEventMask (pCD, MAXIMIZED_STATE,
2394             GetFunctionTimestamp ((XButtonEvent *)event),
2395                 GetEventInverseMask(event));
2396     }
2397
2398     return (False);
2399
2400 } /* END OF FUNCTION F_Maximize */
2401
2402
2403 \f
2404 /*************************************<->*************************************
2405  *
2406  *  F_Menu (args, pCD, event)
2407  *
2408  *
2409  *  Description:
2410  *  -----------
2411  *  This is the window manager function handler for posting a menu.
2412  *  This function can only be invoked by a key or button event.
2413  *   wmGD.menuUnpostKeySpec is assumed set appropriately; it will be set to
2414  *     NULL when the menu is unposted.
2415  *
2416  *************************************<->***********************************/
2417
2418 Boolean F_Menu (String args, ClientData *pCD, XEvent *event)
2419 {
2420     MenuSpec    *menuSpec;
2421     Context      menuContext;
2422     unsigned int button;
2423     int          x;
2424     int          y;
2425     long         flags = POST_AT_XY;
2426     WmScreenData *pSD;
2427
2428
2429     if (event && 
2430         ((event->type == ButtonPress) || (event->type == ButtonRelease)))
2431     {
2432         button = event->xbutton.button;
2433         x = event->xbutton.x_root;
2434         y = event->xbutton.y_root;
2435         if (event->type == ButtonRelease)
2436         {
2437             flags |= POST_TRAVERSAL_ON;
2438         }
2439 #ifdef WSM
2440         /*
2441          * Root menu, if posted with button press, then 
2442          * set up to handle root menu click to make the menu
2443          * sticky.
2444          */
2445         else if (wmGD.rootButtonClick && (event->type == ButtonPress))
2446         {
2447             if (wmGD.bReplayedButton)
2448             {
2449                 /* This button was replayed, it most likely dismissed
2450                    a previous sticky menu, don't post a menu here */
2451                 return (False);
2452             }
2453             wmGD.checkHotspot = True;
2454             wmGD.hotspotRectangle.x = x - wmGD.moveThreshold/2;
2455             wmGD.hotspotRectangle.y = y - wmGD.moveThreshold/2;
2456             wmGD.hotspotRectangle.width = wmGD.moveThreshold;
2457             wmGD.hotspotRectangle.height = wmGD.moveThreshold;
2458         }
2459 #endif /* WSM */
2460     }
2461     else if (event && 
2462         ((event->type == KeyPress) || (event->type == KeyRelease)))
2463     {
2464         button = NoButton;
2465         x = event->xkey.x_root;
2466         y = event->xkey.y_root;
2467     }
2468     else
2469     {
2470         /*
2471          * A button or key event must be used to post a menu using this 
2472          * function.
2473          */
2474
2475         return (False);
2476     }
2477
2478     if (pCD)
2479     {
2480         if (pCD->clientState == NORMAL_STATE)
2481         {
2482             menuContext = F_CONTEXT_NORMAL;
2483         }
2484         else if (pCD->clientState == MAXIMIZED_STATE)
2485         {
2486             menuContext = F_CONTEXT_MAXIMIZE;
2487         }
2488         else 
2489         {
2490             menuContext = F_CONTEXT_ICON;
2491         }
2492         if (P_ICON_BOX(pCD) &&
2493             event->xany.window == ICON_FRAME_WIN(pCD))
2494         {
2495             if (pCD->clientState == MINIMIZED_STATE)
2496             {
2497                 menuContext = F_SUBCONTEXT_IB_IICON;
2498             }
2499             else
2500             {
2501                 menuContext = F_SUBCONTEXT_IB_WICON;
2502             }
2503         }
2504     }
2505     else
2506     {
2507         menuContext = F_CONTEXT_ROOT;
2508     }
2509
2510
2511     /* We do not add this MenuSpec to wmGD.acceleratorMenuSpecs.
2512      * This should have been done in MakeWmFunctionResources().
2513      */
2514
2515     pSD = (pCD) ? PSD_FOR_CLIENT(pCD) : ACTIVE_PSD;
2516     if ((menuSpec = MAKE_MENU (pSD, pCD, args, menuContext, 
2517                               menuContext, (MenuItem *) NULL, FALSE)) != NULL)
2518     {
2519         PostMenu (menuSpec, pCD, x, y, button, menuContext, flags, event);
2520     }
2521
2522     return (False);
2523
2524 } /* END OF FUNCTION F_Menu */
2525
2526 \f
2527 /*************************************<->*************************************
2528  *
2529  *  F_Minimize (args, pCD, event)
2530  *
2531  *
2532  *  Description:
2533  *  -----------
2534  *  This is the window manager function handler for minimizing a client
2535  *  window.
2536  *
2537  *************************************<->***********************************/
2538
2539 Boolean F_Minimize (String args, ClientData *pCD, XEvent *event)
2540 {
2541     ClientData *pcdLeader;
2542
2543
2544     if (pCD)
2545     {
2546         /*
2547          * If the window is a transient then minimize the entire transient
2548          * tree including the transient leader.
2549          */
2550         
2551         pcdLeader = (pCD->transientLeader) ?
2552                                         FindTransientTreeLeader (pCD) : pCD;
2553         if (pcdLeader->clientFunctions & MWM_FUNC_MINIMIZE)
2554         {
2555             SetClientStateWithEventMask (pCD, MINIMIZED_STATE,
2556                 GetFunctionTimestamp ((XButtonEvent *)event),
2557                 GetEventInverseMask(event));
2558         }
2559     }
2560
2561     return (False);
2562
2563 } /* END OF FUNCTION F_Minimize */
2564
2565
2566 \f
2567 /*************************************<->*************************************
2568  *
2569  *  F_Move (args, pCD, event)
2570  *
2571  *
2572  *  Description:
2573  *  -----------
2574  *  This is the window manager function handler for moving a client window
2575  *  or icon.
2576  *
2577  *************************************<->***********************************/
2578
2579 Boolean F_Move (String args, ClientData *pCD, XEvent *event)
2580 {
2581     if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
2582     {
2583         StartClientMove (pCD, event);
2584         HandleClientFrameMove (pCD, event);
2585     }
2586
2587     return (False);
2588
2589 } /* END OF FUNCTION F_Move */
2590
2591
2592 \f
2593 /*************************************<->*************************************
2594  *
2595  *  F_Next_Cmap (args, pCD, event)
2596  *
2597  *
2598  *  Description:
2599  *  -----------
2600  *  This is the window manager function handler installing the next
2601  *  colormap in the list of client window colormaps.
2602  *
2603  *************************************<->***********************************/
2604
2605 Boolean F_Next_Cmap (String args, ClientData *pCD, XEvent *event)
2606 {
2607     if (pCD == NULL)
2608     {
2609         pCD = ACTIVE_PSD->colormapFocus;
2610     }
2611
2612     if (pCD && (pCD->clientCmapCount > 0) &&
2613         ((pCD->clientState == NORMAL_STATE) ||
2614          (pCD->clientState == MAXIMIZED_STATE)))
2615     {
2616         if (++(pCD->clientCmapIndex) >= pCD->clientCmapCount)
2617         {
2618             pCD->clientCmapIndex = 0;
2619         }
2620         pCD->clientColormap = pCD->clientCmapList[pCD->clientCmapIndex];
2621         if (ACTIVE_PSD->colormapFocus == pCD)
2622         {
2623 #ifndef OLD_COLORMAP /* colormap */
2624             /*
2625              * We just re-ordered the colormaps list,
2626              * so we need to re-run the whole thing.
2627              */
2628             pCD->clientCmapFlagsInitialized = 0;
2629             ProcessColormapList (ACTIVE_PSD, pCD);
2630 #else /* OSF original */
2631             WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2632 #endif
2633         }
2634     }
2635
2636     return (True);
2637
2638 } /* END OF FUNCTION F_Next_Cmap */
2639
2640
2641 \f
2642 /*************************************<->*************************************
2643  *
2644  *  F_Nop (args, pCD, event)
2645  *
2646  *
2647  *  Description:
2648  *  -----------
2649  *  This is the window manager function handler for doing nothing.
2650  *
2651  *************************************<->***********************************/
2652
2653 Boolean F_Nop (String args, ClientData *pCD, XEvent *event)
2654 {
2655
2656     return (True);
2657
2658 } /* END OF FUNCTION F_Nop */
2659
2660
2661 \f
2662 /*************************************<->*************************************
2663  *
2664  *  F_Normalize (args, pCD, event)
2665  *
2666  *
2667  *  Description:
2668  *  -----------
2669  *  This is the window manager function handler for putting a client window
2670  *  in the normal state.
2671  *
2672  *************************************<->***********************************/
2673
2674 Boolean F_Normalize (String args, ClientData *pCD, XEvent *event)
2675 {
2676
2677     if (pCD)
2678     {
2679         SetClientStateWithEventMask (pCD, NORMAL_STATE,
2680             GetFunctionTimestamp ((XButtonEvent *)event),
2681                 GetEventInverseMask(event));
2682     }
2683
2684     return (False);
2685
2686 } /* END OF FUNCTION F_Normalize */
2687
2688
2689 \f
2690 /*************************************<->*************************************
2691  *
2692  *  F_Normalize_And_Raise (args, pCD, event)
2693  *
2694  *
2695  *  Description:
2696  *  -----------
2697  *  This is the window manager function handler for putting a client window
2698  *  in the normal state and raising it from and icon.
2699  *
2700  *************************************<->***********************************/
2701
2702 Boolean F_Normalize_And_Raise (String args, ClientData *pCD, XEvent *event)
2703 {
2704 #ifdef PANELIST
2705     WmScreenData        *pSD;
2706     WmWorkspaceData     *pWS;
2707
2708     if (args)
2709     {
2710         if (pCD) 
2711             pSD = PSD_FOR_CLIENT (pCD);
2712         else
2713             pSD = ACTIVE_PSD;
2714
2715         pWS =  pSD->pActiveWS;
2716
2717         if (pSD->useIconBox && 
2718             wmGD.useFrontPanel && 
2719             pSD->iconBoxControl &&
2720             (!strcmp(args, WmNiconBox)))
2721         {
2722             /* 
2723              * There's an icon box in the front panel and this is a 
2724              * request to pop up the icon box.
2725              */
2726             IconBoxPopUp (pWS, True);
2727             return (False);
2728         }
2729     }
2730 #endif /* PANELIST */
2731     if (pCD)
2732     {
2733         if (pCD->clientState == MINIMIZED_STATE)
2734         {
2735             /* normalize window  */
2736             SetClientStateWithEventMask (pCD, NORMAL_STATE,
2737                           (Time)
2738                           (event
2739                            ? GetFunctionTimestamp ((XButtonEvent *)event)
2740                            : GetTimestamp ()),
2741                         GetEventInverseMask(event));
2742         }
2743         else
2744         {
2745             /* Make sure we are in NORMAL_STATE */
2746             SetClientStateWithEventMask (pCD, NORMAL_STATE,
2747                             GetFunctionTimestamp ((XButtonEvent *)event),
2748                                 GetEventInverseMask(event));
2749
2750             /* Raise the window and set the keyboard focus to the window */
2751 #ifdef WSM
2752             wmGD.bSuspendSecondaryRestack = True;
2753 #endif /* WSM */
2754             F_Raise (NULL, pCD, (XEvent *)NULL);
2755 #ifdef WSM
2756             wmGD.bSuspendSecondaryRestack = False;
2757 #endif /* WSM */
2758             if (wmGD.raiseKeyFocus)
2759             {
2760                 F_Focus_Key (NULL, pCD,
2761                              (event 
2762                               ? ((XEvent *)event)
2763                               : ((XEvent *)NULL)));
2764             }
2765         }
2766         wmGD.clickData.clickPending = False;
2767         wmGD.clickData.doubleClickPending = False;
2768     }
2769
2770     return (False);
2771
2772 } /* END OF FUNCTION F_Normalize_And_Raise */
2773
2774
2775 \f
2776 /*************************************<->*************************************
2777  *
2778  *  F_Restore (args, pCD, event)
2779  *
2780  *
2781  *  Description:
2782  *  -----------
2783  *  This is the window manager function handler for putting a client window
2784  *  in the normal state.
2785  *
2786  *************************************<->***********************************/
2787
2788 Boolean F_Restore (String args, ClientData *pCD, XEvent *event)
2789 {
2790     int newState;
2791
2792     if (pCD)
2793     {
2794         /*
2795          * If current state is MAXIMIZED state then just go to NORMAL state,
2796          * otherwise (you are in MINIMIZED state) return to previous state.
2797          */
2798
2799         if (pCD->clientState == MAXIMIZED_STATE)
2800         {
2801             SetClientStateWithEventMask (pCD, NORMAL_STATE,
2802                             GetFunctionTimestamp ((XButtonEvent *)event),
2803                                 GetEventInverseMask(event));
2804         }
2805         else
2806         {
2807             if (pCD->maxConfig)
2808             {
2809                 newState = MAXIMIZED_STATE;
2810             }
2811             else
2812             {
2813                 newState = NORMAL_STATE;
2814             }
2815
2816             SetClientStateWithEventMask (pCD, newState,
2817                             GetFunctionTimestamp ((XButtonEvent *)event),
2818                                 GetEventInverseMask(event));
2819         }
2820     }
2821
2822     return (False);
2823
2824 } /* END OF FUNCTION F_Restore */
2825
2826
2827 \f
2828 /*************************************<->*************************************
2829  *
2830  *  F_Restore_And_Raise (args, pCD, event)
2831  *
2832  *
2833  *  Description:
2834  *  -----------
2835  *  This is the window manager function handler for putting a client window
2836  *  in the normal state and raising it from and icon.
2837  *
2838  *************************************<->***********************************/
2839
2840 Boolean F_Restore_And_Raise (String args, ClientData *pCD, XEvent *event)
2841 {
2842     int newState;
2843     
2844     if (pCD)
2845     {
2846         if (pCD->clientState == MINIMIZED_STATE)
2847         {
2848             /* Restore window  */
2849             if (pCD->maxConfig)
2850             {
2851                 newState = MAXIMIZED_STATE;
2852             }
2853             else
2854             {
2855                 newState = NORMAL_STATE;
2856             }
2857
2858             SetClientStateWithEventMask (pCD, newState,
2859                           (Time)
2860                           (event
2861                            ? GetFunctionTimestamp ((XButtonEvent *)event)
2862                            : GetTimestamp ()),
2863                         GetEventInverseMask(event));
2864         }
2865         else
2866         {
2867             /* Make sure we restore the window first */
2868             F_Restore (NULL, pCD, event);
2869
2870             /* Raise the window and set the keyboard focus to the window */
2871 #ifdef WSM
2872             wmGD.bSuspendSecondaryRestack = True;
2873 #endif /* WSM */
2874             F_Raise (NULL, pCD, (XEvent *)NULL);
2875 #ifdef WSM
2876             wmGD.bSuspendSecondaryRestack = False;
2877 #endif /* WSM */
2878             if (wmGD.raiseKeyFocus)
2879             {
2880                 F_Focus_Key (NULL, pCD,
2881                              (event 
2882                               ? ((XEvent *)event)
2883                               : ((XEvent *)NULL)));
2884             }
2885         }
2886         wmGD.clickData.clickPending = False;
2887         wmGD.clickData.doubleClickPending = False;
2888     }
2889
2890     return (False);
2891
2892 } /* END OF FUNCTION F_Restore_And_Raise */
2893
2894
2895 \f
2896 /*************************************<->*************************************
2897  *
2898  *  F_Pack_Icons (args, pCD, event)
2899  *
2900  *
2901  *  Description:
2902  *  -----------
2903  *  This is the window manager function handler for packing icons in the
2904  *  icon box or on the desktop.
2905  *
2906  *************************************<->***********************************/
2907
2908 Boolean F_Pack_Icons (String args, ClientData *pCD, XEvent *event)
2909 {
2910     
2911     IconBoxData *pIBD;
2912
2913     if (ACTIVE_PSD->useIconBox)
2914     {
2915         pIBD = ACTIVE_WS->pIconBox;
2916         if (pCD)
2917         {
2918             while (pCD != pIBD->pCD_iconBox)
2919             {
2920                 if (pIBD->pNextIconBox)
2921                 {
2922                     pIBD = pIBD->pNextIconBox;
2923                 }
2924                 else
2925                 {
2926                     pIBD = NULL;
2927                     break;
2928                 }
2929             }
2930         }
2931         if (pIBD)
2932         {
2933             PackIconBox (pIBD, False, False, 0, 0);
2934         }
2935         else
2936         {
2937            PackRootIcons ();
2938         }
2939     }
2940     else
2941     {
2942         PackRootIcons ();
2943     }
2944
2945     return (True);
2946
2947
2948 } /* END OF FUNCTION F_Pack_Icons */
2949
2950 \f
2951 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2952 /*************************************<->*************************************
2953  *
2954  *  F_Post_RMenu (args, pCD, event)
2955  *
2956  *
2957  *  Description:
2958  *  -----------
2959  *  This is the window manager function handler for posting the
2960  *  root window menu.
2961  *  This function can only be invoked by a key event.
2962  *
2963  *************************************<->***********************************/
2964
2965 Boolean F_Post_RMenu (String args, ClientData *pCD, XEvent *event)
2966 {
2967     MenuSpec    *rootMenu;
2968     unsigned int button = NoButton;
2969     int          x, y;
2970     long         flags = POST_AT_XY;
2971     Window       rwin, cwin;
2972     int          winx, winy;
2973     unsigned int mask;
2974
2975
2976     if ((event->type == KeyPress) || (event->type == KeyRelease))
2977       {
2978
2979         /* Find the root menu spec */
2980         for (rootMenu = ACTIVE_PSD->menuSpecs;
2981              rootMenu != (MenuSpec *) NULL;
2982              rootMenu = rootMenu->nextMenuSpec)
2983           {
2984             if (strcmp(rootMenu->name, ACTIVE_PSD->rootMenu) == 0)
2985               break;
2986           }
2987     
2988         /* If we couldn't find the root menu, then do nothing. */
2989         if (rootMenu == (MenuSpec *) NULL)
2990           return (False);
2991
2992         else
2993           {
2994             XQueryPointer(DISPLAY, ACTIVE_ROOT,
2995                           &rwin, &cwin, &x, &y, &winx, &winy, &mask);
2996
2997             PostMenu (rootMenu, NULL, x, y, NoButton, F_CONTEXT_ROOT,
2998                       flags, event);
2999           }
3000       }
3001
3002     return (False);
3003
3004 } /* END OF FUNCTION F_Post_RMenu */
3005 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3006
3007 \f
3008 /*************************************<->*************************************
3009  *
3010  *  F_Post_SMenu (args, pCD, event)
3011  *
3012  *
3013  *  Description:
3014  *  -----------
3015  *  This is the window manager function handler for posting the system menu
3016  *  for the specified client.
3017  *  This function can only be invoked by a key or button event.
3018  *  wmGD.menuUnpostKeySpec is assumed set appropriately; it will be set to
3019  *    NULL when the menu is unposted.
3020  *
3021  *************************************<->***********************************/
3022
3023 Boolean F_Post_SMenu (String args, ClientData *pCD, XEvent *event)
3024 {
3025     Context menuContext;
3026
3027
3028     /*
3029      * An event must be used to post the system menu using this function.
3030      */
3031
3032     if (event && pCD && pCD->systemMenuSpec)
3033     {
3034         /*
3035          * Determine whether the keyboard is posting the menu and post
3036          * the menu at an appropriate place.
3037          */
3038
3039         if (pCD->clientState == NORMAL_STATE)
3040         {
3041             menuContext = F_CONTEXT_NORMAL;
3042         }
3043         else if (pCD->clientState == MAXIMIZED_STATE)
3044         {
3045             menuContext = F_CONTEXT_MAXIMIZE;
3046         }
3047         else 
3048         {
3049             menuContext = F_CONTEXT_ICON;
3050         }
3051         if (P_ICON_BOX(pCD) &&
3052             event->xany.window == ICON_FRAME_WIN(pCD))
3053         {
3054             if (pCD->clientState == MINIMIZED_STATE)
3055             {
3056                 menuContext = F_SUBCONTEXT_IB_IICON;
3057             }
3058             else
3059             {
3060                 menuContext = F_SUBCONTEXT_IB_WICON;
3061             }
3062         }
3063
3064         if ((event->type == KeyPress) || (event->type == KeyRelease))
3065         {
3066             /*
3067              * Set up for "sticky" menu processing if specified.
3068              */
3069
3070             if (pCD->clientState == MINIMIZED_STATE ||
3071                 menuContext == (F_SUBCONTEXT_IB_IICON | F_SUBCONTEXT_IB_WICON))
3072             {
3073                 if (wmGD.iconClick)
3074                 {
3075                     wmGD.checkHotspot = True;
3076                 }
3077             }
3078             else if (wmGD.systemButtonClick && (pCD->decor & MWM_DECOR_MENU))
3079             {
3080                 wmGD.checkHotspot = True;
3081             }
3082
3083             PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton, menuContext,
3084                       0, event);
3085         }
3086         else if (event->type == ButtonPress)
3087         {
3088 #ifdef WSM
3089             /*
3090              * Root menu, if posted with button press, then 
3091              * set up to handle root menu click to make the menu
3092              * sticky.
3093              */
3094             if (wmGD.rootButtonClick && (!wmGD.checkHotspot))
3095             {
3096                 wmGD.checkHotspot = True;
3097                 wmGD.hotspotRectangle.x = 
3098                             event->xbutton.x_root - wmGD.moveThreshold/2;
3099                 wmGD.hotspotRectangle.y = 
3100                             event->xbutton.y_root - wmGD.moveThreshold/2;
3101                 wmGD.hotspotRectangle.width = wmGD.moveThreshold;
3102                 wmGD.hotspotRectangle.height = wmGD.moveThreshold;
3103             }
3104 #endif /* WSM */
3105             PostMenu (pCD->systemMenuSpec, pCD, 
3106                 event->xbutton.x_root, event->xbutton.y_root,
3107                 event->xbutton.button, menuContext, POST_AT_XY, event);
3108         }
3109         else if (event->type == ButtonRelease)
3110         {
3111             PostMenu (pCD->systemMenuSpec, pCD, 
3112                 event->xbutton.x_root, event->xbutton.y_root,
3113                 event->xbutton.button, menuContext,
3114                 POST_AT_XY | POST_TRAVERSAL_ON, event);
3115         }
3116     }
3117
3118     return (False);
3119
3120 } /* END OF FUNCTION F_PostSMenu */
3121
3122
3123 \f
3124 /*************************************<->*************************************
3125  *
3126  *  F_Kill (args, pCD, event)
3127  *
3128  *
3129  *  Description:
3130  *  -----------
3131  *  This is the window manager function handler for terminating a client.
3132  *  Essentially the client connection is shut down.
3133  *
3134  *************************************<->***********************************/
3135
3136 Boolean F_Kill (String args, ClientData *pCD, XEvent *event)
3137 {
3138     if (pCD && (pCD->clientFunctions & MWM_FUNC_CLOSE))
3139     {
3140         Boolean do_delete_window =
3141                 pCD->protocolFlags & PROTOCOL_WM_DELETE_WINDOW;
3142         Boolean do_save_yourself =
3143                 pCD->protocolFlags & PROTOCOL_WM_SAVE_YOURSELF;
3144
3145 #ifdef PANELIST
3146         if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
3147         {
3148             Widget              wPanel;
3149             
3150             /*
3151              * Get the widget for the subpanel
3152              * (Should be only child of the shell!)
3153              */
3154             wPanel = WmPanelistWindowToSubpanel (DISPLAY1, pCD->client);
3155             if (wPanel)
3156             {
3157                 SlideSubpanelBackIn (pCD, wPanel);
3158             }
3159             return (False);
3160         }
3161         if (pCD->clientFlags & ICON_BOX)
3162         {
3163             /*
3164              * When the front panel is used with the icon box,
3165              * "Close" hides the icon box into the front panel.
3166              */
3167             if ((wmGD.useFrontPanel) &&
3168                 (pCD->pSD->iconBoxControl) &&
3169                 (IconBoxShowing(pCD->pSD->pActiveWS)))
3170             {
3171                 IconBoxPopUp (pCD->pSD->pActiveWS, False);
3172             }
3173         }
3174         else
3175 #endif /* PANELIST */
3176         if (!do_delete_window && !do_save_yourself)
3177         {
3178             XKillClient (DISPLAY, pCD->client);
3179         }
3180         else
3181         {
3182             if (do_delete_window)
3183             {
3184                 /*
3185                  * The client wants to be notified, not killed.
3186                  */
3187
3188                 SendClientMsg (pCD->client, (long) wmGD.xa_WM_PROTOCOLS,
3189                     (long) wmGD.xa_WM_DELETE_WINDOW, CurrentTime, NULL, 0);
3190             }
3191 #ifdef WSM
3192             /*
3193              * HP does not want to send a client message for both
3194              * delete_window AND save_yourself.  The current OSF
3195              * patch did just that.  This "else if" returns dtwm
3196              * to the behavior of dt 2.01
3197              */
3198             else if (do_save_yourself)
3199 #else /* WSM */
3200             if (do_save_yourself)
3201 #endif /* WSM */
3202             {
3203                 /*
3204                  * Send a WM_SAVE_YOURSELF message and wait for a change to
3205                  * the WM_COMMAND property.
3206                  * !!! button and key input should be kept from the window !!!
3207                  */
3208
3209                 if (AddWmTimer (TIMER_QUIT, 
3210                     (unsigned long) wmGD.quitTimeout, pCD))
3211                 {
3212                     SendClientMsg (pCD->client, (long) wmGD.xa_WM_PROTOCOLS,
3213                         (long) wmGD.xa_WM_SAVE_YOURSELF, CurrentTime, NULL, 0);
3214
3215                     pCD->clientFlags |= CLIENT_TERMINATING;
3216                 }
3217                 else
3218                 {
3219                     XKillClient (DISPLAY, pCD->client);
3220                 }
3221             }
3222         }
3223     }
3224
3225     return (False);
3226
3227 } /* END OF FUNCTION F_Kill */
3228
3229 #ifdef WSM
3230 \f
3231 /*************************************<->*************************************
3232  *
3233  *  F_Marquee_Selection (args, pCD, event)
3234  *
3235  *
3236  *  Description:
3237  *  -----------
3238  *  This is the window manager function handler for selecting 
3239  *  non-window manager objects on the root window.
3240  *
3241  *************************************<->***********************************/
3242
3243 Boolean F_Marquee_Selection (String args, ClientData *pCD, XEvent *event)
3244 {
3245     if (!pCD)
3246     {
3247         /*
3248          * This function only valid in root context
3249          */
3250         StartMarqueeSelect (ACTIVE_PSD, event);
3251         HandleMarqueeSelect (ACTIVE_PSD, event);
3252     }
3253
3254     return (False);
3255
3256 } /* END OF FUNCTION F_Marquee_Selection */
3257
3258 /*************************************<->*************************************
3259  *
3260  *  RefreshByClearing (win)
3261  *
3262  *
3263  *  Description:
3264  *  -----------
3265  *  Recursively refresh this window and its children by doing
3266  *  XClearAreas
3267  *
3268  *************************************<->***********************************/
3269 static void
3270 RefreshByClearing (Window win)
3271 {
3272     Status status;
3273     int i;
3274     Window root, parent;
3275     unsigned int nchildren;
3276     Window *winChildren;
3277
3278     /* clear this window */
3279     XClearArea(DISPLAY, win, 0, 0, 0, 0, True);
3280
3281     /* find any children and clear them, too */
3282     status = XQueryTree(DISPLAY, win, &root, &parent, &winChildren,
3283                     &nchildren);
3284     if (status != 0)
3285     {
3286         /* recurse for each child window */
3287         for (i=0; i<nchildren; ++i) 
3288         {
3289             RefreshByClearing(winChildren[i]);
3290         }
3291
3292         /* clean up */
3293         if (nchildren > 0) 
3294             XFree((char *)winChildren);
3295     }
3296 }
3297 #endif /* WSM */
3298
3299 \f
3300 /*************************************<->*************************************
3301  *
3302  *  F_Refresh (args, pCD, event)
3303  *
3304  *
3305  *  Description:
3306  *  -----------
3307  *  This is the window manager function handler for causing all windows
3308  *  in the workspace to be redrawn.
3309  *
3310  *************************************<->***********************************/
3311
3312 Boolean F_Refresh (String args, ClientData *pCD, XEvent *event)
3313 {
3314     Window win;
3315
3316 #ifdef WSM
3317     if (wmGD.refreshByClearing)
3318     {
3319         RefreshByClearing (ACTIVE_ROOT);
3320     }
3321     else
3322     {
3323 #endif /* WSM */
3324                          /* default background_pixmap is None */
3325     win = XCreateWindow (DISPLAY,
3326                          ACTIVE_ROOT, 0, 0,
3327                          (unsigned int) DisplayWidth (DISPLAY, 
3328                              ACTIVE_SCREEN),
3329                          (unsigned int) DisplayHeight (DISPLAY, 
3330                              ACTIVE_SCREEN),
3331                          0, 
3332                          0,
3333                          InputOutput,
3334                          CopyFromParent,
3335                          0, 
3336                          (XSetWindowAttributes *)NULL);   
3337
3338     XMapWindow (DISPLAY, win);
3339     XDestroyWindow (DISPLAY, win);
3340 #ifdef WSM 
3341     }
3342 #endif /* WSM */
3343     XFlush (DISPLAY);
3344
3345     return (True);
3346
3347 } /* END OF FUNCTION F_Refresh */
3348
3349
3350 \f
3351 /*************************************<->*************************************
3352  *
3353  *  F_Resize (args, pCD, event)
3354  *
3355  *
3356  *  Description:
3357  *  -----------
3358  *  This is the window manager function handler for resizing a client window.
3359  *
3360  *************************************<->***********************************/
3361
3362 Boolean F_Resize (String args, ClientData *pCD, XEvent *event)
3363 {
3364     if (pCD && (pCD->clientFunctions & MWM_FUNC_RESIZE) &&
3365         ((pCD->clientState == NORMAL_STATE) ||
3366                                         (pCD->clientState == MAXIMIZED_STATE)))
3367     {
3368         StartClientResize (pCD, event);
3369         HandleClientFrameResize (pCD, event);
3370     }
3371
3372     return (False);
3373
3374 } /* END OF FUNCTION F_Resize */
3375
3376
3377 \f
3378 /*************************************<->*************************************
3379  *
3380  *  F_Restart (args, pCD, event)
3381  *
3382  *
3383  *  Description:
3384  *  -----------
3385  *  This is the window manager function handler for restarting the window
3386  *  manager.
3387  *
3388  *************************************<->***********************************/
3389
3390 Boolean F_Restart (String args, ClientData *pCD, XEvent *event)
3391 {
3392 #ifdef WSM
3393     if (args && *args && !strcmp (args, DTWM_REQP_NO_CONFIRM))
3394     {
3395         RestartWm (MWM_INFO_STARTUP_CUSTOM);
3396     }
3397     else
3398 #endif /* WSM */
3399     if (wmGD.showFeedback & WM_SHOW_FB_RESTART)
3400     {
3401         ConfirmAction (ACTIVE_PSD, RESTART_ACTION);
3402     }
3403     else
3404     {
3405         RestartWm (MWM_INFO_STARTUP_CUSTOM);
3406     }
3407     return (False);
3408
3409 } /* END OF FUNCTION F_Restart */
3410
3411
3412 \f
3413 /*************************************<->*************************************
3414  *
3415  *  Do_Restart (dummy)
3416  *
3417  *
3418  *  Description:
3419  *  -----------
3420  *  Callback function for restarting the window manager.
3421  *
3422  *************************************<->***********************************/
3423
3424 void Do_Restart (Boolean dummy)
3425 {
3426     RestartWm (MWM_INFO_STARTUP_CUSTOM);
3427
3428 } /* END OF FUNCTION Do_Restart */
3429
3430
3431 \f
3432 /*************************************<->*************************************
3433  *
3434  *  RestartWm (startupFlags)
3435  *
3436  *
3437  *  Description:
3438  *  -----------
3439  *  Actually restarts the window manager.
3440  *
3441  *
3442  *  Inputs:
3443  *  ------
3444  *  startupFlags = flags to be put into the Wm_INFO property for restart.
3445  *
3446  *************************************<->***********************************/
3447
3448 void RestartWm (long startupFlags)
3449 {
3450     ClientListEntry *pNextEntry;
3451     int scr;
3452
3453
3454     for (scr=0; scr<wmGD.numScreens; scr++)
3455     {
3456         if(wmGD.Screens[scr].managed)
3457         {
3458             
3459             /*
3460              * Set up the _MOTIF_WM_INFO property on the root window 
3461              * to indicate a restart.
3462              */
3463             
3464             SetMwmInfo (wmGD.Screens[scr].rootWindow, startupFlags, 0);
3465 #ifdef WSM
3466             SaveResources(&wmGD.Screens[scr]);
3467 #endif /* WSM */
3468             /*
3469              * Unmap client windows and reparent them to the root window.
3470              */
3471             
3472             pNextEntry = wmGD.Screens[scr].lastClient;
3473             while (pNextEntry)
3474             {
3475                 if (pNextEntry->type == NORMAL_STATE)
3476                 {
3477                     if (pNextEntry->pCD->clientFlags & CLIENT_WM_CLIENTS)
3478                     {
3479                         if (pNextEntry->pCD->clientState != MINIMIZED_STATE)
3480                         {
3481                             XUnmapWindow (DISPLAY, 
3482                                           pNextEntry->pCD->clientFrameWin);
3483                         }
3484                     }
3485                     else
3486                     {
3487                         DeFrameClient (pNextEntry->pCD);
3488                     }
3489                 }
3490                 pNextEntry = pNextEntry->prevSibling;
3491             }
3492 #if defined(PANELIST)
3493             UnParentControls (&wmGD.Screens[scr], True);
3494 #endif /* PANELIST */
3495         }
3496         
3497     }
3498     
3499 #ifdef WSM
3500     /* shut down the messaging connection */
3501     dtCloseIPC();
3502 #endif /* WSM */
3503     ResignFromSM();
3504
3505     /*
3506      * This fixes restart problem when going from explicit focus to
3507      * pointer focus.  Window under pointer was not getting focus indication
3508      * until pointer was moved to new window, or out of and into the
3509      * window.
3510      */
3511
3512     XSetInputFocus (DISPLAY, PointerRoot, RevertToPointerRoot, CurrentTime);
3513     XSync (DISPLAY, False);
3514
3515 #ifdef WSM
3516     CLOSE_FILES_ON_EXEC();
3517     _DtEnvControl(DT_ENV_RESTORE_PRE_DT); 
3518 #endif /* WSM */
3519     /*
3520      * Restart the window manager with the initial arguments plus
3521      * the restart settings.
3522      */
3523
3524     execvp (*(wmGD.argv), wmGD.argv);
3525
3526 #ifdef WSM
3527     Warning (((char *)GETMESSAGE(26, 1, 
3528 "The window manager restart failed. The window manager program could not \
3529 be found or could not be executed.")));
3530 #else /* WSM */
3531     Warning ("Cannot restart the window manager");
3532 #endif /* WSM */
3533     Do_Quit_Mwm (True);
3534
3535
3536
3537 } /* END OF FUNCTION RestartWm */
3538
3539 \f
3540 /*************************************<->*************************************
3541  *
3542  *  DeFrameClient (pCD)
3543  *
3544  *
3545  *  Description:
3546  *  -----------
3547  *  Unmaps a client window (and client icon window) and reparents the
3548  *  window back to the root.
3549  *
3550  *
3551  *  Inputs:
3552  *  -------
3553  *  pCD = pointer to the client data for the window to be de-framed.
3554  *
3555  *************************************<->***********************************/
3556
3557 void DeFrameClient (ClientData *pCD)
3558 {
3559     int x, y;
3560     int xoff, yoff;
3561     XWindowChanges windowChanges;
3562
3563     while (pCD)
3564     {
3565         if (pCD->clientState != MINIMIZED_STATE)
3566         {
3567             XUnmapWindow (DISPLAY, pCD->clientFrameWin);
3568         }
3569
3570         if (pCD->iconWindow && (pCD->clientFlags & ICON_REPARENTED))
3571         {
3572             XUnmapWindow (DISPLAY, pCD->iconWindow);
3573             XRemoveFromSaveSet (DISPLAY, pCD->iconWindow);
3574 #ifdef WSM
3575             XReparentWindow (DISPLAY, pCD->iconWindow, 
3576                 ROOT_FOR_CLIENT(pCD), pCD->pWsList->iconX, 
3577                 pCD->pWsList->iconY);
3578 #else /* WSM */
3579             XReparentWindow (DISPLAY, pCD->iconWindow, 
3580                 ROOT_FOR_CLIENT(pCD), pCD->iconX, pCD->iconY);
3581 #endif /* WSM */
3582         }
3583
3584         if (pCD->maxConfig)
3585         {
3586             x = pCD->maxX;
3587             y = pCD->maxY;
3588         }
3589         else
3590         {
3591             if(wmGD.positionIsFrame)
3592             {
3593                 CalculateGravityOffset (pCD, &xoff, &yoff);
3594                 x = pCD->clientX - xoff;
3595                 y = pCD->clientY - yoff;
3596             }
3597             else
3598             {
3599                 x = pCD->clientX;
3600                 y = pCD->clientY;
3601             }
3602         }
3603
3604 #ifndef UNMAP_ON_RESTART
3605         if (pCD->clientState == MINIMIZED_STATE)
3606         {
3607             XUnmapWindow (DISPLAY, pCD->client);
3608         }
3609 #else
3610         XUnmapWindow (DISPLAY, pCD->client);
3611 #endif
3612         XRemoveFromSaveSet (DISPLAY, pCD->client);
3613         XReparentWindow (DISPLAY, pCD->client, 
3614             ROOT_FOR_CLIENT(pCD), x, y);
3615
3616         if (pCD->transientChildren)
3617         {
3618             DeFrameClient (pCD->transientChildren);
3619         }
3620
3621         /*
3622          * restore X border
3623          */
3624         windowChanges.x = x;
3625         windowChanges.y = y;
3626         windowChanges.border_width = pCD->xBorderWidth;
3627         XConfigureWindow (DISPLAY, pCD->client, CWBorderWidth | CWX | CWY,
3628                           &windowChanges);
3629
3630         if (pCD->transientLeader)
3631         {
3632             pCD = pCD->transientSiblings;
3633         }
3634         else
3635         {
3636             pCD = NULL;
3637         }
3638     }
3639
3640 } /* END OF FUNCTION DeFrameClient */
3641
3642 #if defined(PANELIST)
3643 \f
3644 /******************************<->*************************************
3645  *
3646  *  F_Toggle_Front_Panel (args, pCD, event)
3647  *
3648  *
3649  *  Description:
3650  *  -----------
3651  *  This is the window manager function handler for toggling the
3652  *  front panel off and on.
3653  ******************************<->***********************************/
3654
3655 Boolean
3656 F_Toggle_Front_Panel (String args, ClientData *pCD, XEvent *event)
3657 {
3658
3659     WmPanelistObject  pPanelist;
3660
3661     if (pCD)
3662     {
3663         pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
3664     }
3665     else
3666     {
3667         pPanelist = (WmPanelistObject) ACTIVE_PSD->wPanelist;
3668     }
3669
3670     pCD = NULL;
3671     if (pPanelist)
3672     {
3673         (void) XFindContext (DISPLAY, XtWindow(O_Shell(pPanelist)),
3674                             wmGD.windowContextType, (caddr_t *)&pCD);
3675     }
3676
3677
3678     if (pCD)
3679     {
3680         if (pCD->clientState & MINIMIZED_STATE)
3681         {
3682             SetClientState (pCD, NORMAL_STATE, 
3683                     GetFunctionTimestamp ((XButtonEvent *)event));
3684         }
3685         else
3686         {
3687             SetClientState (pCD, MINIMIZED_STATE, 
3688                     GetFunctionTimestamp ((XButtonEvent *)event));
3689         }
3690     }
3691
3692     return(True);
3693 } /* END OF FUNCTION F_Toggle_Front_Panel */
3694
3695 \f
3696 /******************************<->*************************************
3697  *
3698  *  Boolean F_Version (String args, ClientData *pCD, XEvent *event)
3699  *
3700  *  Description:
3701  *  -----------
3702  *  Invoke the help on version dialogue.
3703  *
3704  *  Inputs:
3705  *  ------
3706  *  args - incoming values
3707  *  pCD  - associated client data structure
3708  *  event - what triggered this call
3709  * 
3710  *  Outputs:
3711  *  -------
3712  *  Return - True if the call occurs; false otherwise.
3713  *
3714  *  Comments:
3715  *  --------
3716  *
3717  ******************************<->***********************************/
3718 Boolean
3719 F_Version (String args, ClientData *pCD, XEvent *event)
3720 {
3721
3722     WmPanelistObject  pPanelist;
3723
3724     if (pCD)
3725     {
3726         pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
3727     }
3728     else
3729     {
3730         pPanelist = (WmPanelistObject) ACTIVE_PSD->wPanelist;
3731     }
3732
3733     if (pPanelist)
3734     {
3735         WmDtHelpOnVersion (O_Shell (pPanelist));
3736     }
3737
3738     return (True);
3739
3740 }  /* END OF FUNCTION F_Version */
3741 #endif /* PANELIST */
3742
3743 \f
3744 /******************************<->*************************************
3745  *
3746  *  F_Send_Msg (args, pCD, event)
3747  *
3748  *
3749  *  Description:
3750  *  -----------
3751  *  This is the window manager function handler for sending a client
3752  *  message event to a client window.
3753  *
3754  *
3755  *  Inputs:
3756  *  ------
3757  *  args = (immediate value) message id
3758  *
3759  *  pCD = pointer to the client data
3760  *
3761  *  event = X event that invoked the function (key, button, or menu/NULL)
3762  *
3763  *
3764  ******************************<->***********************************/
3765
3766 Boolean F_Send_Msg (String args, ClientData *pCD, XEvent *event)
3767 {
3768     register int i;
3769
3770
3771     if (pCD && pCD->mwmMessagesCount)
3772     {
3773         /*
3774          * A message id must be made "active" by being included in the
3775          * _MWM_MESSAGES property before the associated message can be sent.
3776          */
3777
3778         for (i = 0; i < pCD->mwmMessagesCount; i++)
3779         {
3780             if (pCD->mwmMessages[i] == (long)args)
3781             {
3782                 SendClientMsg (pCD->client, (long) wmGD.xa_MWM_MESSAGES, 
3783                     (long)args, CurrentTime, NULL, 0);
3784                 return (True);
3785             }
3786         }
3787     }
3788
3789     return (True);
3790
3791 } /* END OF FUNCTION F_Send_Msg */
3792
3793
3794 \f
3795 /*************************************<->*************************************
3796  *
3797  *  F_Separator (args, pCD, event)
3798  *
3799  *
3800  *  Description:
3801  *  -----------
3802  *  This is a placeholder function; it should never be called.
3803  *
3804  *************************************<->***********************************/
3805
3806 Boolean F_Separator (String args, ClientData *pCD, XEvent *event)
3807 {
3808
3809     return (True);
3810
3811 } /* END OF FUNCTION F_Separator */
3812
3813
3814 Boolean ForceRaiseWindow (ClientData *pcd)
3815 {
3816 #if 0
3817     Window stackWindow;
3818     WmScreenData *pSD = (ACTIVE_WS)->pSD;
3819 #endif
3820     XWindowChanges changes;
3821     Boolean restack = False;
3822
3823 #if 0
3824     if (pSD->clientList->type == MINIMIZED_STATE)
3825     {
3826         stackWindow = ICON_FRAME_WIN(pSD->clientList->pCD);
3827     }
3828     else
3829     {
3830         stackWindow = pSD->clientList->pCD->clientFrameWin;
3831     }
3832 #endif
3833
3834     /*
3835      * Windows did not raise on regular f.raise because the raise was
3836      * not relative to another window (methinks).
3837      */
3838     changes.stack_mode = Above;
3839     XConfigureWindow (DISPLAY, pcd->clientFrameWin, CWStackMode,
3840                       &changes);
3841
3842     return (restack);
3843 }
3844
3845
3846 \f
3847 /*************************************<->*************************************
3848  *
3849  *  F_Raise (args, pCD, event)
3850  *
3851  *
3852  *  Description:
3853  *  -----------
3854  *  This is the window manager function handler for topping the client window
3855  *  so that it is unobscured.
3856  *
3857  *************************************<->***********************************/
3858
3859 Boolean F_Raise (String args, ClientData *pCD, XEvent *event)
3860 {
3861     ClientListEntry *pEntry;
3862     ClientListEntry *pNextEntry;
3863     ClientListEntry *pStackEntry;
3864     String string = args;
3865     int flags = STACK_NORMAL;
3866 #ifdef WSM
3867         WmWorkspaceData *pWS = ACTIVE_WS;
3868 #endif /* WSM */
3869
3870     if (string)
3871     {
3872         /* process '-client' argument */
3873         if (string[0] == '-')
3874         {
3875             string = &string[1];
3876             string = (String) GetString ((unsigned char **) &string);
3877
3878             pStackEntry = NULL;
3879             pNextEntry = ACTIVE_PSD->clientList;
3880             while (pNextEntry &&
3881                    (pEntry = FindClientNameMatch (pNextEntry, True, string,
3882                                                   F_GROUP_ALL)))
3883             {
3884                 pNextEntry = pEntry->nextSibling;
3885 #ifdef WSM
3886                 if (ClientInWorkspace (pWS, pEntry->pCD))
3887                 {
3888 #endif /* WSM */
3889                 Do_Raise (pEntry->pCD, pStackEntry, STACK_NORMAL);
3890                 pStackEntry = pEntry;
3891 #ifdef WSM
3892                 }
3893 #endif /* WSM */
3894             }
3895         }
3896         /* process family stacking stuff */
3897         else if (*string)
3898         {
3899             unsigned int  slen, len, index;
3900
3901             slen = strlen(args) - 2;            /* subtract '\n' and NULL */
3902             for (index = 0; index < slen; string = &args[index+1])
3903             {
3904                 if ((string = (String) GetString ((unsigned char **) &string)) == NULL)
3905                    break;
3906                 len = strlen(string);
3907                 if (!strcmp(string,"within"))
3908                 {
3909                     flags |= STACK_WITHIN_FAMILY;
3910                 }
3911                 else if (!strcmp(string,"freeFamily"))
3912                 {
3913                     flags |= STACK_FREE_FAMILY;
3914                 }
3915                 index += len;
3916             }
3917 #ifdef WSM
3918             if (ClientInWorkspace (pWS, pCD))
3919             {
3920 #endif /* WSM */
3921             Do_Raise (pCD, (ClientListEntry *) NULL, flags);
3922 #ifdef WSM
3923             }
3924 #endif /* WSM */
3925         }
3926     }
3927     else if (pCD)
3928     {
3929 #ifdef WSM
3930         if (ClientInWorkspace (pWS, pCD))
3931         {
3932 #endif /* WSM */
3933         Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
3934 #ifdef WSM
3935         }
3936 #endif /* WSM */
3937     }
3938
3939     return (True);
3940
3941 } /* END OF FUNCTION F_Raise */
3942
3943
3944 \f
3945 /*************************************<->*************************************
3946  *
3947  *  Do_Raise (pCD, pStackEntry)
3948  *
3949  *
3950  *  Description:
3951  *  -----------
3952  *  This is the window manager function handler for topping the client window
3953  *  so that it is unobscured.
3954  *
3955  *
3956  *  Inputs:
3957  *  ------
3958  *  pCD = pointer to the client data of the window (or icon) to be raised.
3959  * 
3960  *  pStackEntry = pointer to client list entry for window that is to be 
3961  *      above the raised window (if NULL window is raised to the top of the
3962  *      stack).
3963  *
3964  *************************************<->***********************************/
3965
3966 void Do_Raise (ClientData *pCD, ClientListEntry *pStackEntry, int flags)
3967 {
3968     Boolean restackTransients;
3969     ClientData *pcdLeader;
3970     WmWorkspaceData *pWS = ACTIVE_WS;
3971 #ifdef WSM
3972     Boolean bLeaderRestacked;
3973 #endif /* WSM */
3974
3975 #ifdef PANELIST
3976     if (pCD->pECD)
3977     {
3978         /*
3979          * Window has been reparented into the front panel. 
3980          * Don't follow through on window stacking change.
3981          */
3982         return;
3983     }
3984     else 
3985 #else /* PANELIST */
3986 #endif /* PANELIST */
3987 #ifdef WSM
3988     if (ClientInWorkspace(pWS, pCD)  && 
3989         (!pStackEntry || ClientInWorkspace (pWS, pStackEntry->pCD)))
3990     {
3991         /* 
3992          * Both clients are in the current workspace. Set
3993          * client indices so that the access macros work.
3994          */
3995         SetClientWsIndex (pCD);
3996         if (pStackEntry)
3997         {
3998             SetClientWsIndex (pStackEntry->pCD);
3999         }
4000     }
4001     else
4002     {
4003         /*
4004          * One or both of the clients are not in the current workspace
4005          * Do nothing.
4006          */
4007         return;
4008     }
4009 #endif /* WSM */
4010
4011     pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
4012
4013     if (wmGD.systemModalActive && (pcdLeader != wmGD.systemModalClient))
4014     {
4015         /*
4016          * Don't raise the window above the system modal window.
4017          */
4018     }
4019     else if ((pcdLeader->clientState == MINIMIZED_STATE) &&
4020              !P_ICON_BOX(pcdLeader))
4021     {
4022         /*
4023          * If a dirtyStackEntry exists, return it to its original place 
4024          * in the stack (for all stacking types)
4025          */
4026         if (dirtyStackEntry)
4027         {
4028             if (dirtyStackEntry->transientChildren ||
4029                 dirtyStackEntry->transientLeader)
4030                 RestackTransients (dirtyStackEntry);
4031             dirtyStackEntry = NULL;
4032             dirtyLeader = NULL;
4033         }
4034
4035         /*
4036          * Only restack the icon if it is not currently raised.
4037          */
4038
4039         if (pStackEntry)
4040         {
4041             if (pStackEntry->nextSibling != &pcdLeader->iconEntry)
4042             {
4043                 StackWindow (pWS, &pcdLeader->iconEntry, False /*below*/,
4044                              pStackEntry);
4045                 MoveEntryInList (pWS, &pcdLeader->iconEntry, False /*below*/,
4046                                  pStackEntry);
4047             }
4048         }
4049         else
4050         {
4051             if (ACTIVE_PSD->clientList != &pcdLeader->iconEntry)
4052             {
4053                 StackWindow (pWS, &pcdLeader->iconEntry, 
4054                     True /*on top*/, (ClientListEntry *) NULL);
4055                 MoveEntryInList (pWS, &pcdLeader->iconEntry, 
4056                     True /*on top*/, (ClientListEntry *) NULL);
4057             }
4058         }
4059     }
4060     else /* NORMAL_STATE, MAXIMIZED_STATE, adoption */
4061     {
4062 #ifdef WSM
4063         /*
4064          * Handle restacking of primary/secondary windows
4065          * within the transient window tree. Don't raise this
4066          * window above any modal transients.
4067          */
4068         bLeaderRestacked = False;
4069         if ((pcdLeader->transientChildren) &&
4070             (!pCD->secondariesOnTop) &&
4071             (!wmGD.bSuspendSecondaryRestack) &&
4072             (!IS_APP_MODALIZED(pCD)))
4073         {
4074             if (pCD != pcdLeader)
4075             {
4076                 /* 
4077                  * This is not the transient leader, make sure
4078                  * the transient leader isn't on top.
4079                  * (Brute force solution)
4080                  */
4081                 bLeaderRestacked = NormalizeTransientTreeStacking (pcdLeader);
4082
4083                 if (pCD->transientChildren)
4084                 {
4085                     /*
4086                      * This isn't the overall leader of the transient 
4087                      * tree, but it does have transient's of its own.
4088                      * Move it to the top of its own transient sub-tree.
4089                      */
4090                     bLeaderRestacked |= BumpPrimaryToTop (pCD);
4091                 }
4092             }
4093             else 
4094             {
4095                 /*
4096                  * This is the transient leader, move it to the
4097                  * top.
4098                  */
4099                 bLeaderRestacked = BumpPrimaryToTop (pcdLeader);
4100             }
4101
4102         }
4103 #endif /* WSM */
4104         /*
4105          * If this is a transient window then put it on top of its
4106          * sibling transient windows.
4107          */
4108
4109         restackTransients = False;
4110
4111
4112 /*
4113  * Fix for 5325 - The following code has been reorganized to cause the
4114  *                action of F_Raise to match the current documentation.
4115  *                The new algorithm is as follows:
4116  *
4117  *                if (dirtyStackEntry)
4118  *                  restore dirty tree
4119  *                if (not withinFamily)
4120  *                  bring window group to the top of global stack
4121  *                if (freeFamily)
4122  *                  raise the requested window to top of family
4123  *                else
4124  *                  raise requested window to top of siblings
4125  *                if (need to restack windows)
4126  *                  restack windows
4127  *                return
4128  */
4129         /*
4130          * If a dirtyStackEntry exists, return it to its original place 
4131          * in the stack (for all stacking types)
4132          */
4133         if (dirtyStackEntry)
4134         {
4135             /*
4136              * Check to make sure that the dirty pCD has either transient
4137              * children or a transient leader.  If not, do not restore
4138              * the transients.
4139              */
4140             if (dirtyStackEntry->transientChildren ||
4141                 dirtyStackEntry->transientLeader)
4142                 RestackTransients (dirtyStackEntry);
4143             dirtyStackEntry = NULL;
4144             dirtyLeader = NULL;
4145         }
4146
4147         /*
4148          * If the flags do not indicate "within", raise the window family
4149          * to the top of the window stack. If the window is the primary,
4150          * raise it to the top regardless of the flags.
4151          */
4152         if (!pCD->transientLeader || !(flags & STACK_WITHIN_FAMILY))
4153         {
4154             if (pStackEntry)
4155             {
4156                 if (pStackEntry->nextSibling != &pcdLeader->clientEntry)
4157                 {
4158                     StackWindow (pWS, &pcdLeader->clientEntry, 
4159                         False /*below*/, pStackEntry);
4160                     MoveEntryInList (pWS, &pcdLeader->clientEntry, 
4161                         False /*below*/, pStackEntry);
4162                 }
4163             }
4164             else
4165             {
4166                 if (ACTIVE_PSD->clientList != &pcdLeader->clientEntry)
4167                 {
4168                     StackWindow (pWS, &pcdLeader->clientEntry,
4169                         True /*on top*/, (ClientListEntry *) NULL);
4170                     MoveEntryInList (pWS, &pcdLeader->clientEntry,
4171                         True /*on top*/, (ClientListEntry *) NULL);
4172                 }
4173             }
4174         }
4175   
4176         /*
4177          * If freeFamily stacking is requested, check to make sure that
4178          * the window has either a transientChild or Leader.  This will
4179          * guarantee that windows that form their own family are not
4180          * labelled as dirty (what's to dirty it up?).  If it has either,
4181          * raise the window to the top of the family stack.
4182          */
4183         if ((flags & STACK_FREE_FAMILY) &&
4184             (pCD->transientLeader || pCD->transientChildren))
4185         {
4186             dirtyStackEntry = pCD;
4187             dirtyLeader = pcdLeader;
4188   
4189             restackTransients = ForceRaiseWindow (pCD);
4190         }
4191   
4192         /*
4193          * If withinFamily stacking is requested, put the current transient
4194          * on top of its sibling transient windows.
4195          */
4196         else
4197         {
4198             restackTransients = PutTransientOnTop (pCD);
4199         }
4200   
4201         /* At this point, if doing a regular f.raise the window family has
4202          * already been brought to the top of the stack, so nothing further
4203          * needs to be done for it.
4204          */
4205   
4206         /* Restack the transients if needed */
4207   
4208 #ifdef WSM
4209         if ((restackTransients) || (bLeaderRestacked))
4210 #else /* WSM */
4211         if (restackTransients)
4212 #endif /* WSM */
4213         {
4214             RestackTransients (pCD);
4215         }
4216     }
4217
4218 } /* END OF FUNCTION Do_Raise */
4219
4220
4221 \f
4222 /*************************************<->*************************************
4223  *
4224  *  F_Raise_Lower (args, pCD, event)
4225  *
4226  *
4227  *  Description:
4228  *  -----------
4229  *  This window manager function tops an obscured window or icon and bottoms 
4230  *  a window or icon that is on top of the window stack.
4231  *
4232  *************************************<->***********************************/
4233
4234 Boolean F_Raise_Lower (String args, ClientData *pCD, XEvent *event)
4235 {
4236     ClientData *pcdLeader;
4237
4238     if (pCD)
4239     {
4240         pcdLeader = (pCD->transientLeader) ?
4241                                         FindTransientTreeLeader (pCD) : pCD;
4242
4243         /*
4244          * Treat a raise/lower on a window in a transient tree as if it is
4245          * a raise/lower for the whole tree.
4246          */
4247
4248         if (CheckIfClientObscuredByAny (pcdLeader))
4249         {
4250             /*
4251              * The window is obscured by another window, raise the window.
4252              */
4253
4254 #ifdef WSM
4255             F_Raise (NULL, pCD, (XEvent *)NULL);
4256 #else /* WSM */
4257             F_Raise (NULL, pcdLeader, (XEvent *)NULL);
4258 #endif /* WSM */
4259         }
4260         else if (CheckIfClientObscuringAny (pcdLeader) &&
4261                 !(wmGD.systemModalActive &&
4262                  (pcdLeader == wmGD.systemModalClient)))
4263         {
4264             /*
4265              * The window is obscuring another window and is
4266              * not system modal, lower the window.
4267              */
4268
4269             F_Lower (NULL, pcdLeader, (XEvent *)NULL);
4270 #ifdef WSM
4271             if ((pcdLeader->secondariesOnTop == False) &&
4272                 (pCD->transientLeader != NULL) &&
4273                 (!IS_APP_MODALIZED(pcdLeader)))
4274             {
4275                 /* Push transient below primary */
4276                 (void) BumpPrimaryToTop (pcdLeader);
4277                 RestackTransients (pcdLeader);
4278             }
4279 #endif /* WSM */
4280         }
4281 #ifdef WSM
4282         else if ((pcdLeader->secondariesOnTop == False) &&
4283                  (pcdLeader->transientChildren != NULL) &&
4284                  (!wmGD.systemModalActive) &&
4285                  (!IS_APP_MODALIZED(pcdLeader)))
4286         {
4287             if (LeaderOnTop(pcdLeader))
4288             {
4289                 /* Push primary below transient */
4290                 (void) BumpPrimaryToBottom (pcdLeader);
4291                 RestackTransients (pcdLeader);
4292             }
4293             else
4294             {
4295                 F_Raise (NULL, pCD, (XEvent *)NULL);
4296                 /* Push transient below primary */
4297                 (void) BumpPrimaryToTop (pcdLeader);
4298                 RestackTransients (pcdLeader);
4299             }
4300         }
4301 #endif /* WSM */
4302     }
4303
4304     return (True);
4305
4306 } /* END OF FUNCTION F_Raise_Lower */
4307
4308
4309 \f
4310 /*************************************<->*************************************
4311  *
4312  *  F_Refresh_Win (args, pCD, event)
4313  *
4314  *
4315  *  Description:
4316  *  -----------
4317  *  This is the window manager function handler for causing a client window
4318  *  to redisplay itself.
4319  *
4320  *************************************<->***********************************/
4321
4322 Boolean F_Refresh_Win (String args, ClientData *pCD, XEvent *event)
4323 {
4324     Window win;
4325     unsigned int w, h;
4326
4327     if (pCD && ((pCD->clientState == NORMAL_STATE) ||
4328                 (pCD->clientState == MAXIMIZED_STATE)))
4329     {
4330         if (pCD->clientState == NORMAL_STATE)
4331         {
4332             w = (unsigned int) pCD->clientWidth;
4333             h = (unsigned int) pCD->clientHeight;
4334         }
4335         else
4336         {
4337             w = (unsigned int) pCD->maxWidth;
4338             h = (unsigned int) pCD->maxHeight;
4339         }
4340
4341 #ifdef WSM
4342         if (wmGD.refreshByClearing)
4343         {
4344             RefreshByClearing (pCD->clientFrameWin);
4345         }
4346         else
4347         {
4348 #endif /* WSM */
4349                          /* default background_pixmap is None */
4350         win = XCreateWindow (DISPLAY,
4351                          pCD->clientBaseWin,
4352                          pCD->matteWidth,
4353                          pCD->matteWidth,
4354                          w, h,
4355                          0, 
4356                          0,
4357                          InputOutput,
4358                          CopyFromParent,
4359                          0, 
4360                          (XSetWindowAttributes *)NULL);  
4361
4362         XMapWindow (DISPLAY, win);
4363         XDestroyWindow (DISPLAY, win);
4364 #ifdef WSM
4365         }
4366 #endif /* WSM */
4367         XFlush (DISPLAY);
4368     }
4369
4370     return (True);
4371
4372 } /* END OF FUNCTION F_Refresh_Win */
4373
4374
4375 \f
4376 /*************************************<->*************************************
4377  *
4378  *  F_Set_Behavior (args, pCD, event)
4379  *
4380  *
4381  *  Description:
4382  *  -----------
4383  *  This function is used to switch the window manager configuration between
4384  *  the built-in configuration (for CXI behavior) and the user's custom
4385  *  configuration.
4386  *
4387  *************************************<->***********************************/
4388
4389 Boolean F_Set_Behavior (String args, ClientData *pCD, XEvent *event)
4390 {
4391     /*
4392      * Go system modal in starting to do the set behavior.
4393      */
4394
4395     /* !!! grab the server and the pointer !!! */
4396
4397
4398     /*
4399      * Confirm that a set_behavior should be done.
4400      * Execute restart if so.
4401      */
4402
4403     if (wmGD.showFeedback & WM_SHOW_FB_BEHAVIOR)
4404     {
4405         ConfirmAction (ACTIVE_PSD, (wmGD.useStandardBehavior) ?
4406                        CUSTOM_BEHAVIOR_ACTION : DEFAULT_BEHAVIOR_ACTION);
4407     }
4408     else
4409     {
4410         RestartWm ((long) ((wmGD.useStandardBehavior) ?
4411                         MWM_INFO_STARTUP_CUSTOM : MWM_INFO_STARTUP_STANDARD));
4412     }
4413     return (False);
4414
4415 } /* END OF FUNCTION F_Set_Behavior */
4416
4417
4418 \f
4419 /*************************************<->*************************************
4420  *
4421  *  Do_Set_Behavior (dummy)
4422  *
4423  *
4424  *  Description:
4425  *  -----------
4426  *  Callback to do the f.set_behavior function.
4427  *
4428  *************************************<->***********************************/
4429
4430 void Do_Set_Behavior (Boolean dummy)
4431 {
4432     RestartWm ((long) ((wmGD.useStandardBehavior) ?
4433                         MWM_INFO_STARTUP_CUSTOM : MWM_INFO_STARTUP_STANDARD));
4434
4435 } /* END OF FUNCTION Do_Set_Behavior */
4436
4437 #ifdef WSM
4438 \f
4439 /*************************************<->*************************************
4440  *
4441  *  F_Set_Context (args, pCD, event)
4442  *
4443  *
4444  *  Description:
4445  *  -----------
4446  *  This function is used to set a client context for subsequent
4447  *  WM_REQUESTs
4448  *
4449  *************************************<->***********************************/
4450
4451 Boolean F_Set_Context (String args, ClientData *pCD, XEvent *event)
4452 {
4453  
4454     wmGD.requestContextWin = (Window) args;
4455     return (True);
4456
4457 } /* END OF FUNCTION F_Set_Context */
4458 #endif /* WSM */
4459
4460 \f
4461 /*************************************<->*************************************
4462  *
4463  *  F_Title (args, pCD, event)
4464  *
4465  *
4466  *  Description:
4467  *  -----------
4468  *  This is a placeholder function; it should never be called.
4469  *
4470  *************************************<->***********************************/
4471
4472 Boolean F_Title (String args, ClientData *pCD, XEvent *event)
4473 {
4474
4475     return (True);
4476
4477 } /* END OF FUNCTION F_Title */
4478
4479
4480 \f
4481 /******************************<->*************************************
4482  *
4483  *  F_Screen (args, pCD, event)
4484  *
4485  *
4486  *  Description:
4487  *  -----------
4488  *  This is the window manager function handler for warping to screens
4489  *
4490  *
4491  *  Inputs:
4492  *  ------
4493  *  args = (immediate value) window type flags
4494  *
4495  *  pCD = pointer to the client data
4496  *
4497  *  event = X event that invoked the function (key, button, or menu/NULL)
4498  *
4499  *  NOTE: May want to consider tracking changes in screen because in
4500  *        managing a new window (ie. in ManageWindow()).
4501  *
4502  *  Outputs:
4503  *  -------
4504  *  RETURN = if True then further button binding/function processing can
4505  *           be done for the event that caused this function to be called.
4506  *
4507  *************************************<->***********************************/
4508
4509 Boolean F_Screen (String args, ClientData *pCD, XEvent *event)
4510 {
4511     Window dumwin;
4512     int x, y, dumint;
4513     unsigned int dummask;
4514     WmScreenData *newscr = NULL;
4515     int scr, inc;
4516     static int PreviousScreen = -1;
4517     char pch[80];
4518     
4519
4520     if (PreviousScreen == -1)
4521     {
4522         PreviousScreen = DefaultScreen(DISPLAY);
4523     }
4524
4525     if (strcmp (args, "next") == 0)
4526     {
4527         scr = ACTIVE_PSD->screen + 1;
4528         inc = 1;
4529     }
4530     else if (strcmp (args, "prev") == 0)
4531     {
4532         scr = ACTIVE_PSD->screen - 1;
4533         inc = -1;
4534     }
4535     else if (strcmp (args, "back") == 0)
4536     {
4537         scr = PreviousScreen;
4538         inc = 0;
4539     }
4540     else
4541     {
4542         scr = atoi (args);
4543         inc = 0;
4544     }
4545
4546     while (!newscr) {
4547                                         /* wrap around */
4548         if (scr < 0) 
4549           scr = wmGD.numScreens - 1;
4550         else if (scr >= wmGD.numScreens)
4551           scr = 0;
4552
4553         newscr = &(wmGD.Screens[scr]);
4554         if (!wmGD.Screens[scr].managed) { /* make sure screen is managed */
4555             if (inc) {                  /* walk around the list */
4556                 scr += inc;
4557                 continue;
4558             }
4559             sprintf(pch, 
4560                     "Unable to warp to unmanaged screen %d\n", scr);
4561             Warning (&pch[0]);
4562             XBell (DISPLAY, 0);
4563             return (False);
4564         }
4565     }
4566
4567     if (ACTIVE_PSD->screen == scr) return (False);  /* already on that screen */
4568
4569     PreviousScreen = ACTIVE_PSD->screen;
4570     XQueryPointer (DISPLAY, ACTIVE_ROOT, &dumwin, &dumwin, &x, &y,
4571                    &dumint, &dumint, &dummask);
4572
4573     XWarpPointer (DISPLAY, None, newscr->rootWindow, 0, 0, 0, 0, x, y);
4574
4575     if (newscr && (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
4576     {
4577         /*
4578          * Set the ACTIVE_PSD to the new screen so that Do_Focus_Key can 
4579          * uses the new screen instead of the old screen.  Then call
4580          * Do_Focus_Key with a NULL pCD to find a reasonable client to
4581          * set focus to.
4582          */
4583         SetActiveScreen (newscr);
4584         Do_Focus_Key (NULL, GetFunctionTimestamp ((XButtonEvent *)event),
4585                       ALWAYS_SET_FOCUS);
4586     }
4587
4588     return (False);
4589 }
4590
4591
4592 \f
4593 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
4594 /*************************************<->*************************************
4595  *
4596  *  F_InvokeCommand (args, pCD, event)
4597  *
4598  *
4599  *  Description:
4600  *  -----------
4601  *  This is the window manager function for invoking client inserted menu
4602  *  commands.
4603  *
4604  *************************************<->***********************************/
4605
4606 Boolean F_InvokeCommand (String args, ClientData *pCD, XEvent *event)
4607 {
4608     CARD32 commandID, clientWindow;
4609     Atom notifySelection;
4610
4611     if (args == (String) NULL) return(FALSE);
4612
4613     if (sscanf(args, "%d %d %ld", &commandID, &clientWindow,
4614                &notifySelection) != 3)
4615       return(FALSE);
4616
4617     SendInvokeMessage(commandID,
4618                       (pCD == (ClientData *) NULL ? 0 : pCD->client),
4619                       notifySelection,
4620                       LastTime());
4621
4622     return (True);
4623 } /* END OF FUNCTION F_InvokeCommand */
4624 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
4625
4626 \f
4627 /*************************************<->*************************************
4628  *
4629  *  GetFunctionTimestamp (pEvent)
4630  *
4631  *
4632  *  Description:
4633  *  -----------
4634  *  This function is used to extract a timestamp from a key or button event.
4635  *  If the event passed in is not a key or button event then a timestamp
4636  *  is generated.
4637  *
4638  *
4639  *  Inputs:
4640  *  ------
4641  *  event = pointer to an X event
4642  *
4643  *
4644  *  Outputs:
4645  *  -------
4646  *  RETURN = a timestamp
4647  *
4648  *************************************<->***********************************/
4649
4650 Time GetFunctionTimestamp (XButtonEvent *pEvent)
4651 {
4652     Time time;
4653
4654     if (pEvent &&
4655         (((pEvent->type == ButtonPress) || (pEvent->type == ButtonRelease)) ||
4656          ((pEvent->type == KeyPress) || (pEvent->type == KeyRelease))))
4657     {
4658         time = pEvent->time;
4659     }
4660     else
4661     {
4662         time = GetTimestamp ();
4663     }
4664
4665     return (time);
4666
4667 } /* END OF FUNCTION GetFunctionTimestamp */
4668
4669
4670 /*
4671 ** name the event mask we need for a grab in order to find the matching 
4672 ** event for an event; right now handle only button-presses
4673 */
4674 static unsigned int GetEventInverseMask(XEvent *event)
4675 {
4676         if ((XEvent*)NULL == event)
4677                 return 0;
4678         if (ButtonPress == event->type)
4679                 return ButtonReleaseMask;       /* detail ? */
4680         /*
4681         expansion further here
4682         */
4683         else 
4684                 return 0;
4685 }
4686
4687
4688
4689 /*************************************<->*************************************
4690  *
4691  *  ClearDirtyStackEntry (pCD)
4692  *
4693  *
4694  *  Description:
4695  *  -----------
4696  *  This function is used to clear the static dirtyStackEntry structure and
4697  *  the dirtyLeader static variable when a pCD is destroyed.  This 
4698  *  guarantees that freed memory will not be accessed.
4699  *
4700  *
4701  *  Inputs:
4702  *  ------
4703  *  pCD = pointer to clientData being freed
4704  *
4705  *
4706  *  Outputs:
4707  *  -------
4708  *  RETURN = void
4709  *
4710  *************************************<->***********************************/
4711
4712 void ClearDirtyStackEntry (ClientData *pCD)
4713 {
4714   if (pCD == dirtyStackEntry)
4715     {
4716       dirtyStackEntry = NULL;
4717       dirtyLeader = NULL;
4718     }
4719 }
4720 #if defined(DEBUG) && defined(WSM)
4721 \f
4722 /***********************<->*************************************
4723  *
4724  *  F_ZZ_Debug (args, pCD, event)
4725  *
4726  *
4727  *  Description:
4728  *  -----------
4729  *  This is the window manager debug (multi) function
4730  *
4731  *
4732  *  Inputs:
4733  *  ------
4734  *  args = arguments
4735  *
4736  *  pCD = pointer to the ClientData for the whole front panel
4737  *
4738  *  event = X event that invoked the function (key, button, or menu/NULL)
4739  *
4740  *
4741  *  Outputs:
4742  *  -------
4743  *  RETURN = if True then further button binding/function processing can
4744  *           be done for the event that caused this function to be called.
4745  *
4746  *  Comments:
4747  *  -------
4748  *  Argument 1 determines the debug function to execute:
4749  *
4750  *  Valid arguments:
4751  *
4752  *      "color_server_info"  - dump out color server info
4753  *
4754  ******************************<->***********************************/
4755
4756 Boolean
4757 F_ZZ_Debug (String subFcn, ClientData *pCD, XEvent *event)
4758 {
4759     /* Only do something is sub function is specified */
4760
4761     if (subFcn)
4762     {
4763         if (!(strcmp(subFcn, "dump_resources")))
4764         {
4765             int scr;
4766             char szRes[80];
4767
4768             for (scr=0; scr<wmGD.numScreens; scr++)
4769             {
4770                 sprintf (szRes, "/tmp/dtwm.resources.%d", scr);
4771
4772                 XrmPutFileDatabase(XtScreenDatabase(
4773                                        XScreenOfDisplay(DISPLAY, scr)), 
4774                                    szRes);
4775             }
4776         }
4777     }
4778     return (True);
4779 }
4780 #endif /* DEBUG */
4781
4782 #ifdef WSM
4783 \f
4784 /*************************************<->*************************************
4785  *
4786  *  F_Next_Workspace (args, pCD, event)
4787  *
4788  *
4789  *  Description:
4790  *  -----------
4791  *  This function switches to the next workspace in the list
4792  *
4793  *************************************<->***********************************/
4794
4795 Boolean F_Next_Workspace (String args, ClientData *pCD, XEvent *event)
4796 {
4797     WmScreenData *pSD = ACTIVE_PSD;
4798     int iwsx;
4799
4800     for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
4801     {
4802         if (pSD->pWS[iwsx].id == pSD->pActiveWS->id)
4803         {
4804             iwsx++;
4805             break;
4806         }
4807     }
4808
4809     /* check bounds and wrap */
4810     if (iwsx >= pSD->numWorkspaces)
4811         iwsx = 0;
4812
4813     ChangeToWorkspace (&pSD->pWS[iwsx]);
4814
4815
4816     return (False);
4817
4818 } /* END OF FUNCTION F_Next_Workspace */
4819
4820 \f
4821 /*************************************<->*************************************
4822  *
4823  *  F_Prev_Workspace (args, pCD, event)
4824  *
4825  *
4826  *  Description:
4827  *  -----------
4828  *  This function switches to the previous workspace in the list
4829  *
4830  *************************************<->***********************************/
4831
4832 Boolean F_Prev_Workspace (String args, ClientData *pCD, XEvent *event)
4833 {
4834     WmScreenData *pSD = ACTIVE_PSD;
4835     int iwsx;
4836
4837     for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
4838     {
4839         if (pSD->pWS[iwsx].id == pSD->pActiveWS->id)
4840         {
4841             iwsx--;
4842             break;
4843         }
4844     }
4845
4846     /* check bounds and wrap */
4847     if (iwsx < 0)
4848         iwsx = pSD->numWorkspaces - 1;
4849
4850     ChangeToWorkspace (&pSD->pWS[iwsx]);
4851
4852
4853     return (False);
4854
4855 } /* END OF FUNCTION F_Prev_Workspace */
4856
4857
4858 \f
4859 /*************************************<->*************************************
4860  *
4861  *  F_Workspace_Presence (args, pCD, event)
4862  *
4863  *
4864  *  Description:
4865  *  -----------
4866  *  This function pops up the workspace presence dialog box
4867  *
4868  *************************************<->***********************************/
4869
4870 Boolean F_Workspace_Presence (String args, ClientData *pCD, XEvent *event)
4871 {
4872     Context wsContext = (Context)NULL;
4873
4874     if (pCD && (pCD->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS))
4875     {
4876         if (pCD->clientState == NORMAL_STATE)
4877         {
4878             wsContext = F_CONTEXT_NORMAL;
4879         }
4880         else if (pCD->clientState == MAXIMIZED_STATE)
4881         {
4882             wsContext = F_CONTEXT_MAXIMIZE;
4883         }
4884         else 
4885         {
4886             wsContext = F_CONTEXT_ICON;
4887 /*          return (False); */
4888         }
4889         ShowPresenceBox (pCD, wsContext);
4890     }
4891     return (False);
4892
4893 } /* END OF FUNCTION F_Workspace_Presence */
4894
4895 #ifdef DEBUG
4896 void
4897 DumpWindowList ()
4898 {
4899     WmScreenData *pSD = (ACTIVE_WS)->pSD;
4900     ClientListEntry     *pCLE;
4901
4902     fprintf (stdout, "Window stacking (bottom to top)\n");
4903     pCLE = pSD->lastClient;
4904     while (pCLE)
4905     {
4906         if (ClientInWorkspace (ACTIVE_WS, pCLE->pCD))
4907             fprintf (stdout, "* ");
4908         else
4909             fprintf (stdout, "  ");
4910
4911         fprintf (stdout, "%08lx\t%s\n", 
4912             pCLE->pCD->client,
4913             pCLE->pCD->clientName);
4914
4915         pCLE = pCLE->prevSibling;
4916     }
4917 }
4918 #endif /* DEBUG */
4919
4920 #endif /* WSM */
4921
4922
4923