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