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