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