2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
24 * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
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.
43 #define MWM_NEED_NOENTER16
48 * include extern functions
50 #include "WmWinList.h"
53 #include "WmFunction.h"
54 #include "WmKeyFocus.h"
56 #include "WmResource.h"
57 #include "WmWinInfo.h"
58 #include "WmWrkspace.h"
68 /*************************************<->*************************************
70 * AddClientToList (pWS, pCD, onTop)
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.
85 * pCD = pointer to client data for the window to be added to the list
87 * pWS = pointer to workspace data
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.
96 * pWS = (clientList, lastClient)
98 *************************************<->***********************************/
100 void AddClientToList (WmWorkspaceData *pWS, ClientData *pCD, Boolean onTop)
102 Boolean belowSystemModal = False;
103 XWindowChanges windowChanges;
104 WmScreenData *pSD = pWS->pSD;
105 WsClientData *pWsc = GetWsClientData (pWS, pCD);
108 if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
111 * Set up the system modal input screen window just below the
112 * system modal window.
115 SetupSystemModalState (pCD);
117 if (!wmGD.systemModalActive || (wmGD.systemModalClient != pCD))
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
125 pCD->inputMode = MWM_INPUT_FULL_APPLICATION_MODAL;
128 else if (wmGD.systemModalActive &&
129 ((FindTransientTreeLeader (pCD))->inputMode !=
130 MWM_INPUT_SYSTEM_MODAL))
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.
138 windowChanges.sibling = pSD->inputScreenWindow;
139 windowChanges.stack_mode = Below;
140 XConfigureWindow (DISPLAY, pCD->clientFrameWin,
141 CWSibling | CWStackMode, &windowChanges);
142 belowSystemModal = True;
145 if (pCD->transientLeader)
147 AddTransient (pWS, pCD);
151 pCD->clientEntry.type = NORMAL_STATE;
152 pCD->clientEntry.pCD = pCD;
154 if (belowSystemModal && wmGD.systemModalClient)
156 AddEntryToList (pWS, &pCD->clientEntry, False /*below*/,
161 AddEntryToList (pWS, &pCD->clientEntry, True /*on top*/, NULL);
165 AddEntryToList (pWS, &pCD->clientEntry, False /*on bottom*/, NULL);
169 if (!pWsc->pIconBox && pWsc->iconFrameWin)
172 * Put the icon on the bottom of the stack.
175 if (pSD->lastClient->type == MINIMIZED_STATE)
179 pWsib = &pSD->lastClient->pCD->pWsList[0];
180 windowChanges.sibling = pWsib->iconFrameWin;
184 windowChanges.sibling = pSD->lastClient->pCD->clientFrameWin;
186 windowChanges.stack_mode = Below;
187 XConfigureWindow (DISPLAY, pWsc->iconFrameWin,
188 CWSibling | CWStackMode, &windowChanges);
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;
199 } /* END OF FUNCTION AddClientToList */
203 /*************************************<->*************************************
205 * AddEntryToList (pWS, pEntry, onTop, pStackEntry)
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.
217 * pWS = pointer to workspace data
218 * pEntry = pointer to a client list entry to be added to the client list
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).
226 * pStackEntry = pointer to a client list entry to be used as a reference
227 * in adding an entry to the client list.
231 * pWS = (clientList, lastClient)
233 *************************************<->***********************************/
235 void AddEntryToList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
237 WmScreenData *pSD = pWS->pSD;
243 if (pEntry != pStackEntry)
245 pEntry->nextSibling = pStackEntry;
246 pEntry->prevSibling = pStackEntry->prevSibling;
247 pStackEntry->prevSibling = pEntry;
248 if (pEntry->prevSibling)
250 pEntry->prevSibling->nextSibling = pEntry;
254 pSD->clientList = pEntry;
260 if (pSD->clientList != pEntry)
262 pEntry->nextSibling = pSD->clientList;
263 pEntry->prevSibling = NULL;
266 pSD->clientList->prevSibling = pEntry;
270 pSD->lastClient = pEntry;
272 pSD->clientList = pEntry;
280 if (pEntry != pStackEntry)
282 pEntry->nextSibling = pStackEntry->nextSibling;
283 pEntry->prevSibling = pStackEntry;
284 pStackEntry->nextSibling = pEntry;
285 if (pEntry->nextSibling)
287 pEntry->nextSibling->prevSibling = pEntry;
291 pSD->lastClient = pEntry;
297 if (pSD->lastClient != pEntry)
299 pEntry->nextSibling = NULL;
300 pEntry->prevSibling = pSD->lastClient;
303 pSD->lastClient->nextSibling = pEntry;
307 pSD->clientList = pEntry;
309 pSD->lastClient = pEntry;
314 } /* END OF FUNCTION AddEntryToList */
318 /*************************************<->*************************************
320 * MoveEntryInList (pWS, pEntry, onTop, pStackEntry)
325 * This function moves a client list entry in the client window list.
330 * pWS = pointer to workspace data
332 * pEntry = pointer to a client list entry to be moved in the client list
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).
340 * pStackEntry = pointer to a client list entry to be used as a reference
341 * in moving an entry in the client list.
345 * pWS = (clientList, lastClient)
347 *************************************<->***********************************/
349 void MoveEntryInList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
351 DeleteEntryFromList (pWS, pEntry);
352 AddEntryToList (pWS, pEntry, onTop, pStackEntry);
354 } /* END OF FUNCTION MoveEntryInList */
358 /*************************************<->*************************************
360 * DeleteEntryFromList (pWS, pListEntry)
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.
372 * pWS = pointer to workspace data
373 * listEntry = pointer to a client list entry
377 * pWS = (clientList, lastClient)
379 *************************************<->***********************************/
381 void DeleteEntryFromList (WmWorkspaceData *pWS, ClientListEntry *pListEntry)
384 if (pListEntry->prevSibling)
386 pListEntry->prevSibling->nextSibling = pListEntry->nextSibling;
390 pWS->pSD->clientList = pListEntry->nextSibling;
393 if (pListEntry->nextSibling)
395 pListEntry->nextSibling->prevSibling = pListEntry->prevSibling;
399 pWS->pSD->lastClient = pListEntry->prevSibling;
402 } /* END OF FUNCTION DeleteEntryFromList */
406 /*************************************<->*************************************
408 * DeleteClientFromList (pWS, pCD)
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.
420 * pCD = pointer to client data for the window to be added to the list
424 * pWS = (clientList, lastClient)
426 *************************************<->***********************************/
428 void DeleteClientFromList (WmWorkspaceData *pWS, ClientData *pCD)
430 WsClientData *pWsc = GetWsClientData (pWS, pCD);
431 WmScreenData *pSD = pWS->pSD;
433 if (pCD->transientLeader)
435 DeleteTransient (pCD);
440 * If this is a system modal window then clean up the system modal
444 if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
446 UndoSystemModalState ();
450 * Remove the client and icon entries from the window list.
453 if (!pWsc->pIconBox && pWsc->iconFrameWin)
455 if (pCD->iconEntry.prevSibling)
457 pCD->iconEntry.prevSibling->nextSibling =
458 pCD->iconEntry.nextSibling;
462 pSD->clientList = pCD->iconEntry.nextSibling;
464 if (pCD->iconEntry.nextSibling)
466 pCD->iconEntry.nextSibling->prevSibling =
467 pCD->iconEntry.prevSibling;
471 pSD->lastClient = pCD->iconEntry.prevSibling;
475 if (pCD->clientEntry.prevSibling)
477 pCD->clientEntry.prevSibling->nextSibling =
478 pCD->clientEntry.nextSibling;
482 pSD->clientList = pCD->clientEntry.nextSibling;
485 if (pCD->clientEntry.nextSibling)
487 pCD->clientEntry.nextSibling->prevSibling =
488 pCD->clientEntry.prevSibling;
492 pSD->lastClient = pCD->clientEntry.prevSibling;
496 } /* END OF FUNCTION DeleteClientFromList */
500 /*************************************<->*************************************
502 * AddTransient (pWS, pCD)
507 * This function adds the transient window to the lead window's list of
513 * pWS = pointer to workspace data
514 * pCD = pointer to client data of a transient window
519 * pCD->transientLeader = (transientChildren, modalCount)
521 *************************************<->***********************************/
523 void AddTransient (WmWorkspaceData *pWS, ClientData *pCD)
525 ClientData *pcdLeader = pCD->transientLeader;
526 ClientData *pcdTop = FindTransientTreeLeader (pCD);
527 Boolean restackTransients;
528 WmScreenData *pSD = pWS->pSD;
531 pCD->transientSiblings = pcdLeader->transientChildren;
532 pcdLeader->transientChildren = pCD;
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
544 restackTransients = PutTransientOnTop (pCD);
548 * Handle application modal transient windows
551 if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
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.
558 * (This is the old MWM_INPUT_APPLICATION_MODAL behavior.)
562 MarkModalTransient (pcdLeader, pCD);
563 pcdLeader = pcdLeader->transientLeader;
566 else if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
569 * If this is a full application modal window then increment
570 * the modal count for the rest of the transient tree.
573 MarkModalSubtree (pcdTop, pCD);
575 else if (pcdTop->fullModalCount)
578 * There is already a full application modal window in the tree
580 pcdLeader = pCD->transientLeader;
581 if ((pcdLeader->inputMode != MWM_INPUT_FULL_APPLICATION_MODAL) ||
582 (IS_APP_MODALIZED(pcdLeader)))
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.
591 pCD->fullModalCount = pcdLeader->fullModalCount;
597 * Do the actual restacking in the X window stack if necessary.
600 if ((pSD->clientList != &pcdTop->clientEntry) && !wmGD.systemModalActive)
602 F_Raise (NULL, pCD, NULL);
604 else if (restackTransients)
606 RestackTransientsAtWindow (pCD);
608 else if (pCD != FindTransientOnTop (pcdTop))
610 StackTransientWindow (pCD);
614 } /* END OF FUNCTION AddTransient */
618 /*************************************<->*************************************
620 * MarkModalSubtree (pcdTree, pcdAvoid)
625 * This function marks the transient tree with pcdTree as its leader.
626 * If pcdAvoid is in the tree, it is not marked.
630 * pcdTree = pointer to client data of the tree to mark
631 * pcdAvoid = pointer to client data to not mark if in tree
634 *************************************<->***********************************/
636 void MarkModalSubtree (ClientData *pcdTree, ClientData *pcdAvoid)
638 /* Mark children, if any */
640 if (pcdTree->transientChildren)
641 MarkModalSubtree (pcdTree->transientChildren, pcdAvoid);
645 if (pcdTree != pcdAvoid)
647 MarkModalTransient (pcdTree, pcdAvoid);
652 if (pcdTree->transientSiblings)
653 MarkModalSubtree (pcdTree->transientSiblings, pcdAvoid);
658 /*************************************<->*************************************
660 * MarkModalTransient (pcdLeader, pCD)
665 * This function marks a transient window for application modal processing.
666 * Grabs are done to eat up pointer button events.
670 * pcdLeader = pointer to client data to mark
671 * pCD = pointer to client data of new transient
674 *************************************<->***********************************/
676 void MarkModalTransient (ClientData *pcdLeader, ClientData *pCD)
678 if (!IS_APP_MODALIZED(pcdLeader))
681 * Eat pointer button events while application modal.
683 XGrabButton (DISPLAY, AnyButton, AnyModifier,
684 pcdLeader->clientBaseWin, True,
685 ButtonPressMask | ButtonMotionMask, GrabModeAsync,
686 GrabModeAsync, None, wmGD.workspaceCursor);
689 /* bump application modal count */
690 if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
691 pcdLeader->fullModalCount++;
693 pcdLeader->primaryModalCount++;
697 /*************************************<->*************************************
699 * DeleteTransient (pCD)
704 * This function deletes the transient window from the lead window's list
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
716 * pCD = pointer to client data of transient.
718 *************************************<->***********************************/
720 void DeleteTransient (ClientData *pCD)
722 ClientData *pcdLeader;
728 * Handle primary application modality.
729 * Reset the modal window counts for the leader windows up through the
730 * transient window tree.
733 modalCount = pCD->primaryModalCount;
734 if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
740 pcdLeader = pCD->transientLeader;
744 UnMarkModalTransient (pcdLeader, modalCount, pCD);
746 pcdLeader = pcdLeader->transientLeader;
751 * Handle full application modality.
752 * Undo application modal windows in a depth first manner.
755 pcdLeader = FindTransientTreeLeader (pCD);
757 if (pCD->transientChildren)
759 DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
761 if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
765 * If this is a full application modal window then decrement
766 * the modal count for the rest of the transient tree.
769 FixupFullAppModalCounts (pcdLeader, pCD);
774 * Delete this transient from its parent's list of transient windows.
777 pcdPrev = pCD->transientLeader->transientChildren;
782 pCD->transientLeader->transientChildren = pCD->transientSiblings;
786 while (pcdPrev && (pcdPrev->transientSiblings != pCD))
788 pcdPrev = pcdPrev->transientSiblings;
791 pcdPrev->transientSiblings = pCD->transientSiblings;
795 } /* END OF FUNCTION DeleteTransient */
798 /*************************************<->*************************************
800 * DeleteFullAppModalChildren (pcdLeader, pCD)
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.
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.
815 * pcdLeader = pointer to client data of transient tree root.
816 * pCD = pointer to client data of transient subtree to delete.
818 *************************************<->***********************************/
820 void DeleteFullAppModalChildren (ClientData *pcdLeader, ClientData *pCD)
823 /* recursively do children first */
824 if (pCD->transientChildren)
825 DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
827 /* do fullAppModal fixup for this guy */
828 FixupFullAppModalCounts (pcdLeader, pCD);
830 /* do siblings of passed transient */
831 if (pCD->transientSiblings)
832 DeleteFullAppModalChildren (pcdLeader, pCD->transientSiblings);
835 } /* END OF FUNCTION DeleteFullAppModalChildren */
838 /*************************************<->*************************************
840 * FixupFullAppModalCounts (pcdLeader, pcdDelete)
845 * This function traverses the entire transient tree (pointed to by
846 * pcdLeader) and fixes up the fullModalCounts to reflect the removal
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.
856 * pcdLeader = pointer to client data for head of transient tree.
857 * pcdDelet = pointer to client data of transient being deleted.
859 *************************************<->***********************************/
862 FixupFullAppModalCounts (ClientData *pcdLeader, ClientData *pcdDelete)
867 if (pcdLeader->transientChildren)
869 FixupFullAppModalCounts (pcdLeader->transientChildren, pcdDelete);
873 * fixup leader: decrement the count if it is greater than
874 * the transient being deleted.
877 if (pcdLeader->fullModalCount > pcdDelete->fullModalCount)
879 UnMarkModalTransient (pcdLeader, 1, pcdDelete);
883 if (pcdLeader->transientSiblings)
885 FixupFullAppModalCounts (pcdLeader->transientSiblings, pcdDelete);
888 } /* END OF FUNCTION FixupFullAppModalCounts */
892 /*************************************<->*************************************
894 * UnMarkModalTransient (pcdModee, modalCount, pcdModal)
899 * This function unmarks a transient window for application modal processing.
900 * Original grabs are restored.
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
909 *************************************<->***********************************/
911 void UnMarkModalTransient (ClientData *pcdModee, int modalCount, ClientData *pcdModal)
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;
920 * Restore original button bindings/grabs if not modal anymore
922 if (!IS_APP_MODALIZED(pcdModee))
924 XUngrabButton (DISPLAY, AnyButton, AnyModifier,
925 pcdModee->clientBaseWin);
927 SetupCButtonBindings (pcdModee->clientBaseWin, BUTTON_SPECS(pcdModee));
929 if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
930 (wmGD.keyboardFocus != pcdModee))
932 DoExplicitSelectGrab (pcdModee->clientBaseWin);
938 /*************************************<->*************************************
940 * PutTransientOnTop (pcd)
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
954 * pcd = pointer to client data of a transient window
959 * pcdLeader = (transientSiblings)
961 * RETURN = True if the transient tree needs to be restacked
963 *************************************<->***********************************/
965 Boolean PutTransientOnTop (ClientData *pcd)
967 ClientData *pcdLeader;
969 Boolean restack = False;
972 pcdLeader = pcd->transientLeader;
973 if (pcdLeader != NULL)
975 pcdPrev = pcdLeader->transientChildren;
978 while (pcdPrev->transientSiblings != pcd)
980 pcdPrev = pcdPrev->transientSiblings;
982 pcdPrev->transientSiblings = pcd->transientSiblings;
983 pcd->transientSiblings = pcdLeader->transientChildren;
984 pcdLeader->transientChildren = pcd;
988 if (PutTransientOnTop (pcdLeader))
992 if (BumpPrimaryToBottom (pcdLeader))
1000 } /* END OF FUNCTION PutTransientOnTop */
1004 /*************************************<->*************************************
1006 * PutTransientBelowSiblings (pcd)
1011 * This function changes the transient window list to insure that the
1012 * specified transient window is below its sibling windows.
1017 * pcd = pointer to client data of a transient window
1022 * pcdLeader = (transientSiblings)
1024 * RETURN = True if restacking has been done in the transient window tree.
1026 *************************************<->***********************************/
1028 Boolean PutTransientBelowSiblings (ClientData *pcd)
1030 ClientData *pcdLeader;
1031 ClientData *pcdNext;
1032 Boolean restack = False;
1035 pcdLeader = pcd->transientLeader;
1038 if (pcd->transientSiblings || (pcdLeader->transientChildren != pcd))
1041 if (pcdLeader->transientChildren == pcd)
1043 pcdLeader->transientChildren = pcd->transientSiblings;
1046 pcdNext = pcdLeader->transientChildren;
1047 while (pcdNext->transientSiblings)
1049 if (pcdNext->transientSiblings == pcd)
1051 pcdNext->transientSiblings = pcd->transientSiblings;
1055 pcdNext = pcdNext->transientSiblings;
1058 pcdNext->transientSiblings = pcd;
1060 pcd->transientSiblings = NULL;
1065 } /* END OF FUNCTION PutTransientBelowSiblings */
1069 /*************************************<->*************************************
1071 * RestackTransients (pcd)
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.
1084 * pcd = pointer to client data of a window in a transient tree
1086 *************************************<->***********************************/
1088 void RestackTransients (ClientData *pcd)
1090 ClientData *pcdLeader;
1092 static int size = 0;
1093 static Window *windows = NULL;
1094 XWindowChanges windowChanges;
1099 * Build a restacking list and do the restacking.
1102 pcdLeader = FindTransientTreeLeader (pcd);
1103 count = CountTransientChildren (pcdLeader);
1105 /* No work to do if no transient children; count includes leader. */
1112 * Expand the (static) windows buffer that is used in restacking.
1116 (Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
1118 /* cannot get memory space */
1125 MakeTransientFamilyStackingList (windows, pcdLeader);
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.
1133 for (leaderIndex = 0; leaderIndex < count; leaderIndex++)
1135 if (windows[leaderIndex] == pcdLeader->clientFrameWin)
1138 if (leaderIndex >= count) /* ? Couldn't find leader; should NOT happen. */
1139 leaderIndex = count - 1;
1141 windowChanges.stack_mode = Above;
1142 for (i = leaderIndex; i > 0; i--)
1144 windowChanges.sibling = windows[i];
1145 XConfigureWindow (DISPLAY, windows[i - 1],
1146 CWSibling | CWStackMode, &windowChanges);
1149 windowChanges.stack_mode = Below;
1150 for (i = leaderIndex; i < count - 1; i++)
1152 windowChanges.sibling = windows[i];
1153 XConfigureWindow (DISPLAY, windows[i + 1],
1154 CWSibling | CWStackMode, &windowChanges);
1157 } /* END OF FUNCTION RestackTransients */
1161 /*************************************<->*************************************
1163 * RestackTransientsAtWindow (pcd)
1168 * This function restacks windows in a transient window tree. The
1169 * "anchor point" in the stack for the transient window tree is the
1175 * pcd = pointer to client data of a window in a transient tree
1177 *************************************<->***********************************/
1179 void RestackTransientsAtWindow (ClientData *pcd)
1181 ClientData *pcdLeader;
1182 XWindowChanges windowChanges;
1184 pcdLeader = FindTransientTreeLeader (pcd);
1185 if (pcdLeader && (pcdLeader != pcd))
1187 windowChanges.sibling = pcd->clientFrameWin;
1188 windowChanges.stack_mode = Below;
1189 XConfigureWindow (DISPLAY, pcdLeader->clientFrameWin,
1190 CWSibling | CWStackMode, &windowChanges);
1193 RestackTransients (pcd);
1195 } /* END OF FUNCTION RestackTransientsAtWindow */
1199 /*************************************<->*************************************
1201 * FindTransientTreeLeader (pcd)
1206 * This function identifies the leader of the transient tree that
1207 * contains the specified client.
1212 * pcd = pointer to client data of a window in a transient tree.
1216 * RETURN = pointer to the client data for the transient tree leader.
1218 *************************************<->***********************************/
1220 ClientData * FindTransientTreeLeader (ClientData *pcd)
1225 * Find the head of the transient window tree.
1228 while (pcd->transientLeader)
1230 pcd = pcd->transientLeader;
1235 } /* END OF FUNCTION FindTransientTreeLeader */
1239 /*************************************<->*************************************
1241 * CountTransientChildren (pcd)
1246 * This function returns a count of the number of children in the
1247 * transient window tree headed by the specified client window.
1252 * pcd = pointer to client data of a window in a transient tree
1256 * RETURN = count of transient windows in the transient window tree
1258 *************************************<->***********************************/
1261 CountTransientChildren (ClientData *pcd)
1264 ClientData *pcdNext;
1268 pcdNext = pcd->transientChildren;
1271 if (pcdNext->transientChildren)
1273 count += CountTransientChildren (pcdNext);
1279 pcdNext = pcdNext->transientSiblings;
1284 } /* END OF FUNCTION CountTransientChildren */
1288 /*************************************<->*************************************
1290 * MakeTransientWindowList (windows, pcd)
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.
1302 * windows = pointer to the windows list to be filled out
1304 * pcd = pointer to client data of a window in a transient tree
1308 * RETURN = pointer to the next entry in the windows list
1310 *************************************<->***********************************/
1312 Window * MakeTransientWindowList (Window *windows, ClientData *pcd)
1315 ClientData *pcdNext;
1318 pcdNext = pcd->transientChildren;
1321 if (pcdNext->transientChildren)
1323 windows = MakeTransientWindowList (windows, pcdNext);
1325 *windows = pcdNext->clientFrameWin;
1327 pcdNext = pcdNext->transientSiblings;
1333 } /* END OF FUNCTION MakeTransientWindowList */
1337 /*************************************<->*************************************
1339 * FindTransientFocus (pcd)
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.
1351 * pcd = pointer to client data of a window in a transient tree.
1355 * RETURN = pointer to the client data for a window that can accept the
1356 * keyboard input focus.
1358 *************************************<->***********************************/
1360 ClientData * FindTransientFocus (ClientData *pcd)
1364 ClientData *pcdFocus;
1367 * Find a window that does not have an application modal subordinate.
1368 * First, search descendents
1372 while (pcdFocus->transientChildren && IS_APP_MODALIZED(pcdFocus))
1374 pcdFocus = pcdFocus->transientChildren;
1378 * If (search of descendents FAILS) then search siblings.
1381 if (IS_APP_MODALIZED(pcdFocus))
1383 ClientData *pcdSibling;
1386 while (pcdFocus && IS_APP_MODALIZED(pcdFocus))
1388 pcdSibling = pcdFocus;
1389 while (pcdSibling->transientSiblings && IS_APP_MODALIZED(pcdFocus))
1391 pcdSibling = pcdSibling->transientSiblings;
1393 if (IS_APP_MODALIZED(pcdSibling))
1395 pcdFocus = pcdFocus->transientChildren;
1399 pcdFocus = pcdSibling;
1405 return (pcdFocus ? pcdFocus : wmGD.keyboardFocus);
1407 } /* END OF FUNCTION FindTransientFocus */
1411 /*************************************<->*************************************
1413 * FindTransientOnTop (pcd)
1418 * This function identifies the top-most transient window in the
1419 * transient window tree that contains the specified client.
1424 * pcd = pointer to client data of a window in a transient tree.
1428 * RETURN = pointer to the client data for the top-most transient window.
1430 *************************************<->***********************************/
1432 ClientData * FindTransientOnTop (ClientData *pcd)
1437 * Find the head of the transient window tree.
1440 pcd = FindTransientTreeLeader (pcd);
1441 if (!(pcd->secondariesOnTop) &&
1442 (LeaderOnTop (pcd)))
1446 if (LeaderOnTop (pcd))
1448 /* The primary window is on top! */
1453 pcdSub = FindSubLeaderToTop (pcd);
1461 * Find the top-most transient window (the window in the transient tree
1462 * that is highest in the window stack).
1465 while (pcd->transientChildren)
1467 pcd = pcd->transientChildren;
1472 } /* END OF FUNCTION FindTransientOnTop */
1476 /*************************************<->*************************************
1478 * StackWindow (pWS, pEntry, onTop, pStackEntry)
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.
1489 * pWS = pointer to workspace data
1491 * pEntry = pointer to the client list entry for the window to be restacked.
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
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.
1503 *************************************<->***********************************/
1505 void StackWindow (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
1508 Boolean stackTransientTreeWindows = False;
1509 Window activeIconWindow;
1511 XWindowChanges changes;
1512 WmScreenData *pSD = pWS->pSD;
1517 if (pStackEntry->type == MINIMIZED_STATE)
1519 stackWindow = ICON_FRAME_WIN(pStackEntry->pCD);
1523 stackWindow = pStackEntry->pCD->clientFrameWin;
1528 stackWindow = (Window)0;
1531 if (pEntry->type == MINIMIZED_STATE)
1533 window = ICON_FRAME_WIN(pEntry->pCD);
1538 * Restack the transient tree if appropriate.
1541 if (pEntry->pCD->transientLeader || pEntry->pCD->transientChildren)
1543 stackTransientTreeWindows = True;
1545 window = (FindTransientOnTop (pEntry->pCD))->clientFrameWin;
1549 window = pEntry->pCD->clientFrameWin;
1555 * The active icon text label must be restacked along with the associated
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))
1564 activeIconWindow = ACTIVE_ICON_TEXT_WIN;
1568 activeIconWindow = (Window)0;
1573 if ((stackWindow == 0) && (pSD->clientList))
1575 if (pSD->clientList->type == MINIMIZED_STATE)
1577 stackWindow = ICON_FRAME_WIN(pSD->clientList->pCD);
1581 if (pSD->clientList->pCD->transientChildren)
1584 (FindTransientOnTop(pSD->clientList->pCD))->clientFrameWin;
1588 stackWindow = pSD->clientList->pCD->clientFrameWin;
1593 if (activeIconWindow)
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),
1606 changes.sibling = stackWindow;
1607 changes.stack_mode = Above;
1608 XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1610 if (stackTransientTreeWindows)
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);
1624 * Adjust stack entry window if we're stacking below a
1627 if (pStackEntry && pStackEntry->pCD->transientChildren)
1629 stackWindow = LowestWindowInTransientFamily (pStackEntry->pCD);
1632 if (stackWindow == 0)
1634 if (pSD->lastClient->type == MINIMIZED_STATE)
1636 stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
1640 if (pSD->lastClient->pCD->transientChildren)
1643 LowestWindowInTransientFamily (pSD->lastClient->pCD);
1646 stackWindow = pSD->lastClient->pCD->clientFrameWin;
1650 if (activeIconWindow)
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),
1663 changes.sibling = stackWindow;
1664 changes.stack_mode = Below;
1665 XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
1667 if (stackTransientTreeWindows)
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);
1679 } /* END OF FUNCTION StackWindow */
1683 /*************************************<->*************************************
1685 * StackTransientWindow (pcd)
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.
1697 * pcd = pointer to client data of a window in a transient tree
1699 *************************************<->***********************************/
1701 void StackTransientWindow (ClientData *pcd)
1703 XWindowChanges changes;
1704 ClientData *pcdPrev;
1707 if (pcd->transientLeader->transientChildren == pcd)
1709 if (pcd->transientSiblings)
1711 changes.sibling = pcd->transientSiblings->clientFrameWin;
1715 changes.sibling = pcd->transientLeader->clientFrameWin;
1717 changes.stack_mode = Above;
1721 pcdPrev = pcd->transientLeader;
1722 while (pcdPrev->transientSiblings != pcd)
1724 pcdPrev = pcdPrev->transientSiblings;
1726 changes.sibling = pcdPrev->clientFrameWin;
1727 changes.stack_mode = Below;
1730 XConfigureWindow (DISPLAY, pcd->clientFrameWin, (CWSibling | CWStackMode),
1734 } /* END OF FUNCTION StackTransientWindow */
1738 /*************************************<->*************************************
1740 * CheckIfClientObscuring (pcdTop, pcd)
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.
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.
1756 * pcd = pointer to client data for a window (it may be the leader of
1762 * RETURN = True if the top window(s) overlap the lower window(s)
1764 *************************************<->***********************************/
1766 Boolean CheckIfClientObscuring (ClientData *pcdTop, ClientData *pcd)
1768 Boolean obscuring = False;
1769 ClientData *pcdNext;
1773 * Check only if the top window is visible onscreen.
1776 if (pcdTop->transientChildren && (pcdTop->clientState != MINIMIZED_STATE))
1778 pcdNext = pcdTop->transientChildren;
1779 while (pcdNext && !obscuring)
1781 obscuring = CheckIfClientObscuring (pcdNext, pcd);
1782 pcdNext = pcdNext->transientSiblings;
1786 if (!obscuring && pcd->transientChildren &&
1787 (pcd->clientState != MINIMIZED_STATE))
1789 pcdNext = pcd->transientChildren;
1790 while (pcdNext && !obscuring)
1792 obscuring = CheckIfClientObscuring (pcdTop, pcdNext);
1793 pcdNext = pcdNext->transientSiblings;
1799 obscuring = CheckIfObscuring (pcdTop, pcd);
1804 } /* END OF FUNCTION CheckIfClientObscuring */
1808 /*************************************<->*************************************
1810 * CheckIfObscuring (pcdA, pcdB)
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.
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.
1825 * pcdB = pointer to client data for a window.
1830 * RETURN = True if the top window overlaps the lower window
1832 *************************************<->***********************************/
1834 Boolean CheckIfObscuring (ClientData *pcdA, ClientData *pcdB)
1836 Boolean obscuring = False;
1847 * For workspace stuff: if either is unseen, then neither
1850 if ((pcdA->clientState & UNSEEN_STATE) ||
1851 (pcdB->clientState & UNSEEN_STATE))
1856 if (pcdA->clientState == NORMAL_STATE)
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;
1864 else if (pcdA->clientState == MINIMIZED_STATE)
1868 aX2 = aX1 + ICON_WIDTH(pcdA) - 1;
1869 aY2 = aY1 + ICON_HEIGHT(pcdA) - 1;
1871 else /* (pcdA->clientState == MAXIMIZED_STATE) */
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;
1880 if (pcdB->clientState == NORMAL_STATE)
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;
1888 else if (pcdB->clientState == MINIMIZED_STATE)
1892 bX2 = bX1 + ICON_WIDTH(pcdB) - 1;
1893 bY2 = bY1 + ICON_HEIGHT(pcdB) - 1;
1895 else /* (pcdB->clientState == MAXIMIZED_STATE) */
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;
1905 * Check if there is overlap in both dimensions.
1908 if (((aX1 >= bX1) && (aX1 <= bX2)) || ((aX2 >= bX1) && (aX2 <= bX2)) ||
1909 ((bX1 >= aX1) && (bX1 <= aX2)) || ((bX2 >= aX1) && (bX2 <= aX2)))
1911 if (((aY1 >= bY1) && (aY1 <= bY2)) || ((aY2 >= bY1) && (aY2 <= bY2)) ||
1912 ((bY1 >= aY1) && (bY1 <= aY2)) || ((bY2 >= aY1) && (bY2 <= aY2)))
1921 } /* END OF FUNCTION CheckIfObscuring */
1925 /*************************************<->*************************************
1927 * CheckIfClientObscuredByAny (pcd)
1932 * This function determines whether a window or a transient window tree
1933 * is obscured (at least partially) by any other window.
1938 * pcd = pointer to client data for a window (it may be the leader of
1944 * RETURN = True if the window(s) are overlapped.
1946 *************************************<->***********************************/
1948 Boolean CheckIfClientObscuredByAny (ClientData *pcd)
1950 Boolean obscured = False;
1951 ClientListEntry *pListEntry;
1954 pListEntry = ACTIVE_PSD->clientList;
1955 while (pListEntry && !obscured)
1957 if (pListEntry->pCD == pcd)
1959 if (((pListEntry->type == MINIMIZED_STATE) &&
1960 (pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
1961 ((pListEntry->type != MINIMIZED_STATE) &&
1962 (pListEntry->pCD->clientState != MINIMIZED_STATE)))
1967 else if (((pListEntry->type == MINIMIZED_STATE) &&
1968 (pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
1969 ((pListEntry->type != MINIMIZED_STATE) &&
1970 (pListEntry->pCD->clientState != MINIMIZED_STATE)))
1973 * The window for the entry is visible on screen. See if it
1974 * obscures the indicated window.
1977 obscured = CheckIfClientObscuring (pListEntry->pCD, pcd);
1982 pListEntry = pListEntry->nextSibling;
1988 } /* END OF FUNCTION CheckIfClientObscuredByAny */
1992 /*************************************<->*************************************
1994 * CheckIfClientObscuringAny (pcd)
1999 * This function determines whether a window or a transient window tree
2000 * is obscuring another window.
2005 * pcd = pointer to client data for a window (it may be the leader of
2011 * RETURN = True if the window(s) overlaps anther window.
2013 *************************************<->***********************************/
2015 Boolean CheckIfClientObscuringAny (ClientData *pcd)
2017 Boolean obscuring = False;
2018 ClientListEntry *pListEntry;
2021 pListEntry = (pcd->clientState == MINIMIZED_STATE) ?
2022 &pcd->iconEntry : &pcd->clientEntry;
2023 while (pListEntry && !obscuring)
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))))
2031 obscuring = CheckIfClientObscuring (pcd, pListEntry->pCD);
2034 pListEntry = pListEntry->nextSibling;
2039 } /* END OF FUNCTION CheckIfClientObscuringAny */
2043 /*************************************<->*************************************
2045 * SetupSystemModalState (pCD)
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.
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
2063 * wmGD = changes to system modal state data
2065 *************************************<->***********************************/
2067 void SetupSystemModalState (ClientData *pCD)
2069 XWindowChanges windowChanges;
2070 unsigned int width, height;
2071 unsigned int x_hot, y_hot;
2072 unsigned char *bits;
2073 unsigned char *mask_bits;
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.
2082 if (wmGD.menuActive != NULL)
2084 UnpostMenu (wmGD.menuActive);
2085 XSync (DISPLAY, False);
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.
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 */
2101 CurrentTime) == GrabFrozen)
2107 XUngrabPointer (DISPLAY, CurrentTime);
2110 if (XGrabKeyboard(DISPLAY,
2111 ROOT_FOR_CLIENT(pCD),
2112 FALSE, /* owner_events */
2113 GrabModeAsync, /* pointer_mode */
2114 GrabModeAsync, /* keyboard_mode */
2115 CurrentTime) == GrabFrozen)
2121 XUngrabKeyboard (DISPLAY, CurrentTime);
2126 if (wmGD.useLargeCursors)
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;
2137 #endif /* LARGECURSORS */
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;
2148 for (scr=0; scr<wmGD.numScreens; scr++)
2150 pSD = &(wmGD.Screens[scr]);
2153 * Make the system modal input screen window if necessary.
2156 if (pSD->managed && pSD->inputScreenWindow == 0)
2158 XSetWindowAttributes windowAttributes;
2163 windowAttributes.event_mask = ButtonPressMask;
2164 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2166 windowAttributes.event_mask |= EnterWindowMask;
2168 windowAttributes.override_redirect = True;
2170 pixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow,
2171 (char *)bits, width, height);
2173 maskPixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow,
2174 (char *)mask_bits, width, height);
2176 xcolors[0].pixel = BlackPixel (DISPLAY, pSD->screen);
2177 xcolors[1].pixel = WhitePixel (DISPLAY, pSD->screen);
2178 XQueryColors (DISPLAY, DefaultColormap (DISPLAY, pSD->screen),
2180 windowAttributes.cursor =
2181 XCreatePixmapCursor (DISPLAY, pixmap, maskPixmap,
2182 &(xcolors[0]), &(xcolors[1]),
2184 XFreePixmap (DISPLAY, pixmap);
2185 XFreePixmap (DISPLAY, maskPixmap);
2187 pSD->inputScreenWindow =
2188 XCreateWindow (DISPLAY, pSD->rootWindow, 0, 0,
2189 DisplayWidth (DISPLAY, pSD->screen),
2190 DisplayHeight (DISPLAY, pSD->screen),
2195 CWEventMask | CWOverrideRedirect | CWCursor,
2198 if (pSD->managed && pSD != ACTIVE_PSD)
2200 XMapRaised (DISPLAY, pSD->inputScreenWindow);
2206 wmGD.systemModalWindow = pCD->clientFrameWin;
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
2217 SetKeyboardFocus (NULL, REFRESH_LAST_FOCUS);
2218 XSetInputFocus (DISPLAY, wmGD.systemModalWindow, RevertToPointerRoot,
2224 * Map the system modal input screen window below the system modal
2228 windowChanges.sibling = wmGD.systemModalWindow;
2229 windowChanges.stack_mode = Below;
2230 XConfigureWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow,
2231 CWSibling | CWStackMode, &windowChanges);
2233 XMapWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow);
2237 * Setup the system modal global data.
2240 wmGD.systemModalActive = True;
2241 wmGD.systemModalClient = pCD;
2244 } /* END OF FUNCTION SetupSystemModalState */
2248 /*************************************<->*************************************
2250 * UndoSystemModalState ()
2255 * This function cleans up after a system modal window goes away.
2260 * wmGD = (system modal state data)
2265 * wmGD = changes to system modal state data
2267 *************************************<->***********************************/
2269 void UndoSystemModalState (void)
2274 * Unmap the system modal input screen window.
2277 for (scr = 0; scr < wmGD.numScreens; scr++)
2279 if(wmGD.Screens[scr].managed)
2281 XUnmapWindow (DISPLAY, wmGD.Screens[scr].inputScreenWindow);
2286 * Reset the focus if a window manager system modal dialog box was
2290 if (!wmGD.systemModalClient)
2292 AutoResetKeyFocus (NULL, GetTimestamp());
2297 * Reset the system modal global data.
2300 wmGD.systemModalActive = False;
2301 wmGD.systemModalClient = NULL;
2302 wmGD.systemModalWindow = 0;
2304 } /* END OF FUNCTION UndoSystemModalState */
2308 /*************************************<->*************************************
2310 * FindClientNameMatch (pStartingEntry, toNext, clientName, types)
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.
2322 * pEntry = pointer to the client list entry where the search is
2325 * toNext = if True then search client list from first to last; otherwise
2326 * search the client list last to first.
2328 * clientName = string that indicates a client name or class.
2330 * type = types of objects (icon, window, ...) that are to be matched.
2335 * RETURN = pointer to client list entry for matched client.
2337 *************************************<->***********************************/
2338 ClientListEntry * FindClientNameMatch (ClientListEntry *pEntry,
2341 unsigned long types)
2344 Boolean foundMatch = False;
2349 while (!foundMatch && pEntry)
2353 if (pEntry->type == MINIMIZED_STATE)
2355 if ((pCD->clientState == MINIMIZED_STATE) &&
2356 (types & F_GROUP_ICON))
2363 if ((pCD->clientState != MINIMIZED_STATE) &&
2364 (types & F_GROUP_WINDOW))
2371 ((pCD->clientName && (strcmp (clientName,pCD->clientName) == 0)) ||
2372 (pCD->clientClass && (strcmp (clientName,pCD->clientClass) == 0))))
2378 pEntry = (toNext) ? pEntry->nextSibling : pEntry->prevSibling;
2384 } /* END OF FUNCTION FindClientNameMatch */
2386 /*************************************<->*************************************
2388 * BumpPrimaryToTop (pcdLeader)
2393 * This function moves the primary window to the "top" of the transient
2398 * pcdLeader = pointer to client data of transient tree root.
2400 * Returns: True if stacking order of leader window changed.
2401 * False if not stacking change.
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.
2409 *************************************<->***********************************/
2411 Boolean BumpPrimaryToTop (ClientData *pcdLeader)
2416 count = CountTransientChildren (pcdLeader);
2418 if (pcdLeader->primaryStackPosition != (count-1))
2420 pcdLeader->primaryStackPosition = count - 1;
2431 /*************************************<->*************************************
2433 * BumpPrimaryToBottom (pcdLeader)
2438 * This function moves the primary window to the "bottom" of the transient
2443 * pcdLeader = pointer to client data of transient tree root.
2445 * Returns: True if stacking order of leader window changed.
2446 * False if not stacking change.
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.
2454 *************************************<->***********************************/
2456 Boolean BumpPrimaryToBottom (ClientData *pcdLeader)
2460 if (pcdLeader->primaryStackPosition != 0)
2462 pcdLeader->primaryStackPosition = 0;
2474 /*************************************<->*************************************
2476 * LowestWindowInTransientFamily (pcdLeader)
2481 * This function returns the lowest stacked window in a transient
2486 * pcdLeader = pointer to client data of leader of a transient tree
2488 * Returns: id of lowest window in the transient tree for this family
2490 *************************************<->***********************************/
2493 LowestWindowInTransientFamily (ClientData *pcdLeader)
2496 static int size = 0;
2497 static Window *windows = NULL;
2498 Window wReturn = None;
2501 * Build a window list
2503 count = CountTransientChildren (pcdLeader);
2508 * Expand the (static) windows buffer
2512 (Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
2514 /* cannot get memory space */
2521 MakeTransientFamilyStackingList (windows, pcdLeader);
2525 wReturn = windows[count-1];
2534 } /* END OF FUNCTION LowestWindowInTransientFamily */
2537 /*************************************<->*************************************
2539 * FindSubLeaderToTop (pcd)
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).
2551 * pcd = pointer to client data of a transient leader window
2553 * Return: ptr to client data for client that should be topped, or NULL
2559 *************************************<->***********************************/
2562 FindSubLeaderToTop (
2566 ClientData *pcdRet = NULL;
2567 ClientData *pcdNext;
2569 pcdNext = pcd->transientChildren;
2570 while (pcdNext && (!pcdRet))
2572 if (pcdNext->transientChildren)
2574 if (LeaderOnTop (pcdNext))
2580 pcdRet = FindSubLeaderToTop (pcdNext);
2583 pcdNext = pcdNext->transientSiblings;
2590 /*************************************<->*************************************
2592 * MakeTransientFamilyStackingList (windows, pcdLeader)
2597 * This function makes a transient window list of windows in the
2598 * transient window tree headed by the specified client.
2603 * windows = pointer to the windows list to be filled out
2605 * pcdLeader = pointer to client data of a window in a transient tree
2609 * The windows array is modified.
2613 * This function puts the transient leader window in the list in the
2616 *************************************<->***********************************/
2619 MakeTransientFamilyStackingList (
2621 ClientData *pcdLeader)
2625 Window *nextWindow, wSave, wTemp, wTop;
2626 int count = CountTransientChildren (pcdLeader);
2630 * Construct the transient stacking list according to
2631 * normal Motif rules.
2633 nextWindow = MakeTransientWindowList (windows, pcdLeader);
2635 if (!(pcdLeader->secondariesOnTop))
2638 * If the leader window shouldn't be on the bottom , then
2639 * adjust the stacking of the list.
2641 if ((pcdLeader->primaryStackPosition > 0) &&
2642 (pcdLeader->primaryStackPosition < count))
2644 for (i=0; i<pcdLeader->primaryStackPosition; i++)
2647 windows[j] = windows[j-1];
2649 j = count - pcdLeader->primaryStackPosition - 1;
2650 windows[j] = pcdLeader->clientFrameWin;
2655 * Put the leader at the bottom.
2657 *nextWindow = pcdLeader->clientFrameWin;
2660 * If one of the transients is also a local leader
2661 * and wants to be on top, then adjust the list.
2663 pcdSub = FindSubLeaderToTop (pcdLeader);
2664 if (pcdSub && (pcdSub->clientFrameWin != None))
2666 /* insert this window at top */
2667 wTop = wSave = pcdSub->clientFrameWin;
2669 /* shuffle the rest down */
2670 for (i=0; i<count; i++)
2685 * Put the leader at the bottom.
2687 *nextWindow = pcdLeader->clientFrameWin;
2690 } /* END OF FUNCTION MakeTransientFamilyStackingList */
2693 /*************************************<->*************************************
2695 * NormalizeTransientTreeStacking (pcdLeader)
2700 * This function traverses the transient tree and cleans up any
2701 * local primary windows that are above their respective secondary
2707 * pcdLeader = pointer to client data of a transient tree leader
2709 * Return: True if any changes in stacking order were made
2714 * This only touches the data structures.
2716 *************************************<->***********************************/
2719 NormalizeTransientTreeStacking (
2720 ClientData *pcdLeader)
2723 ClientData *pcdNext;
2724 Boolean bChanged = False;
2726 pcdNext = pcdLeader->transientChildren;
2727 bChanged = BumpPrimaryToBottom (pcdLeader);
2730 if (pcdNext->transientChildren)
2732 bChanged |= BumpPrimaryToBottom (pcdNext);
2734 bChanged |= NormalizeTransientTreeStacking (pcdNext);
2736 pcdNext = pcdNext->transientSiblings;
2742 /*************************************<->*************************************
2744 * LeaderOnTop (pcdLeader)
2749 * This function tests a leader of a transient (sub) tree to see if
2750 * it should be on top of its transient windows.
2755 * pcdLeader = pointer to client data of a transient tree leader
2757 * Return: True if this leader is on top of its transients
2763 *************************************<->***********************************/
2767 ClientData *pcdLeader)
2770 Boolean bOnTop = False;
2771 int count = CountTransientChildren (pcdLeader);
2773 if ((pcdLeader->primaryStackPosition > 0) &&
2774 (pcdLeader->primaryStackPosition < count))