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