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