dtwm: Remove id strings related to historic version control system used before CDE...
[oweals/cde.git] / cde / programs / dtwm / WmWinList.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.3
29 */ 
30 /*
31  * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 Hewlett-Packard Company
32  * (c) Copyright 1993, 1994 International Business Machines Corp.
33  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
34  * (c) Copyright 1993, 1994 Novell, Inc.
35  */
36
37 /*
38  * Included Files:
39  */
40
41 #include "WmGlobal.h"
42
43 #define MWM_NEED_NOENTER16
44 #include "WmBitmap.h"
45
46
47 /*
48  * include extern functions
49  */
50 #include "WmWinList.h"
51 #include "WmCEvent.h"
52 #include "WmEvent.h"
53 #include "WmFunction.h"
54 #include "WmKeyFocus.h"
55 #include "WmMenu.h"
56 #include "WmResource.h"
57 #include "WmWinInfo.h"
58 #ifdef WSM
59 #include "WmWrkspace.h"
60 #endif /* WSM */
61
62
63
64
65 /*
66  * Global Variables:
67  */
68
69 \f
70 /*************************************<->*************************************
71  *
72  *  AddClientToList (pWS, pCD, onTop)
73  *
74  *
75  *  Description:
76  *  -----------
77  *  This function adds a client window to the client window list.  If it is
78  *  a transient window then it is added to the transient window tree that
79  *  contains its transient leader.  The window stacking order is also
80  *  maintained for the cases where there is a system modal window active
81  *  or the window is a transient window.  If a system modal window is being
82  *  added then the system modal "input screen" window is setup.
83  *
84  *
85  *  Inputs:
86  *  ------
87  *  pCD = pointer to client data for the window to be added to the list
88  *
89  *  pWS = pointer to workspace data
90  *
91  *  onTop = if True then the window is displayed on top of the window
92  *      stack and is added to the beginning of the window list, otherwise
93  *      it is added to the end of the window list.
94  *
95  * 
96  *  Outputs:
97  *  -------
98  *  pWS = (clientList, lastClient)
99  * 
100  *************************************<->***********************************/
101
102 void AddClientToList (WmWorkspaceData *pWS, ClientData *pCD, Boolean onTop)
103 {
104     Boolean belowSystemModal = False;
105     XWindowChanges windowChanges;
106     WmScreenData *pSD = pWS->pSD;
107 #ifdef WSM
108     WsClientData *pWsc = GetWsClientData (pWS, pCD);
109 #endif /* WSM */
110
111
112     if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
113     {
114         /*
115          * Set up the system modal input screen window just below the
116          * system modal window.
117          */
118
119         SetupSystemModalState (pCD);
120
121         if (!wmGD.systemModalActive || (wmGD.systemModalClient != pCD))
122         {
123             /*
124              * If we failed to setup as system modal, then 
125              * back off to MWM_INPUT_FULL_APPLICATION_MODAL.
126              * This will do *something* if this is a transient 
127              * window.
128              */
129             pCD->inputMode = MWM_INPUT_FULL_APPLICATION_MODAL;
130         }
131     }
132     else if (wmGD.systemModalActive &&
133              ((FindTransientTreeLeader (pCD))->inputMode !=
134               MWM_INPUT_SYSTEM_MODAL))
135     {
136         /*
137          * If a system modal window is active then place the window below
138          * the system modal input screen window if the window is not a
139          * descendant of the system modal window.
140          */
141
142         windowChanges.sibling = pSD->inputScreenWindow;
143         windowChanges.stack_mode = Below;
144         XConfigureWindow (DISPLAY, pCD->clientFrameWin,
145             CWSibling | CWStackMode, &windowChanges);
146         belowSystemModal = True;
147     }
148
149     if (pCD->transientLeader)
150     {
151         AddTransient (pWS, pCD);
152     }
153     else
154     {
155         pCD->clientEntry.type = NORMAL_STATE;
156         pCD->clientEntry.pCD = pCD;
157
158         if (belowSystemModal && wmGD.systemModalClient)
159         {
160             AddEntryToList (pWS, &pCD->clientEntry, False /*below*/,
161                             pSD->clientList);
162         }
163         else if (onTop)
164         {
165             AddEntryToList (pWS, &pCD->clientEntry, True /*on top*/, NULL);
166         }
167         else
168         {
169             AddEntryToList (pWS, &pCD->clientEntry, False /*on bottom*/, NULL);
170         }
171
172
173 #ifdef WSM
174         if (!pWsc->pIconBox && pWsc->iconFrameWin)
175 #else /* WSM */
176         if (!pCD->pIconBox && pCD->iconFrameWin)
177 #endif /* WSM */
178         {
179             /*
180              * Put the icon on the bottom of the stack.
181              */
182
183             if (pSD->lastClient->type == MINIMIZED_STATE)
184             {
185 #ifdef WSM
186                 WsClientData *pWsib;
187
188                 pWsib = &pSD->lastClient->pCD->pWsList[0];
189                 windowChanges.sibling = pWsib->iconFrameWin;
190 #else /* WSM */
191                 windowChanges.sibling = pSD->lastClient->pCD->iconFrameWin;
192 #endif /* WSM */
193             }
194             else
195             {
196                 windowChanges.sibling = pSD->lastClient->pCD->clientFrameWin;
197             }
198             windowChanges.stack_mode = Below;
199 #ifdef WSM
200             XConfigureWindow (DISPLAY, pWsc->iconFrameWin,
201                 CWSibling | CWStackMode, &windowChanges);
202 #else /* WSM */
203             XConfigureWindow (DISPLAY, pCD->iconFrameWin,
204                 CWSibling | CWStackMode, &windowChanges);
205 #endif /* WSM */
206
207             pCD->iconEntry.type = MINIMIZED_STATE;
208             pCD->iconEntry.pCD = pCD;
209             pCD->iconEntry.nextSibling = NULL;
210             pCD->iconEntry.prevSibling = pSD->lastClient;
211             pSD->lastClient->nextSibling = &pCD->iconEntry;
212             pSD->lastClient = &pCD->iconEntry;
213         }
214     }
215
216 } /* END OF FUNCTION AddClientToList */
217
218
219 \f
220 /*************************************<->*************************************
221  *
222  *  AddEntryToList (pWS, pEntry, onTop, pStackEntry)
223  *
224  *
225  *  Description:
226  *  -----------
227  *  This function adds a client list entry to the client window list.
228  *  This is usually done as part of the process of changing the ordering
229  *  of the window list.
230  *
231  *
232  *  Inputs:
233  *  ------
234  *  pWS  = pointer to workspace data
235  *  pEntry = pointer to a client list entry to be added to the client list
236  *
237  *  onTop = if True then the client list entry is added on top of the 
238  *      specified client list stack entry (if the stack entry is not
239  *      specified then the entry is added to the front of the list);
240  *      otherwise the entry is added after the specified stacking entry
241  *      (or to the end of the list if the stacking entry is not specified).
242  *
243  *  pStackEntry = pointer to a client list entry to be used as a reference
244  *      in adding an entry to the client list.
245  * 
246  *  Outputs:
247  *  -------
248  *  pWS = (clientList, lastClient)
249  * 
250  *************************************<->***********************************/
251
252 void AddEntryToList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
253 {
254     WmScreenData *pSD = pWS->pSD;
255
256     if (onTop)
257     {
258         if (pStackEntry)
259         {
260             if (pEntry != pStackEntry)
261             {
262                 pEntry->nextSibling = pStackEntry;
263                 pEntry->prevSibling = pStackEntry->prevSibling;
264                 pStackEntry->prevSibling = pEntry;
265                 if (pEntry->prevSibling)
266                 {
267                     pEntry->prevSibling->nextSibling = pEntry;
268                 }
269                 else
270                 {
271                     pSD->clientList = pEntry;
272                 }
273             }
274         }
275         else
276         {
277             if (pSD->clientList != pEntry)
278             {
279                 pEntry->nextSibling = pSD->clientList;
280                 pEntry->prevSibling = NULL;
281                 if (pSD->clientList)
282                 {
283                     pSD->clientList->prevSibling = pEntry;
284                 }
285                 else
286                 {
287                     pSD->lastClient = pEntry;
288                 }
289                 pSD->clientList = pEntry;
290             }
291         }
292     }
293     else
294     {
295         if (pStackEntry)
296         {
297             if (pEntry != pStackEntry)
298             {
299                 pEntry->nextSibling = pStackEntry->nextSibling;
300                 pEntry->prevSibling = pStackEntry;
301                 pStackEntry->nextSibling = pEntry;
302                 if (pEntry->nextSibling)
303                 {
304                     pEntry->nextSibling->prevSibling = pEntry;
305                 }
306                 else
307                 {
308                     pSD->lastClient = pEntry;
309                 }
310             }
311         }
312         else
313         {
314             if (pSD->lastClient != pEntry)
315             {
316                 pEntry->nextSibling = NULL;
317                 pEntry->prevSibling = pSD->lastClient;
318                 if (pSD->clientList)
319                 {
320                     pSD->lastClient->nextSibling = pEntry;
321                 }
322                 else
323                 {
324                     pSD->clientList = pEntry;
325                 }
326                 pSD->lastClient = pEntry;
327             }
328         }
329     }
330
331 } /* END OF FUNCTION AddEntryToList */
332
333
334 \f
335 /*************************************<->*************************************
336  *
337  *  MoveEntryInList (pWS, pEntry, onTop, pStackEntry)
338  *
339  *
340  *  Description:
341  *  -----------
342  *  This function moves a client list entry in the client window list.
343  *
344  *
345  *  Inputs:
346  *  ------
347  *  pWS = pointer to workspace data
348  *
349  *  pEntry = pointer to a client list entry to be moved in the client list
350  *
351  *  onTop = if True then the client list entry is moved on top of the 
352  *      specified client list stack entry (if the stack entry is not
353  *      specified then the entry is moved to the front of the list);
354  *      otherwise the entry is moved after the specified stacking entry
355  *      (or to the end of the list if the stacking entry is not specified).
356  *
357  *  pStackEntry = pointer to a client list entry to be used as a reference
358  *      in moving an entry in the client list.
359  * 
360  *  Outputs:
361  *  -------
362  *  pWS = (clientList, lastClient)
363  * 
364  *************************************<->***********************************/
365
366 void MoveEntryInList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
367 {
368     DeleteEntryFromList (pWS, pEntry);
369     AddEntryToList (pWS, pEntry, onTop, pStackEntry);
370
371 } /* END OF FUNCTION MoveEntryInList */
372
373
374 \f
375 /*************************************<->*************************************
376  *
377  *  DeleteEntryFromList (pWS, pListEntry)
378  *
379  *
380  *  Description:
381  *  -----------
382  *  This function deletes a client list entry from the client window list.
383  *  This is usually done as part of the process of changing the ordering
384  *  of the window list.
385  *
386  *
387  *  Inputs:
388  *  ------
389  *  pWS = pointer to workspace data
390  *  listEntry = pointer to a client list entry
391  * 
392  *  Outputs:
393  *  -------
394  *  pWS = (clientList, lastClient)
395  * 
396  *************************************<->***********************************/
397
398 void DeleteEntryFromList (WmWorkspaceData *pWS, ClientListEntry *pListEntry)
399 {
400     
401     if (pListEntry->prevSibling)
402     {
403         pListEntry->prevSibling->nextSibling = pListEntry->nextSibling;
404     }
405     else
406     {
407         pWS->pSD->clientList = pListEntry->nextSibling;
408     }
409
410     if (pListEntry->nextSibling)
411     {
412         pListEntry->nextSibling->prevSibling = pListEntry->prevSibling;
413     }
414     else
415     {
416         pWS->pSD->lastClient = pListEntry->prevSibling;
417     }
418
419 } /* END OF FUNCTION DeleteEntryFromList */
420
421
422 \f
423 /*************************************<->*************************************
424  *
425  *  DeleteClientFromList (pWS, pCD)
426  *
427  *
428  *  Description:
429  *  -----------
430  *  This function deletes a client from the client window list.  If this is
431  *  a transient window then it is deleted from its transient window tree.
432  *  If this is a system modal window then clean up the system modal state.
433  *
434  *
435  *  Inputs:
436  *  ------
437  *  pCD = pointer to client data for the window to be added to the list
438  * 
439  *  Outputs:
440  *  -------
441  *  pWS = (clientList, lastClient)
442  * 
443  *************************************<->***********************************/
444
445 void DeleteClientFromList (WmWorkspaceData *pWS, ClientData *pCD)
446 {
447 #ifdef WSM
448     WsClientData *pWsc = GetWsClientData (pWS, pCD);
449 #endif /* WSM */
450     WmScreenData *pSD = pWS->pSD;
451
452     if (pCD->transientLeader)
453     {
454         DeleteTransient (pCD);
455     }
456     else
457     {
458         /*
459          * If this is a system modal window then clean up the system modal
460          * state.
461          */
462
463         if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
464         {
465             UndoSystemModalState ();
466         }
467
468         /*
469          * Remove the client and icon entries from the window list.
470          */
471
472 #ifdef WSM
473         if (!pWsc->pIconBox && pWsc->iconFrameWin)
474 #else /* WSM */
475         if (!pCD->pIconBox && pCD->iconFrameWin)
476 #endif /* WSM */
477         {
478             if (pCD->iconEntry.prevSibling)
479             {
480                 pCD->iconEntry.prevSibling->nextSibling =
481                                                 pCD->iconEntry.nextSibling;
482             }
483             else
484             {
485                 pSD->clientList = pCD->iconEntry.nextSibling;
486             }
487             if (pCD->iconEntry.nextSibling)
488             {
489                 pCD->iconEntry.nextSibling->prevSibling =
490                                                 pCD->iconEntry.prevSibling;
491             }
492             else
493             {
494                 pSD->lastClient = pCD->iconEntry.prevSibling;
495             }
496         }
497
498         if (pCD->clientEntry.prevSibling)
499         {
500             pCD->clientEntry.prevSibling->nextSibling =
501                                                 pCD->clientEntry.nextSibling;
502         }
503         else
504         {
505             pSD->clientList = pCD->clientEntry.nextSibling;
506         }
507
508         if (pCD->clientEntry.nextSibling)
509         {
510             pCD->clientEntry.nextSibling->prevSibling =
511                                                 pCD->clientEntry.prevSibling;
512         }
513         else
514         {
515             pSD->lastClient = pCD->clientEntry.prevSibling;
516         }
517     }
518
519 } /* END OF FUNCTION DeleteClientFromList */
520
521
522 \f
523 /*************************************<->*************************************
524  *
525  *  AddTransient (pWS, pCD)
526  *
527  *
528  *  Description:
529  *  -----------
530  *  This function adds the transient window to the lead window's list of
531  *  transients.
532  *
533  *
534  *  Inputs:
535  *  ------
536  *  pWS = pointer to workspace data
537  *  pCD = pointer to client data of a transient window
538  *
539  * 
540  *  Outputs:
541  *  -------
542  *  pCD->transientLeader = (transientChildren, modalCount)
543  * 
544  *************************************<->***********************************/
545
546 void AddTransient (WmWorkspaceData *pWS, ClientData *pCD)
547 {
548     ClientData *pcdLeader = pCD->transientLeader;
549     ClientData *pcdTop = FindTransientTreeLeader (pCD);
550     Boolean restackTransients;
551     WmScreenData *pSD = pWS->pSD;
552
553
554     pCD->transientSiblings = pcdLeader->transientChildren;
555     pcdLeader->transientChildren = pCD;
556
557
558     /*
559      * Insure that the new transient window is on top of its siblings
560      * and that the transient window tree is on top of the window
561      * stack (this is the standard behavior for newly mapped and
562      * managed windows).  If there is a system modal window that the
563      * transient window is not associated with then don't raise the
564      * transient tree.
565      */
566
567     restackTransients = PutTransientOnTop (pCD);
568
569
570     /*
571      * Handle application modal transient windows
572      */
573
574     if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
575     {
576         /*
577          * If this is a primary application modal window then increment 
578          * the modal count for transient leaders that are directly up 
579          * the transient tree.
580          *
581          * (This is the old MWM_INPUT_APPLICATION_MODAL behavior.)
582          */
583         while (pcdLeader)
584         {
585             MarkModalTransient (pcdLeader, pCD);
586             pcdLeader = pcdLeader->transientLeader;
587         }
588     }
589     else if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
590     {
591         /*
592          * If this is a full application modal window then increment 
593          * the modal count for the rest of the transient tree.
594          */
595
596         MarkModalSubtree (pcdTop, pCD);
597     }
598     else if (pcdTop->fullModalCount)
599     {
600         /*
601          * There is already a full application modal window in the tree
602          */
603         pcdLeader = pCD->transientLeader;
604         if ((pcdLeader->inputMode != MWM_INPUT_FULL_APPLICATION_MODAL) ||
605             (IS_APP_MODALIZED(pcdLeader)))
606         {
607             /*
608              * The immediate parent of this transient is not the
609              * current full application modal window.  Set the full
610              * modal count to the parent's so that they both become
611              * unmodalized at the same time. This allows a full
612              * app modal window to have active, non-modal transients.
613              */
614             pCD->fullModalCount = pcdLeader->fullModalCount;
615         }
616     }
617
618
619     /*
620      * Do the actual restacking in the X window stack if necessary.
621      */
622
623     if ((pSD->clientList != &pcdTop->clientEntry) && !wmGD.systemModalActive)
624     {
625         F_Raise (NULL, pCD, NULL);
626     }
627     else if (restackTransients)
628     {
629         RestackTransientsAtWindow (pCD);
630     }
631     else if (pCD != FindTransientOnTop (pcdTop))
632     {
633         StackTransientWindow (pCD);
634     }
635
636
637 } /* END OF FUNCTION AddTransient */
638
639
640 \f
641 /*************************************<->*************************************
642  *
643  *  MarkModalSubtree (pcdTree, pcdAvoid)
644  *
645  *
646  *  Description:
647  *  -----------
648  *  This function marks the transient tree with pcdTree as its leader.
649  *  If pcdAvoid is in the tree, it is not marked.
650  *
651  *  Inputs:
652  *  ------
653  *  pcdTree     = pointer to client data of the tree to mark
654  *  pcdAvoid    = pointer to client data to not mark if in tree
655  *
656  * 
657  *************************************<->***********************************/
658
659 void MarkModalSubtree (ClientData *pcdTree, ClientData *pcdAvoid)
660 {
661     /* Mark children, if any */
662
663     if (pcdTree->transientChildren)
664         MarkModalSubtree (pcdTree->transientChildren, pcdAvoid);
665
666     /* Mark this node */
667
668     if (pcdTree != pcdAvoid) 
669     {
670         MarkModalTransient (pcdTree, pcdAvoid);
671     }
672
673     /* Mark siblings */
674
675     if (pcdTree->transientSiblings)
676         MarkModalSubtree (pcdTree->transientSiblings, pcdAvoid);
677
678 }
679
680 \f
681 /*************************************<->*************************************
682  *
683  *  MarkModalTransient (pcdLeader, pCD)
684  *
685  *
686  *  Description:
687  *  -----------
688  *  This function marks a transient window for application modal processing.
689  *  Grabs are done to eat up pointer button events.
690  *
691  *  Inputs:
692  *  ------
693  *  pcdLeader = pointer to client data to mark
694  *  pCD = pointer to client data of new transient
695  *
696  * 
697  *************************************<->***********************************/
698
699 void MarkModalTransient (ClientData *pcdLeader, ClientData *pCD)
700 {
701     if (!IS_APP_MODALIZED(pcdLeader))
702     {
703         /*
704          * Eat pointer button events while application modal.
705          */
706         XGrabButton (DISPLAY, AnyButton, AnyModifier,
707             pcdLeader->clientBaseWin, True,
708             ButtonPressMask | ButtonMotionMask, GrabModeAsync,
709             GrabModeAsync, None, wmGD.workspaceCursor);
710     }
711
712     /* bump application modal count */
713     if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
714         pcdLeader->fullModalCount++;
715     else 
716         pcdLeader->primaryModalCount++;
717 }
718
719 \f
720 /*************************************<->*************************************
721  *
722  *  DeleteTransient (pCD)
723  *
724  *
725  *  Description:
726  *  -----------
727  *  This function deletes the transient window from the lead window's list
728  *  of transients
729  *
730  *  Much of the complication of this code arises from trying to handle
731  *  mixtures of both full- and primary-application modal transients.
732  *  It also tries to handle the case where a sequence of application
733  *  modal transients appear in different places in the transient tree
734  *  (i.e. not as descendents of a previously existing full app modal 
735  *  transient).
736  *
737  *  Inputs:
738  *  ------
739  *  pCD = pointer to client data of transient.
740  *
741  *************************************<->***********************************/
742
743 void DeleteTransient (ClientData *pCD)
744 {
745     ClientData *pcdLeader;
746     ClientData *pcdPrev; 
747     int modalCount;
748
749
750     /*
751      * Handle primary application modality.
752      * Reset the modal window counts for the leader windows up through the
753      * transient window tree.
754      */
755
756     modalCount = pCD->primaryModalCount;
757     if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
758     {
759         modalCount += 1;
760     }
761     if (modalCount)
762     {
763         pcdLeader = pCD->transientLeader;
764         while (pcdLeader)
765         {
766             if (modalCount)
767                 UnMarkModalTransient (pcdLeader, modalCount, pCD);
768
769             pcdLeader = pcdLeader->transientLeader;
770         }
771     }
772
773     /*
774      * Handle full application modality.
775      * Undo application modal windows in a depth first manner.
776      */
777
778     pcdLeader = FindTransientTreeLeader (pCD);
779
780     if (pCD->transientChildren)
781     {
782         DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
783     }
784     if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
785
786     {
787         /*
788          * If this is a full application modal window then decrement 
789          * the modal count for the rest of the transient tree.
790          */
791
792         FixupFullAppModalCounts (pcdLeader, pCD);
793     }
794
795
796     /*
797      * Delete this transient from its parent's list of transient windows.
798      */
799
800     pcdPrev = pCD->transientLeader->transientChildren;
801     if(pcdPrev)
802     {
803         if (pcdPrev == pCD)
804         {
805             pCD->transientLeader->transientChildren = pCD->transientSiblings;
806         }
807         else
808         {
809             while (pcdPrev && (pcdPrev->transientSiblings != pCD))
810             {
811                 pcdPrev = pcdPrev->transientSiblings;
812             }
813             if (pcdPrev)
814               pcdPrev->transientSiblings = pCD->transientSiblings;
815         }
816     }
817
818 } /* END OF FUNCTION DeleteTransient */
819
820 \f
821 /*************************************<->*************************************
822  *
823  *  DeleteFullAppModalChildren (pcdLeader, pCD)
824  *
825  *
826  *  Description:
827  *  -----------
828  *  This function handles the clean-up of nested full application modal
829  *  windows. The deletion has to be handled carefully to keep a correct
830  *  fullModalCount on the transients that remain in the tree.
831  *
832  *  The algorithm is to traverse the transient children depth first and
833  *  fix up the tree's fullModalCount for each full application modal
834  *  window that's found. 
835  *
836  *  Inputs:
837  *  ------
838  *  pcdLeader   = pointer to client data of transient tree root.
839  *  pCD         = pointer to client data of transient subtree to delete.
840  *
841  *************************************<->***********************************/
842
843 void DeleteFullAppModalChildren (ClientData *pcdLeader, ClientData *pCD)
844 {
845
846     /* recursively do children first */
847     if (pCD->transientChildren)
848         DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
849
850     /* do fullAppModal fixup for this guy */
851     FixupFullAppModalCounts (pcdLeader, pCD);
852
853     /* do siblings of passed transient */
854     if (pCD->transientSiblings)
855         DeleteFullAppModalChildren (pcdLeader, pCD->transientSiblings);
856
857     
858 } /* END OF FUNCTION DeleteFullAppModalChildren */
859
860 \f
861 /*************************************<->*************************************
862  *
863  *  FixupFullAppModalCounts (pcdLeader, pcdDelete)
864  *
865  *
866  *  Description:
867  *  -----------
868  *  This function traverses the entire transient tree (pointed to by 
869  *  pcdLeader) and fixes up the fullModalCounts to reflect the removal 
870  *  of pcdDelete. 
871  *
872  *  The fix-up consists of decrementing the count
873  *  of the remaining full app modal windows in the tree iff the remaining
874  *  window's fullModalCount is greater than the fullModalCount of the 
875  *  transient being deleted.
876  *
877  *  Inputs:
878  *  ------
879  *  pcdLeader   = pointer to client data for head of transient tree.
880  *  pcdDelet    = pointer to client data of transient being deleted.
881  *
882  *************************************<->***********************************/
883
884 void
885 FixupFullAppModalCounts (ClientData *pcdLeader, ClientData *pcdDelete)
886
887 {
888
889     /* fixup children */
890     if (pcdLeader->transientChildren) 
891     {
892         FixupFullAppModalCounts (pcdLeader->transientChildren, pcdDelete);
893     }
894
895     /* 
896      * fixup leader: decrement the count if it is greater than
897      * the transient being deleted.
898      *
899      */
900     if (pcdLeader->fullModalCount > pcdDelete->fullModalCount)
901     {
902         UnMarkModalTransient (pcdLeader, 1, pcdDelete);
903     }
904
905     /* fixup siblings */
906     if (pcdLeader->transientSiblings) 
907     {
908         FixupFullAppModalCounts (pcdLeader->transientSiblings, pcdDelete);
909     }
910     
911 } /* END OF FUNCTION FixupFullAppModalCounts */
912
913
914 \f
915 /*************************************<->*************************************
916  *
917  *  UnMarkModalTransient (pcdModee, modalCount, pcdModal)
918  *
919  *
920  *  Description:
921  *  -----------
922  *  This function unmarks a transient window for application modal processing.
923  *  Original grabs are restored.
924  *
925  *  Inputs:
926  *  ------
927  *  pcdModee   = pointer to client data for transient to unmark
928  *  pcdModal   = pointer to client data for modal transient
929  *  modalCount = amount to decrement the client's modal count by
930  *
931  * 
932  *************************************<->***********************************/
933
934 void UnMarkModalTransient (ClientData *pcdModee, int modalCount, ClientData *pcdModal)
935 {
936     /* decrement application modal count */
937     if (pcdModal->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
938         pcdModee->fullModalCount -= modalCount;
939     else if (pcdModal->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
940         pcdModee->primaryModalCount -= modalCount;
941
942     /*
943      * Restore original button bindings/grabs if not modal anymore
944      */
945     if (!IS_APP_MODALIZED(pcdModee))
946     {
947         XUngrabButton (DISPLAY, AnyButton, AnyModifier, 
948             pcdModee->clientBaseWin);
949
950         SetupCButtonBindings (pcdModee->clientBaseWin, BUTTON_SPECS(pcdModee));
951
952         if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
953             (wmGD.keyboardFocus != pcdModee))
954         {
955             DoExplicitSelectGrab (pcdModee->clientBaseWin);
956         }
957     }
958 }
959
960 \f
961 /*************************************<->*************************************
962  *
963  *  PutTransientOnTop (pcd)
964  *
965  *
966  *  Description:
967  *  -----------
968  *  This function changes the transient window list to insure that the
969  *  specified transient window is on top of its siblings and its parent
970  *  is on top of its siblings, etc.  The sibling list is ordered such
971  *  that the first window in the list is on top of second window in the
972  *  list, etc.
973  *
974  *
975  *  Inputs:
976  *  ------
977  *  pcd = pointer to client data of a transient window
978  *
979  * 
980  *  Outputs:
981  *  -------
982  *  pcdLeader = (transientSiblings)
983  *
984  *  RETURN = True if the transient tree needs to be restacked
985  *
986  *************************************<->***********************************/
987
988 Boolean PutTransientOnTop (ClientData *pcd)
989 {
990     ClientData *pcdLeader;
991     ClientData *pcdPrev;
992     Boolean restack = False;
993
994
995     pcdLeader = pcd->transientLeader;
996     if (pcdLeader != NULL)
997     {
998         pcdPrev = pcdLeader->transientChildren;
999         if (pcdPrev != pcd)
1000         {
1001             while (pcdPrev->transientSiblings != pcd)
1002             {
1003                 pcdPrev = pcdPrev->transientSiblings;
1004             }
1005             pcdPrev->transientSiblings = pcd->transientSiblings;
1006             pcd->transientSiblings = pcdLeader->transientChildren;
1007             pcdLeader->transientChildren = pcd;
1008             restack = True;
1009         }
1010
1011         if (PutTransientOnTop (pcdLeader))
1012         {
1013             restack = True;
1014         }
1015 #ifdef WSM
1016         if (BumpPrimaryToBottom (pcdLeader))
1017         {
1018             restack = True;
1019         }
1020 #endif /* WSM */
1021     }
1022
1023     return (restack);
1024
1025 } /* END OF FUNCTION PutTransientOnTop */
1026
1027
1028 \f
1029 /*************************************<->*************************************
1030  *
1031  *  PutTransientBelowSiblings (pcd)
1032  *
1033  *
1034  *  Description:
1035  *  -----------
1036  *  This function changes the transient window list to insure that the
1037  *  specified transient window is below its sibling windows.
1038  *
1039  *
1040  *  Inputs:
1041  *  ------
1042  *  pcd = pointer to client data of a transient window
1043  *
1044  * 
1045  *  Outputs:
1046  *  -------
1047  *  pcdLeader = (transientSiblings)
1048  *
1049  *  RETURN = True if restacking has been done in the transient window tree.
1050  *
1051  *************************************<->***********************************/
1052
1053 Boolean PutTransientBelowSiblings (ClientData *pcd)
1054 {
1055     ClientData *pcdLeader;
1056     ClientData *pcdNext;
1057     Boolean restack = False;
1058
1059
1060     pcdLeader = pcd->transientLeader;
1061     if (pcdLeader)
1062     {
1063         if (pcd->transientSiblings || (pcdLeader->transientChildren != pcd))
1064         {
1065             restack = True;
1066             if (pcdLeader->transientChildren == pcd)
1067             {
1068                 pcdLeader->transientChildren = pcd->transientSiblings;
1069             }
1070
1071             pcdNext = pcdLeader->transientChildren;
1072             while (pcdNext->transientSiblings)
1073             {
1074                 if (pcdNext->transientSiblings == pcd)
1075                 {
1076                     pcdNext->transientSiblings = pcd->transientSiblings;
1077                 }
1078                 else
1079                 {
1080                     pcdNext = pcdNext->transientSiblings;
1081                 }
1082             }
1083             pcdNext->transientSiblings = pcd;
1084         }
1085         pcd->transientSiblings = NULL;
1086     }
1087
1088     return (restack);
1089
1090 } /* END OF FUNCTION PutTransientBelowSiblings */
1091
1092
1093 \f
1094 /*************************************<->*************************************
1095  *
1096  *  RestackTransients (pcd)
1097  *
1098  *
1099  *  Description:
1100  *  -----------
1101  *  This function restacks windows in a transient window tree.  Secondary
1102  *  (transient) windows are stacked on top of their associated primary
1103  *  windows and the first secondary window in the transientSiblings list
1104  *  is stacked on top of the second window in the list, etc.
1105  *  
1106  *
1107  *  Inputs:
1108  *  ------
1109  *  pcd = pointer to client data of a window in a transient tree
1110  *
1111  *************************************<->***********************************/
1112
1113 void RestackTransients (ClientData *pcd)
1114 {
1115     ClientData *pcdLeader;
1116     int count;
1117     static int size = 0;
1118     static Window *windows = NULL;
1119 #ifndef WSM
1120     Window *nextWindow;
1121 #endif /* WSM */
1122     XWindowChanges windowChanges;
1123     int i;
1124     int leaderIndex;
1125
1126     /*
1127      * Build a restacking list and do the restacking.
1128      */
1129
1130     pcdLeader = FindTransientTreeLeader (pcd);
1131     count = CountTransientChildren (pcdLeader);
1132
1133     /* No work to do if no transient children; count includes leader. */
1134     if (count < 2)
1135       return;
1136
1137     if (count > size)
1138     {
1139         /*
1140          * Expand the (static) windows buffer that is used in restacking.
1141          */
1142
1143         if (!(windows =
1144                 (Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
1145         {
1146             /* cannot get memory space */
1147             size = 0;
1148             return;
1149         }
1150         size = count + 5;
1151     }
1152
1153 #ifdef WSM
1154     MakeTransientFamilyStackingList (windows, pcdLeader);
1155 #else /* WSM */
1156     nextWindow = MakeTransientWindowList (windows, pcdLeader);
1157     *nextWindow = pcdLeader->clientFrameWin;
1158 #endif /* WSM */
1159
1160     /*
1161      *  Changes for CDExc19397.
1162      *  XRestackWindows may move pcdLeader; that messes up the
1163      *  global window stack.  Call XConfigureWindow() instead,
1164      *  and don't change location of pcdLeader.
1165      */
1166     for (leaderIndex = 0; leaderIndex < count; leaderIndex++)
1167     {
1168       if (windows[leaderIndex] == pcdLeader->clientFrameWin)
1169         break;
1170     }
1171     if (leaderIndex >= count) /* ? Couldn't find leader; should NOT happen. */
1172       leaderIndex = count - 1;
1173
1174     windowChanges.stack_mode = Above;
1175     for (i = leaderIndex; i > 0; i--)
1176     {
1177       windowChanges.sibling = windows[i];
1178       XConfigureWindow (DISPLAY, windows[i - 1],
1179                         CWSibling | CWStackMode, &windowChanges);
1180     }
1181
1182     windowChanges.stack_mode = Below;
1183     for (i = leaderIndex; i < count - 1; i++)
1184     {
1185       windowChanges.sibling = windows[i];
1186       XConfigureWindow (DISPLAY, windows[i + 1],
1187                         CWSibling | CWStackMode, &windowChanges);
1188     }
1189
1190 } /* END OF FUNCTION RestackTransients */
1191
1192
1193 \f
1194 /*************************************<->*************************************
1195  *
1196  *  RestackTransientsAtWindow (pcd)
1197  *
1198  *
1199  *  Description:
1200  *  -----------
1201  *  This function restacks windows in a transient window tree.  The
1202  *  "anchor point" in the stack for the transient window tree is the
1203  *  specified window.
1204  *  
1205  *
1206  *  Inputs:
1207  *  ------
1208  *  pcd = pointer to client data of a window in a transient tree
1209  *
1210  *************************************<->***********************************/
1211
1212 void RestackTransientsAtWindow (ClientData *pcd)
1213 {
1214     ClientData *pcdLeader;
1215     XWindowChanges windowChanges;
1216
1217     pcdLeader = FindTransientTreeLeader (pcd);
1218     if (pcdLeader && (pcdLeader != pcd))
1219     {
1220         windowChanges.sibling = pcd->clientFrameWin;
1221         windowChanges.stack_mode = Below;
1222         XConfigureWindow (DISPLAY, pcdLeader->clientFrameWin,
1223             CWSibling | CWStackMode, &windowChanges);
1224     }
1225
1226     RestackTransients (pcd);
1227
1228 } /* END OF FUNCTION RestackTransientsAtWindow */
1229
1230
1231 \f
1232 /*************************************<->*************************************
1233  *
1234  *  FindTransientTreeLeader (pcd)
1235  *
1236  *
1237  *  Description:
1238  *  -----------
1239  *  This function identifies the leader of the transient tree that
1240  *  contains the specified client.
1241  *  
1242  *
1243  *  Inputs:
1244  *  ------
1245  *  pcd = pointer to client data of a window in a transient tree.
1246  *
1247  *  Outputs:
1248  *  -------
1249  *  RETURN = pointer to the client data for the transient tree leader.
1250  *
1251  *************************************<->***********************************/
1252
1253 ClientData * FindTransientTreeLeader (ClientData *pcd)
1254
1255 {
1256
1257     /*
1258      * Find the head of the transient window tree.
1259      */
1260
1261     while (pcd->transientLeader)
1262     {
1263         pcd = pcd->transientLeader;
1264     }
1265
1266     return (pcd);
1267
1268 } /* END OF FUNCTION FindTransientTreeLeader */
1269
1270
1271 \f
1272 /*************************************<->*************************************
1273  *
1274  *  CountTransientChildren (pcd)
1275  *
1276  *
1277  *  Description:
1278  *  -----------
1279  *  This function returns a count of the number of children in the 
1280  *  transient window tree headed by the specified client window.
1281  *  
1282  *
1283  *  Inputs:
1284  *  ------
1285  *  pcd = pointer to client data of a window in a transient tree
1286  *
1287  *  Outputs:
1288  *  -------
1289  *  RETURN = count of transient windows in the transient window tree
1290  *
1291  *************************************<->***********************************/
1292
1293 int
1294 CountTransientChildren (ClientData *pcd)
1295
1296 {
1297     ClientData *pcdNext;
1298     int count = 1;
1299
1300
1301     pcdNext = pcd->transientChildren;
1302     while (pcdNext)
1303     {
1304         if (pcdNext->transientChildren)
1305         {
1306             count += CountTransientChildren (pcdNext);
1307         }
1308         else
1309         {
1310             count++;
1311         }
1312         pcdNext = pcdNext->transientSiblings;
1313     }
1314
1315     return (count);
1316
1317 } /* END OF FUNCTION CountTransientChildren */
1318
1319
1320 \f
1321 /*************************************<->*************************************
1322  *
1323  *  MakeTransientWindowList (windows, pcd)
1324  *
1325  *
1326  *  Description:
1327  *  -----------
1328  *  This function makes a transient window list of windows in the 
1329  *  transient window tree headed by the specified client.  This list is
1330  *  to be passed to XRestackWindows.
1331  *  
1332  *
1333  *  Inputs:
1334  *  ------
1335  *  windows = pointer to the windows list to be filled out
1336  *
1337  *  pcd = pointer to client data of a window in a transient tree
1338  *
1339  *  Outputs:
1340  *  -------
1341  *  RETURN = pointer to the next entry in the windows list
1342  *
1343  *************************************<->***********************************/
1344
1345 Window * MakeTransientWindowList (Window *windows, ClientData *pcd)
1346
1347 {
1348     ClientData *pcdNext;
1349
1350
1351     pcdNext = pcd->transientChildren;
1352     while (pcdNext)
1353     {
1354         if (pcdNext->transientChildren)
1355         {
1356             windows = MakeTransientWindowList (windows, pcdNext);
1357         }
1358         *windows = pcdNext->clientFrameWin;
1359         windows++;
1360         pcdNext = pcdNext->transientSiblings;
1361     }
1362
1363     return (windows);
1364
1365
1366 } /* END OF FUNCTION MakeTransientWindowList */
1367
1368
1369 \f
1370 /*************************************<->*************************************
1371  *
1372  *  FindTransientFocus (pcd)
1373  *
1374  *
1375  *  Description:
1376  *  -----------
1377  *  This function identifies a window in the transient tree that is headed
1378  *  by the specified client that can accept the keyboard input.  The
1379  *  effect of application modal windows is taken into account.
1380  *  
1381  *
1382  *  Inputs:
1383  *  ------
1384  *  pcd = pointer to client data of a window in a transient tree.
1385  *
1386  *  Outputs:
1387  *  -------
1388  *  RETURN = pointer to the client data for a window that can accept the
1389  *      keyboard input focus.
1390  *
1391  *************************************<->***********************************/
1392
1393 ClientData * FindTransientFocus (ClientData *pcd)
1394
1395 {
1396
1397     ClientData *pcdFocus;
1398
1399     /*
1400      * Find a window that does not have an application modal subordinate.
1401      * First, search descendents
1402      */
1403
1404     pcdFocus = pcd;
1405     while (pcdFocus->transientChildren && IS_APP_MODALIZED(pcdFocus))
1406     {
1407         pcdFocus = pcdFocus->transientChildren;
1408     }
1409
1410     /*
1411      * If (search of descendents FAILS) then search siblings.
1412      */
1413     
1414     if (IS_APP_MODALIZED(pcdFocus))
1415     {
1416         ClientData *pcdSibling;
1417
1418         pcdFocus = pcd;
1419         while (pcdFocus && IS_APP_MODALIZED(pcdFocus))
1420         {
1421             pcdSibling = pcdFocus;
1422             while (pcdSibling->transientSiblings && IS_APP_MODALIZED(pcdFocus))
1423             {
1424                 pcdSibling = pcdSibling->transientSiblings;
1425             }
1426             if (IS_APP_MODALIZED(pcdSibling))
1427             {
1428                 pcdFocus = pcdFocus->transientChildren;
1429             }
1430             else
1431             {
1432                 pcdFocus = pcdSibling;
1433                 break;
1434             }
1435         }
1436     }
1437
1438     return (pcdFocus ? pcdFocus : wmGD.keyboardFocus);
1439
1440 } /* END OF FUNCTION FindTransientFocus */
1441
1442
1443 \f
1444 /*************************************<->*************************************
1445  *
1446  *  FindTransientOnTop (pcd)
1447  *
1448  *
1449  *  Description:
1450  *  -----------
1451  *  This function identifies the top-most transient window in the
1452  *  transient window tree that contains the specified client.
1453  *  
1454  *
1455  *  Inputs:
1456  *  ------
1457  *  pcd = pointer to client data of a window in a transient tree.
1458  *
1459  *  Outputs:
1460  *  -------
1461  *  RETURN = pointer to the client data for the top-most transient window.
1462  *
1463  *************************************<->***********************************/
1464
1465 ClientData * FindTransientOnTop (ClientData *pcd)
1466
1467 {
1468
1469     /*
1470      * Find the head of the transient window tree.
1471      */
1472
1473     pcd = FindTransientTreeLeader (pcd);
1474 #ifdef WSM
1475     if (!(pcd->secondariesOnTop) &&
1476         (LeaderOnTop (pcd)))
1477     {
1478         ClientData *pcdSub;
1479
1480         if (LeaderOnTop (pcd))
1481         {
1482             /* The primary window is on top! */
1483             return (pcd);
1484         }
1485         else
1486         {
1487             pcdSub = FindSubLeaderToTop (pcd);
1488             if (pcdSub)
1489                 return (pcdSub);
1490         }
1491     }
1492 #endif /* WSM */
1493
1494
1495     /*
1496      * Find the top-most transient window (the window in the transient tree
1497      * that is highest in the window stack).
1498      */
1499
1500     while (pcd->transientChildren)
1501     {
1502         pcd = pcd->transientChildren;
1503     }
1504
1505     return (pcd);
1506
1507 } /* END OF FUNCTION FindTransientOnTop */
1508
1509
1510 \f
1511 /*************************************<->*************************************
1512  *
1513  *  StackWindow (pWS, pEntry, onTop, pStackEntry)
1514  *
1515  *
1516  *  Description:
1517  *  -----------
1518  *  This function stacks a window of a particular type (normal or icon)
1519  *  to the top or botton of the window stack on the screen.
1520  *  
1521  *
1522  *  Inputs:
1523  *  ------
1524  *  pWS = pointer to workspace data
1525  *
1526  *  pEntry = pointer to the client list entry for the window to be restacked.
1527  *
1528  *  onTop = if True then the window is to be restacked on top of the
1529  *      specified stack window (if the stack window is not specified then
1530  *      the entry is added to the top of the window stack)
1531  *      otherwise the window is stacked below the specified stack window
1532  *      (or at the bottom of the window stack if the stack window is not
1533  *      specified).
1534  *
1535  *  pStackEntry = pointer to a client list entry for a window in the window
1536  *      stack that is to be used as a reference in restacking.
1537  *
1538  *************************************<->***********************************/
1539
1540 void StackWindow (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
1541 {
1542     Window stackWindow;
1543     Boolean stackTransientTreeWindows = False;
1544     Window activeIconWindow;
1545     Window window;
1546     XWindowChanges changes;
1547     WmScreenData *pSD = pWS->pSD;
1548
1549
1550     if (pStackEntry)
1551     {
1552         if (pStackEntry->type == MINIMIZED_STATE)
1553         {
1554             stackWindow = ICON_FRAME_WIN(pStackEntry->pCD);
1555         }
1556         else
1557         {
1558             stackWindow = pStackEntry->pCD->clientFrameWin;
1559         }
1560     }
1561     else
1562     {
1563         stackWindow = (Window)0;
1564     }
1565
1566     if (pEntry->type == MINIMIZED_STATE)
1567     {
1568         window = ICON_FRAME_WIN(pEntry->pCD);
1569     }
1570     else
1571     {
1572         /*
1573          * Restack the transient tree if appropriate.
1574          */
1575
1576         if (pEntry->pCD->transientLeader || pEntry->pCD->transientChildren)
1577         {
1578             stackTransientTreeWindows = True;
1579
1580             window = (FindTransientOnTop (pEntry->pCD))->clientFrameWin;
1581         }
1582         else
1583         {
1584             window = pEntry->pCD->clientFrameWin;
1585         }
1586     }
1587
1588
1589     /*
1590      * The active icon text label must be restacked along with the associated
1591      * icon.
1592      */
1593
1594     if ((pEntry->type == MINIMIZED_STATE) &&
1595         (pEntry->pCD == wmGD.keyboardFocus) &&
1596         (ICON_DECORATION(pEntry->pCD) & ICON_ACTIVE_LABEL_PART) &&
1597         (ACTIVE_ICON_TEXT_WIN))
1598     {
1599         activeIconWindow = ACTIVE_ICON_TEXT_WIN;
1600     }
1601     else
1602     {
1603         activeIconWindow = (Window)0;
1604     }
1605
1606     if (onTop)
1607     {
1608         if ((stackWindow == 0) && (pSD->clientList))
1609         {
1610             if (pSD->clientList->type == MINIMIZED_STATE)
1611             {
1612                 stackWindow = ICON_FRAME_WIN(pSD->clientList->pCD);
1613             }
1614             else
1615             {
1616                 if (pSD->clientList->pCD->transientChildren)
1617                 {
1618                     stackWindow =
1619                      (FindTransientOnTop(pSD->clientList->pCD))->clientFrameWin;
1620                 }
1621                 else
1622                 {
1623                     stackWindow = pSD->clientList->pCD->clientFrameWin;
1624                 }
1625             }
1626         }
1627
1628         if (activeIconWindow)
1629         {
1630             changes.sibling = stackWindow;
1631             changes.stack_mode = Above;
1632             XConfigureWindow (DISPLAY, activeIconWindow,
1633                 (CWSibling | CWStackMode), &changes);
1634             changes.sibling = activeIconWindow;
1635             changes.stack_mode = Below;
1636             XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1637                 &changes);
1638         }
1639         else
1640         {
1641             changes.sibling = stackWindow;
1642             changes.stack_mode = Above;
1643             XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1644                 &changes);
1645             if (stackTransientTreeWindows)
1646             {
1647                 /* make sure that the leader is in the correct spot */
1648                 changes.sibling = window;
1649                 changes.stack_mode = Below;
1650                 XConfigureWindow (DISPLAY, pEntry->pCD->clientFrameWin,
1651                                   (CWSibling | CWStackMode), &changes);
1652                 RestackTransients (pEntry->pCD);
1653             }
1654         }
1655     }
1656     else
1657     {
1658 #ifdef WSM
1659         /*
1660          * Adjust stack entry window if we're stacking below a
1661          * transient tree.
1662          */
1663         if (pStackEntry && pStackEntry->pCD->transientChildren)
1664         {
1665             stackWindow = LowestWindowInTransientFamily (pStackEntry->pCD);
1666         }
1667
1668 #endif /* WSM */
1669         if (stackWindow == 0)
1670         {
1671             if (pSD->lastClient->type == MINIMIZED_STATE)
1672             {
1673                 stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
1674             }
1675             else
1676             {
1677 #ifdef WSM
1678                 if (pSD->lastClient->pCD->transientChildren)
1679                 {
1680                     stackWindow = 
1681                         LowestWindowInTransientFamily (pSD->lastClient->pCD);
1682                 }
1683                 else
1684 #endif /* WSM */
1685                 stackWindow = pSD->lastClient->pCD->clientFrameWin;
1686             }
1687         }
1688
1689         if (activeIconWindow)
1690         {
1691             changes.sibling = stackWindow;
1692             changes.stack_mode = Below;
1693             XConfigureWindow (DISPLAY, activeIconWindow,
1694                               (CWSibling | CWStackMode), &changes);
1695             changes.sibling = activeIconWindow;
1696             changes.stack_mode = Below;
1697             XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1698                               &changes);
1699         }
1700         else
1701         {
1702             changes.sibling = stackWindow;
1703             changes.stack_mode = Below;
1704             XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1705                               &changes);
1706             if (stackTransientTreeWindows)
1707             {
1708                 /* make sure that the leader is in the correct spot */
1709                 changes.sibling = window;
1710                 changes.stack_mode = Below;
1711                 XConfigureWindow (DISPLAY, pEntry->pCD->clientFrameWin,
1712                                   (CWSibling | CWStackMode), &changes);
1713                 RestackTransients (pEntry->pCD);
1714             }
1715         }
1716     }
1717
1718 } /* END OF FUNCTION StackWindow */
1719
1720
1721 \f
1722 /*************************************<->*************************************
1723  *
1724  *  StackTransientWindow (pcd)
1725  *
1726  *
1727  *  Description:
1728  *  -----------
1729  *  This function stacks a transient window within its transient window
1730  *  tree on the screen.  The transient window tree should indicate the
1731  *  intended stacking position.
1732  *  
1733  *
1734  *  Inputs:
1735  *  ------
1736  *  pcd = pointer to client data of a window in a transient tree
1737  *
1738  *************************************<->***********************************/
1739
1740 void StackTransientWindow (ClientData *pcd)
1741 {
1742     XWindowChanges changes;
1743     ClientData *pcdPrev;
1744
1745
1746     if (pcd->transientLeader->transientChildren == pcd)
1747     {
1748         if (pcd->transientSiblings)
1749         {
1750             changes.sibling = pcd->transientSiblings->clientFrameWin;
1751         }
1752         else
1753         {
1754             changes.sibling = pcd->transientLeader->clientFrameWin;
1755         }
1756         changes.stack_mode = Above;
1757     }
1758     else
1759     {
1760         pcdPrev = pcd->transientLeader;
1761         while (pcdPrev->transientSiblings != pcd)
1762         {
1763             pcdPrev = pcdPrev->transientSiblings;
1764         }
1765         changes.sibling = pcdPrev->clientFrameWin;
1766         changes.stack_mode = Below;
1767     }
1768
1769     XConfigureWindow (DISPLAY, pcd->clientFrameWin, (CWSibling | CWStackMode),
1770         &changes);
1771
1772
1773 } /* END OF FUNCTION StackTransientWindow */
1774
1775
1776 \f
1777 /*************************************<->*************************************
1778  *
1779  *  CheckIfClientObscuring (pcdTop, pcd)
1780  *
1781  *
1782  *  Description:
1783  *  -----------
1784  *  This function determines whether a window or a transient window tree
1785  *  is obscuring (at least partially) a window or a transient window tree
1786  *  that is below it in the window stack.
1787  *  
1788  *
1789  *  Inputs:
1790  *  ------
1791  *  pcdTop = pointer to client data for a window (it may be the leader of
1792  *      a transient tree; this window is the higher in the window stack
1793  *      than the window it is be checked against.
1794  *
1795  *  pcd = pointer to client data for a window (it may be the leader of
1796  *      a transient tree.
1797  *
1798  *
1799  *  Outputs:
1800  *  -------
1801  *  RETURN = True if the top window(s) overlap the lower window(s)
1802  *
1803  *************************************<->***********************************/
1804
1805 Boolean CheckIfClientObscuring (ClientData *pcdTop, ClientData *pcd)
1806 {
1807     Boolean obscuring = False;
1808     ClientData *pcdNext;
1809
1810
1811     /*
1812      * Check only if the top window is visible onscreen.
1813      */
1814
1815     if (pcdTop->transientChildren && (pcdTop->clientState != MINIMIZED_STATE))
1816     {
1817         pcdNext = pcdTop->transientChildren;
1818         while (pcdNext && !obscuring)
1819         {
1820             obscuring = CheckIfClientObscuring (pcdNext, pcd);
1821             pcdNext = pcdNext->transientSiblings;
1822         }
1823     }
1824
1825     if (!obscuring && pcd->transientChildren &&
1826         (pcd->clientState != MINIMIZED_STATE))
1827     {
1828         pcdNext = pcd->transientChildren;
1829         while (pcdNext && !obscuring)
1830         {
1831             obscuring = CheckIfClientObscuring (pcdTop, pcdNext);
1832             pcdNext = pcdNext->transientSiblings;
1833         }
1834     }
1835
1836     if (!obscuring)
1837     {
1838         obscuring = CheckIfObscuring (pcdTop, pcd);
1839     }
1840
1841     return (obscuring);
1842
1843 } /* END OF FUNCTION CheckIfClientObscuring */
1844
1845
1846 \f
1847 /*************************************<->*************************************
1848  *
1849  *  CheckIfObscuring (pcdA, pcdB)
1850  *
1851  *
1852  *  Description:
1853  *  -----------
1854  *  This function determines whether a window (not a transient tree)
1855  *  is obscuring (at least partially) a window (not a transient tree)
1856  *  that is below it in the window stack.
1857  *  
1858  *
1859  *  Inputs:
1860  *  ------
1861  *  pcdA = pointer to client data for a window; this window is higher in
1862  *      the window stack than the window it is be checked against.
1863  *
1864  *  pcdB = pointer to client data for a window.
1865  *
1866  *
1867  *  Outputs:
1868  *  -------
1869  *  RETURN = True if the top window overlaps the lower window
1870  *
1871  *************************************<->***********************************/
1872
1873 Boolean CheckIfObscuring (ClientData *pcdA, ClientData *pcdB)
1874 {
1875     Boolean obscuring = False;
1876     int aX1;
1877     int aX2;
1878     int aY1;
1879     int aY2;
1880     int bX1;
1881     int bX2;
1882     int bY1;
1883     int bY2;
1884
1885 #ifdef WSM
1886     /*
1887      * For workspace stuff: if either is unseen, then neither
1888      * is obscured.
1889      */
1890     if ((pcdA->clientState & UNSEEN_STATE) ||
1891         (pcdB->clientState & UNSEEN_STATE))
1892     {
1893         return (False);
1894     }
1895 #endif /* WSM */
1896
1897     if (pcdA->clientState == NORMAL_STATE)
1898     {
1899         aX1 = pcdA->clientX - pcdA->clientOffset.x;
1900         aY1 = pcdA->clientY - pcdA->clientOffset.y;
1901         aX2 = aX1 + pcdA->clientWidth + (2 * pcdA->clientOffset.x) - 1;
1902         aY2 = aY1 + pcdA->clientHeight + pcdA->clientOffset.y +
1903               pcdA->clientOffset.x - 1;
1904     }
1905     else if (pcdA->clientState == MINIMIZED_STATE)
1906     {
1907         aX1 = ICON_X(pcdA);
1908         aY1 = ICON_Y(pcdA);
1909         aX2 = aX1 + ICON_WIDTH(pcdA) - 1; 
1910         aY2 = aY1 + ICON_HEIGHT(pcdA) - 1;
1911     }
1912     else /* (pcdA->clientState == MAXIMIZED_STATE) */
1913     {
1914         aX1 = pcdA->maxX - pcdA->clientOffset.x;
1915         aY1 = pcdA->maxY - pcdA->clientOffset.y;
1916         aX2 = aX1 + pcdA->maxWidth + (2 * pcdA->clientOffset.x) - 1;
1917         aY2 = aY1 + pcdA->maxHeight + pcdA->clientOffset.y +
1918               pcdA->clientOffset.x - 1;
1919     }
1920
1921     if (pcdB->clientState == NORMAL_STATE)
1922     {
1923         bX1 = pcdB->clientX - pcdB->clientOffset.x;
1924         bY1 = pcdB->clientY - pcdB->clientOffset.y;
1925         bX2 = bX1 + pcdB->clientWidth + (2 * pcdB->clientOffset.x) - 1;
1926         bY2 = bY1 + pcdB->clientHeight + pcdB->clientOffset.y +
1927               pcdB->clientOffset.x - 1;
1928     }
1929     else if (pcdB->clientState == MINIMIZED_STATE)
1930     {
1931         bX1 = ICON_X(pcdB);
1932         bY1 = ICON_Y(pcdB);
1933         bX2 = bX1 + ICON_WIDTH(pcdB) - 1; 
1934         bY2 = bY1 + ICON_HEIGHT(pcdB) - 1;
1935     }
1936     else /* (pcdB->clientState == MAXIMIZED_STATE) */
1937     {
1938         bX1 = pcdB->maxX - pcdB->clientOffset.x;
1939         bY1 = pcdB->maxY - pcdB->clientOffset.y;
1940         bX2 = bX1 + pcdB->maxWidth + (2 * pcdB->clientOffset.x) - 1;
1941         bY2 = bY1 + pcdB->maxHeight + pcdB->clientOffset.y +
1942               pcdB->clientOffset.x - 1;
1943     }
1944
1945     /*
1946      * Check if there is overlap in both dimensions.
1947      */
1948
1949     if (((aX1 >= bX1) && (aX1 <= bX2)) || ((aX2 >= bX1) && (aX2 <= bX2)) ||
1950         ((bX1 >= aX1) && (bX1 <= aX2)) || ((bX2 >= aX1) && (bX2 <= aX2)))
1951     {
1952         if (((aY1 >= bY1) && (aY1 <= bY2)) || ((aY2 >= bY1) && (aY2 <= bY2)) ||
1953             ((bY1 >= aY1) && (bY1 <= aY2)) || ((bY2 >= aY1) && (bY2 <= aY2)))
1954         {
1955             obscuring = True;
1956         }
1957     }
1958
1959     return (obscuring);
1960
1961
1962 } /* END OF FUNCTION CheckIfObscuring */
1963
1964
1965 \f
1966 /*************************************<->*************************************
1967  *
1968  *  CheckIfClientObscuredByAny (pcd)
1969  *
1970  *
1971  *  Description:
1972  *  -----------
1973  *  This function determines whether a window or a transient window tree
1974  *  is obscured (at least partially) by any other window.
1975  *  
1976  *
1977  *  Inputs:
1978  *  ------
1979  *  pcd = pointer to client data for a window (it may be the leader of
1980  *      a transient tree.
1981  *
1982  *
1983  *  Outputs:
1984  *  -------
1985  *  RETURN = True if the window(s) are overlapped.
1986  *
1987  *************************************<->***********************************/
1988
1989 Boolean CheckIfClientObscuredByAny (ClientData *pcd)
1990 {
1991     Boolean obscured = False;
1992     ClientListEntry *pListEntry;
1993
1994
1995     pListEntry = ACTIVE_PSD->clientList;
1996     while (pListEntry && !obscured)
1997     {
1998         if (pListEntry->pCD == pcd)
1999         {
2000             if (((pListEntry->type == MINIMIZED_STATE) &&
2001                  (pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
2002                 ((pListEntry->type != MINIMIZED_STATE) &&
2003                  (pListEntry->pCD->clientState != MINIMIZED_STATE)))
2004             {
2005                 pListEntry = NULL;
2006             }
2007         }
2008         else if (((pListEntry->type == MINIMIZED_STATE) &&
2009                    (pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
2010                  ((pListEntry->type != MINIMIZED_STATE) &&
2011                   (pListEntry->pCD->clientState != MINIMIZED_STATE)))
2012         {
2013             /*
2014              * The window for the entry is visible on screen.  See if it
2015              * obscures the indicated window.
2016              */
2017
2018             obscured = CheckIfClientObscuring (pListEntry->pCD, pcd);
2019         }
2020
2021         if (pListEntry)
2022         {
2023             pListEntry = pListEntry->nextSibling;
2024         }
2025     }
2026
2027     return (obscured);
2028
2029 } /* END OF FUNCTION CheckIfClientObscuredByAny */
2030
2031
2032 \f
2033 /*************************************<->*************************************
2034  *
2035  *  CheckIfClientObscuringAny (pcd)
2036  *
2037  *
2038  *  Description:
2039  *  -----------
2040  *  This function determines whether a window or a transient window tree
2041  *  is obscuring another window.
2042  *  
2043  *
2044  *  Inputs:
2045  *  ------
2046  *  pcd = pointer to client data for a window (it may be the leader of
2047  *      a transient tree.
2048  *
2049  *
2050  *  Outputs:
2051  *  -------
2052  *  RETURN = True if the window(s) overlaps anther window.
2053  *
2054  *************************************<->***********************************/
2055
2056 Boolean CheckIfClientObscuringAny (ClientData *pcd)
2057 {
2058     Boolean obscuring = False;
2059     ClientListEntry *pListEntry;
2060
2061
2062     pListEntry = (pcd->clientState == MINIMIZED_STATE) ?
2063                                         &pcd->iconEntry : &pcd->clientEntry;
2064     while (pListEntry && !obscuring)
2065     {
2066         if ((pListEntry->pCD != pcd) &&
2067             (((pListEntry->type == MINIMIZED_STATE) &&
2068               (pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
2069              ((pListEntry->type != MINIMIZED_STATE) &&
2070               (pListEntry->pCD->clientState != MINIMIZED_STATE))))
2071         {
2072             obscuring = CheckIfClientObscuring (pcd, pListEntry->pCD);
2073         }
2074
2075         pListEntry = pListEntry->nextSibling;
2076     }
2077
2078     return (obscuring);
2079
2080 } /* END OF FUNCTION CheckIfClientObscuringAny */
2081
2082
2083 \f
2084 /*************************************<->*************************************
2085  *
2086  *  SetupSystemModalState (pCD)
2087  *
2088  *
2089  *  Description:
2090  *  -----------
2091  *  This function prepares for mapping a system modal window.  An input
2092  *  screen window is mapped below the system modal window to prevent input
2093  *  to the windows not related to the system modal window.
2094  *  
2095  *
2096  *  Inputs:
2097  *  ------
2098  *  pCD = pointer to client data for the system modal window; if NULL the
2099  *      system modal window is a special window manager dialog box
2100  *
2101  *
2102  *  Outputs:
2103  *  -------
2104  *  wmGD = changes to system modal state data
2105  *
2106  *************************************<->***********************************/
2107
2108 void SetupSystemModalState (ClientData *pCD)
2109 {
2110     XWindowChanges windowChanges;
2111     unsigned int   width, height;
2112     unsigned int   x_hot, y_hot;
2113     unsigned char *bits;
2114     unsigned char *mask_bits;
2115     WmScreenData *pSD;
2116     int scr;
2117
2118     /*
2119      * If we've got a menu active, then unpost it first
2120      * so that grabs from the menu don't interfere with
2121      * the system modal dialog. We want to avoid lock-ups.
2122      */
2123     if (wmGD.menuActive != NULL)
2124     {
2125         UnpostMenu (wmGD.menuActive);
2126         XSync (DISPLAY, False);
2127     }
2128
2129     /*
2130      * Try to grab the pointer and keyboard. If either
2131      * fails because event processing is frozen by another grab, then 
2132      * don't do system modal for fear of leaving the system unusable.
2133      */
2134     if (XGrabPointer(DISPLAY, 
2135                      ROOT_FOR_CLIENT(pCD),
2136                      FALSE,                     /* owner_events */
2137                      (unsigned int) 0,          /* event mask */
2138                      GrabModeAsync,             /* pointer_mode */
2139                      GrabModeAsync,             /* keyboard_mode */
2140                      None,                      /* confine_to window */
2141                      None,                      /* cursor */
2142                      CurrentTime) == GrabFrozen)
2143     {   
2144         return;
2145     }
2146     else
2147     {
2148         XUngrabPointer (DISPLAY, CurrentTime);
2149     }
2150
2151     if (XGrabKeyboard(DISPLAY, 
2152                      ROOT_FOR_CLIENT(pCD),
2153                      FALSE,                     /* owner_events */
2154                      GrabModeAsync,             /* pointer_mode */
2155                      GrabModeAsync,             /* keyboard_mode */
2156                      CurrentTime) == GrabFrozen)
2157     {   
2158         return;
2159     }
2160     else
2161     {
2162         XUngrabKeyboard (DISPLAY, CurrentTime);
2163     }
2164
2165 #ifdef LARGECURSORS
2166
2167     if (wmGD.useLargeCursors)
2168     {
2169         width = noenter32_width;
2170         height = noenter32_height;
2171         x_hot = noenter32_x_hot;
2172         y_hot = noenter32_y_hot;
2173         bits = noenter32_bits;
2174         mask_bits = noenter32m_bits;
2175     }
2176     else
2177
2178 #endif /* LARGECURSORS */
2179
2180     {
2181         width = noenter16_width;
2182         height = noenter16_height;
2183         x_hot = noenter16_x_hot;
2184         y_hot = noenter16_y_hot;
2185         bits = noenter16_bits;
2186         mask_bits = noenter16m_bits;
2187     }
2188
2189     for (scr=0; scr<wmGD.numScreens; scr++)
2190     {
2191         pSD = &(wmGD.Screens[scr]);
2192         
2193         /*
2194          * Make the system modal input screen window if necessary.
2195          */
2196         
2197         if (pSD->managed && pSD->inputScreenWindow == 0)
2198         {
2199             XSetWindowAttributes windowAttributes;
2200             Pixmap               pixmap;
2201             Pixmap               maskPixmap;
2202             XColor               xcolors[2];
2203             
2204             windowAttributes.event_mask = ButtonPressMask;
2205             if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2206             {
2207                 windowAttributes.event_mask |= EnterWindowMask;
2208             }
2209             windowAttributes.override_redirect = True;
2210             
2211             pixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow, 
2212                                             (char *)bits, width, height);
2213             
2214             maskPixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow, 
2215                                                 (char *)mask_bits, width, height);
2216             
2217             xcolors[0].pixel = BlackPixel (DISPLAY, pSD->screen);
2218             xcolors[1].pixel = WhitePixel (DISPLAY, pSD->screen);
2219             XQueryColors (DISPLAY, DefaultColormap (DISPLAY, pSD->screen), 
2220                           xcolors, 2);
2221             windowAttributes.cursor =
2222                 XCreatePixmapCursor (DISPLAY, pixmap, maskPixmap,
2223                                      &(xcolors[0]), &(xcolors[1]), 
2224                                      x_hot, y_hot);
2225             XFreePixmap (DISPLAY, pixmap);
2226             XFreePixmap (DISPLAY, maskPixmap);
2227             
2228             pSD->inputScreenWindow =
2229                 XCreateWindow (DISPLAY, pSD->rootWindow, 0, 0,
2230                                DisplayWidth (DISPLAY, pSD->screen),
2231                                DisplayHeight (DISPLAY, pSD->screen),
2232                                0,
2233                                0,
2234                                InputOnly,
2235                                CopyFromParent,
2236                                CWEventMask | CWOverrideRedirect | CWCursor,
2237                                &windowAttributes);
2238         }
2239         if (pSD->managed && pSD != ACTIVE_PSD)
2240         {
2241             XMapRaised (DISPLAY, pSD->inputScreenWindow);
2242         }
2243     }
2244     
2245     if (pCD)
2246     {
2247         wmGD.systemModalWindow = pCD->clientFrameWin;
2248     }
2249     else
2250     {
2251         /*
2252          * ELSE: the system modal window is a special window manager dialog
2253          * box and wmGD.systemModalWindow is set prior to the call to 
2254          * SetupSystemModalState.  Set the focus to the special window manager
2255          * dialog box.
2256          */
2257         
2258         SetKeyboardFocus (NULL, REFRESH_LAST_FOCUS);
2259         XSetInputFocus (DISPLAY, wmGD.systemModalWindow, RevertToPointerRoot,
2260                         CurrentTime);
2261     }
2262     
2263     
2264     /*
2265      * Map the system modal input screen window below the system modal
2266      * window.
2267      */
2268     
2269     windowChanges.sibling = wmGD.systemModalWindow;
2270     windowChanges.stack_mode = Below;
2271     XConfigureWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow, 
2272                       CWSibling | CWStackMode, &windowChanges);
2273     
2274     XMapWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow);
2275     
2276     
2277     /*
2278      * Setup the system modal global data.
2279      */
2280     
2281     wmGD.systemModalActive = True;
2282     wmGD.systemModalClient = pCD;
2283     
2284     
2285 } /* END OF FUNCTION SetupSystemModalState */
2286
2287
2288 \f
2289 /*************************************<->*************************************
2290  *
2291  *  UndoSystemModalState ()
2292  *
2293  *
2294  *  Description:
2295  *  -----------
2296  *  This function cleans up after a system modal window goes away.
2297  *  
2298  *
2299  *  Inputs:
2300  *  ------
2301  *  wmGD = (system modal state data)
2302  *
2303  *
2304  *  Outputs:
2305  *  -------
2306  *  wmGD = changes to system modal state data
2307  *
2308  *************************************<->***********************************/
2309
2310 void UndoSystemModalState (void)
2311 {
2312     int scr;
2313     
2314     /*
2315      * Unmap the system modal input screen window.
2316      */
2317
2318     for (scr = 0; scr < wmGD.numScreens; scr++)
2319     {
2320         if(wmGD.Screens[scr].managed)
2321         {
2322             XUnmapWindow (DISPLAY, wmGD.Screens[scr].inputScreenWindow);
2323         }
2324     }
2325
2326     /*
2327      * Reset the focus if a window manager system modal dialog box was
2328      * being displayed.
2329      */
2330
2331     if (!wmGD.systemModalClient)
2332     {
2333         AutoResetKeyFocus (NULL, GetTimestamp());
2334     }
2335
2336
2337     /*
2338      * Reset the system modal global data.
2339      */
2340
2341     wmGD.systemModalActive = False;
2342     wmGD.systemModalClient = NULL;
2343     wmGD.systemModalWindow = 0;
2344
2345 } /* END OF FUNCTION UndoSystemModalState */
2346
2347
2348 \f
2349 /*************************************<->*************************************
2350  *
2351  *  FindClientNameMatch (pStartingEntry, toNext, clientName, types)
2352  *
2353  *
2354  *  Description:
2355  *  -----------
2356  *  This function searches for a client that has a particular name or class.
2357  *  A match will be indicated if the client with the name or class also
2358  *  is in a particular state.
2359  *  
2360  *
2361  *  Inputs:
2362  *  ------
2363  *  pEntry = pointer to the client list entry where the search is
2364  *      to begin.
2365  *
2366  *  toNext = if True then search client list from first to last; otherwise
2367  *      search the client list last to first.
2368  *
2369  *  clientName = string that indicates a client name or class.
2370  *
2371  *  type = types of objects (icon, window, ...) that are to be matched.
2372  *
2373  *
2374  *  Outputs:
2375  *  -------
2376  *  RETURN = pointer to client list entry for matched client.
2377  *
2378  *************************************<->***********************************/
2379 ClientListEntry * FindClientNameMatch (ClientListEntry *pEntry,
2380                                        Boolean toNext,
2381                                        String clientName,
2382                                        unsigned long types)
2383
2384 {
2385     Boolean foundMatch = False;
2386     Boolean checkEntry;
2387     ClientData *pCD;
2388
2389
2390     while (!foundMatch && pEntry)
2391     {
2392         checkEntry = False;
2393         pCD = pEntry->pCD;
2394         if (pEntry->type == MINIMIZED_STATE)
2395         {
2396             if ((pCD->clientState == MINIMIZED_STATE) &&
2397                 (types & F_GROUP_ICON))
2398             {
2399                 checkEntry = True;
2400             }
2401         }
2402         else
2403         {
2404             if ((pCD->clientState != MINIMIZED_STATE) &&
2405                 (types & F_GROUP_WINDOW))
2406             {
2407                 checkEntry = True;
2408             }
2409         }
2410
2411         if (checkEntry &&
2412             ((pCD->clientName && (strcmp (clientName,pCD->clientName) == 0)) ||
2413              (pCD->clientClass && (strcmp (clientName,pCD->clientClass) == 0))))
2414         {
2415             foundMatch = True;
2416         }
2417         else
2418         {
2419             pEntry = (toNext) ? pEntry->nextSibling : pEntry->prevSibling;
2420         }
2421     }
2422
2423     return (pEntry);
2424
2425 } /* END OF FUNCTION FindClientNameMatch */
2426 #ifdef WSM
2427 \f
2428 /*************************************<->*************************************
2429  *
2430  *  BumpPrimaryToTop (pcdLeader)
2431  *
2432  *
2433  *  Description:
2434  *  -----------
2435  *  This function moves the primary window to the "top" of the transient
2436  *  tree. 
2437  *
2438  *  Inputs:
2439  *  ------
2440  *  pcdLeader   = pointer to client data of transient tree root.
2441  *
2442  *  Returns: True if stacking order of leader window changed.
2443  *           False if not stacking change.
2444  *
2445  *  Comments:
2446  *  ---------
2447  *  This affects only the clientData structures. There is no immediate
2448  *  effect on the actual stacking order on the display. That is done
2449  *  by StackWindow and/or RestackTransients.
2450  *
2451  *************************************<->***********************************/
2452
2453 Boolean BumpPrimaryToTop (ClientData *pcdLeader)
2454 {
2455     int count;
2456     Boolean rval;
2457
2458     count = CountTransientChildren (pcdLeader);
2459
2460     if (pcdLeader->primaryStackPosition != (count-1))
2461     {
2462         pcdLeader->primaryStackPosition = count - 1;
2463         rval = True;
2464     }
2465     else
2466     {
2467         rval = False;
2468     }
2469     return (rval);
2470 }
2471
2472 \f
2473 /*************************************<->*************************************
2474  *
2475  *  BumpPrimaryToBottom (pcdLeader)
2476  *
2477  *
2478  *  Description:
2479  *  -----------
2480  *  This function moves the primary window to the "bottom" of the transient
2481  *  tree. 
2482  *
2483  *  Inputs:
2484  *  ------
2485  *  pcdLeader   = pointer to client data of transient tree root.
2486  *
2487  *  Returns: True if stacking order of leader window changed.
2488  *           False if not stacking change.
2489  *
2490  *  Comments:
2491  *  ---------
2492  *  This affects only the clientData structures. There is no immediate
2493  *  effect on the actual stacking order on the display. That is done
2494  *  by StackWindow and/or RestackTransients.
2495  *
2496  *************************************<->***********************************/
2497
2498 Boolean BumpPrimaryToBottom (ClientData *pcdLeader)
2499 {
2500     Boolean rval;
2501
2502     if (pcdLeader->primaryStackPosition != 0)
2503     {
2504         pcdLeader->primaryStackPosition = 0;
2505         rval = True;
2506     }
2507     else
2508     {
2509         rval = False;
2510     }
2511
2512     return (rval);
2513 }
2514
2515 \f
2516 /*************************************<->*************************************
2517  *
2518  *  LowestWindowInTransientFamily (pcdLeader)
2519  *
2520  *
2521  *  Description:
2522  *  -----------
2523  *  This function returns the lowest stacked window in a transient
2524  *  tree family.
2525  *
2526  *  Inputs:
2527  *  ------
2528  *  pcdLeader = pointer to client data of leader of a transient tree
2529  *
2530  *  Returns:  id of lowest window in the transient tree for this family
2531  *
2532  *************************************<->***********************************/
2533
2534 Window
2535 LowestWindowInTransientFamily (ClientData *pcdLeader)
2536 {
2537     int count;
2538     static int size = 0;
2539     static Window *windows = NULL;
2540     Window wReturn = None;
2541
2542     /*
2543      * Build a window list 
2544      */
2545     count = CountTransientChildren (pcdLeader);
2546
2547     if (count > size)
2548     {
2549         /*
2550          * Expand the (static) windows buffer
2551          */
2552
2553         if (!(windows =
2554                 (Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
2555         {
2556             /* cannot get memory space */
2557             size = 0;
2558             return None;
2559         }
2560         size = count + 5;
2561     }
2562
2563     MakeTransientFamilyStackingList (windows, pcdLeader);
2564
2565     if (count > 0)
2566     {
2567         wReturn = windows[count-1];
2568     }
2569     else
2570     {
2571         wReturn = None;
2572     }
2573
2574     return (wReturn);
2575
2576 } /* END OF FUNCTION LowestWindowInTransientFamily */
2577
2578 \f
2579 /*************************************<->*************************************
2580  *
2581  *  FindSubLeaderToTop (pcd)
2582  *
2583  *
2584  *  Description:
2585  *  -----------
2586  *  This function identifies a candidate window to top within the 
2587  *  transient tree that is a local transient leader (the window has 
2588  *  transients hanging off of it, too). 
2589  *  
2590  *
2591  *  Inputs:
2592  *  ------
2593  *  pcd = pointer to client data of a transient leader window
2594  *
2595  *  Return:  ptr to client data for client that should be topped, or NULL
2596  *  
2597  *
2598  *  Comments:
2599  *  --------
2600  *
2601  *************************************<->***********************************/
2602
2603 ClientData *
2604 FindSubLeaderToTop (
2605         ClientData *pcd)
2606
2607 {
2608     ClientData *pcdRet = NULL;
2609     ClientData *pcdNext;
2610
2611     pcdNext = pcd->transientChildren;
2612     while (pcdNext && (!pcdRet))
2613     {
2614         if (pcdNext->transientChildren)
2615         {
2616             if (LeaderOnTop (pcdNext))
2617             {
2618                 pcdRet = pcdNext;
2619             }
2620             else
2621             {
2622                 pcdRet = FindSubLeaderToTop (pcdNext);
2623             }
2624         }
2625         pcdNext = pcdNext->transientSiblings;
2626     }
2627
2628     return (pcdRet);
2629 }
2630
2631 \f
2632 /*************************************<->*************************************
2633  *
2634  *  MakeTransientFamilyStackingList (windows, pcdLeader)
2635  *
2636  *
2637  *  Description:
2638  *  -----------
2639  *  This function makes a transient window list of windows in the 
2640  *  transient window tree headed by the specified client.  
2641  *  
2642  *
2643  *  Inputs:
2644  *  ------
2645  *  windows = pointer to the windows list to be filled out
2646  *
2647  *  pcdLeader = pointer to client data of a window in a transient tree
2648  *
2649  *  Outputs:
2650  *  -------
2651  *  The windows array is modified.
2652  *
2653  *  Comments:
2654  *  --------
2655  *  This function puts the transient leader window in the list in the 
2656  *  right place.
2657  *
2658  *************************************<->***********************************/
2659
2660 void
2661 MakeTransientFamilyStackingList (
2662         Window *windows, 
2663         ClientData *pcdLeader)
2664
2665 {
2666     ClientData *pcdSub;
2667     Window *nextWindow, wSave, wTemp, wTop;
2668     int count = CountTransientChildren (pcdLeader);
2669     register int i, j;
2670
2671     /*
2672      * Construct the transient stacking list according to
2673      * normal Motif rules.
2674      */
2675     nextWindow = MakeTransientWindowList (windows, pcdLeader);
2676
2677     if (!(pcdLeader->secondariesOnTop))
2678     {
2679         /*
2680          * If the leader window shouldn't be on the bottom , then 
2681          * adjust the stacking of the list.
2682          */
2683         if ((pcdLeader->primaryStackPosition > 0) &&
2684             (pcdLeader->primaryStackPosition < count))
2685         {
2686             for (i=0; i<pcdLeader->primaryStackPosition; i++)
2687             {
2688                 j = count - i - 1;
2689                 windows[j] = windows[j-1];
2690             }
2691             j = count - pcdLeader->primaryStackPosition - 1;
2692             windows[j] = pcdLeader->clientFrameWin;
2693         }
2694         else
2695         {
2696             /*
2697              * Put the leader at the bottom.
2698              */
2699             *nextWindow = pcdLeader->clientFrameWin;
2700
2701             /*
2702              * If one of the transients is also a local leader
2703              * and wants to be on top, then adjust the list.
2704              */
2705             pcdSub = FindSubLeaderToTop (pcdLeader);
2706             if (pcdSub && (pcdSub->clientFrameWin != None))
2707             {
2708                 /* insert this window at top */
2709                 wTop = wSave = pcdSub->clientFrameWin;
2710
2711                 /* shuffle the rest down */
2712                 for (i=0; i<count; i++)
2713                 {
2714                     wTemp = windows[i];
2715                     windows[i] = wSave;
2716                     wSave = wTemp;
2717
2718                     if (wTop == wSave)
2719                         break;
2720                 }
2721             }
2722         }
2723     }
2724     else
2725     {
2726         /*
2727          * Put the leader at the bottom.
2728          */
2729         *nextWindow = pcdLeader->clientFrameWin;
2730     }
2731
2732 } /* END OF FUNCTION MakeTransientFamilyStackingList */
2733
2734 \f
2735 /*************************************<->*************************************
2736  *
2737  *  NormalizeTransientTreeStacking (pcdLeader)
2738  *
2739  *
2740  *  Description:
2741  *  -----------
2742  *  This function traverses the transient tree and cleans up any 
2743  *  local primary windows that are above their respective secondary
2744  *  windows.
2745  *  
2746  *
2747  *  Inputs:
2748  *  ------
2749  *  pcdLeader = pointer to client data of a transient tree leader
2750  *
2751  *  Return:  True if any changes in stacking order were made
2752  *  
2753  *
2754  *  Comments:
2755  *  --------
2756  *  This only touches the data structures. 
2757  *
2758  *************************************<->***********************************/
2759
2760 Boolean
2761 NormalizeTransientTreeStacking (
2762         ClientData *pcdLeader)
2763
2764 {
2765     ClientData *pcdNext;
2766     Boolean bChanged = False;
2767
2768     pcdNext = pcdLeader->transientChildren;
2769     bChanged = BumpPrimaryToBottom (pcdLeader);
2770     while (pcdNext)
2771     {
2772         if (pcdNext->transientChildren)
2773         {
2774             bChanged |= BumpPrimaryToBottom (pcdNext);
2775
2776             bChanged |= NormalizeTransientTreeStacking (pcdNext);
2777         }
2778         pcdNext = pcdNext->transientSiblings;
2779     }
2780     return (bChanged);
2781 }
2782
2783 \f
2784 /*************************************<->*************************************
2785  *
2786  *  LeaderOnTop (pcdLeader)
2787  *
2788  *
2789  *  Description:
2790  *  -----------
2791  *  This function tests a leader of a transient (sub) tree to see if
2792  *  it should be on top of its transient windows. 
2793  *  
2794  *
2795  *  Inputs:
2796  *  ------
2797  *  pcdLeader = pointer to client data of a transient tree leader
2798  *
2799  *  Return:  True if this leader is on top of its transients
2800  *  
2801  *
2802  *  Comments:
2803  *  --------
2804  *
2805  *************************************<->***********************************/
2806
2807 Boolean
2808 LeaderOnTop (
2809         ClientData *pcdLeader)
2810
2811 {
2812     Boolean bOnTop = False;
2813     int count = CountTransientChildren (pcdLeader);
2814
2815     if ((pcdLeader->primaryStackPosition > 0) &&
2816         (pcdLeader->primaryStackPosition < count))
2817     {
2818         bOnTop = True;
2819     }
2820
2821     return (bOnTop);
2822 }
2823
2824 #endif /* WSM */