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