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