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