/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* Motif Release 1.2.3
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: WmWinList.c /main/8 1997/06/10 15:50:50 samborn $"
#endif
#endif
/*
* (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 Hewlett-Packard Company
* (c) Copyright 1993, 1994 International Business Machines Corp.
* (c) Copyright 1993, 1994 Sun Microsystems, Inc.
* (c) Copyright 1993, 1994 Novell, Inc.
*/
/*
* Included Files:
*/
#include "WmGlobal.h"
#define MWM_NEED_NOENTER16
#include "WmBitmap.h"
/*
* include extern functions
*/
#include "WmWinList.h"
#include "WmCEvent.h"
#include "WmFunction.h"
#include "WmKeyFocus.h"
#include "WmMenu.h"
#include "WmResource.h"
#include "WmWinInfo.h"
#ifdef WSM
#include "WmWrkspace.h"
#endif /* WSM */
/*
* Global Variables:
*/
/*************************************<->*************************************
*
* AddClientToList (pWS, pCD, onTop)
*
*
* Description:
* -----------
* This function adds a client window to the client window list. If it is
* a transient window then it is added to the transient window tree that
* contains its transient leader. The window stacking order is also
* maintained for the cases where there is a system modal window active
* or the window is a transient window. If a system modal window is being
* added then the system modal "input screen" window is setup.
*
*
* Inputs:
* ------
* pCD = pointer to client data for the window to be added to the list
*
* pWS = pointer to workspace data
*
* onTop = if True then the window is displayed on top of the window
* stack and is added to the beginning of the window list, otherwise
* it is added to the end of the window list.
*
*
* Outputs:
* -------
* pWS = (clientList, lastClient)
*
*************************************<->***********************************/
void AddClientToList (WmWorkspaceData *pWS, ClientData *pCD, Boolean onTop)
{
Boolean belowSystemModal = False;
XWindowChanges windowChanges;
WmScreenData *pSD = pWS->pSD;
#ifdef WSM
WsClientData *pWsc = GetWsClientData (pWS, pCD);
#endif /* WSM */
if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
{
/*
* Set up the system modal input screen window just below the
* system modal window.
*/
SetupSystemModalState (pCD);
if (!wmGD.systemModalActive || (wmGD.systemModalClient != pCD))
{
/*
* If we failed to setup as system modal, then
* back off to MWM_INPUT_FULL_APPLICATION_MODAL.
* This will do *something* if this is a transient
* window.
*/
pCD->inputMode = MWM_INPUT_FULL_APPLICATION_MODAL;
}
}
else if (wmGD.systemModalActive &&
((FindTransientTreeLeader (pCD))->inputMode !=
MWM_INPUT_SYSTEM_MODAL))
{
/*
* If a system modal window is active then place the window below
* the system modal input screen window if the window is not a
* descendant of the system modal window.
*/
windowChanges.sibling = pSD->inputScreenWindow;
windowChanges.stack_mode = Below;
XConfigureWindow (DISPLAY, pCD->clientFrameWin,
CWSibling | CWStackMode, &windowChanges);
belowSystemModal = True;
}
if (pCD->transientLeader)
{
AddTransient (pWS, pCD);
}
else
{
pCD->clientEntry.type = NORMAL_STATE;
pCD->clientEntry.pCD = pCD;
if (belowSystemModal && wmGD.systemModalClient)
{
AddEntryToList (pWS, &pCD->clientEntry, False /*below*/,
pSD->clientList);
}
else if (onTop)
{
AddEntryToList (pWS, &pCD->clientEntry, True /*on top*/, NULL);
}
else
{
AddEntryToList (pWS, &pCD->clientEntry, False /*on bottom*/, NULL);
}
#ifdef WSM
if (!pWsc->pIconBox && pWsc->iconFrameWin)
#else /* WSM */
if (!pCD->pIconBox && pCD->iconFrameWin)
#endif /* WSM */
{
/*
* Put the icon on the bottom of the stack.
*/
if (pSD->lastClient->type == MINIMIZED_STATE)
{
#ifdef WSM
WsClientData *pWsib;
pWsib = &pSD->lastClient->pCD->pWsList[0];
windowChanges.sibling = pWsib->iconFrameWin;
#else /* WSM */
windowChanges.sibling = pSD->lastClient->pCD->iconFrameWin;
#endif /* WSM */
}
else
{
windowChanges.sibling = pSD->lastClient->pCD->clientFrameWin;
}
windowChanges.stack_mode = Below;
#ifdef WSM
XConfigureWindow (DISPLAY, pWsc->iconFrameWin,
CWSibling | CWStackMode, &windowChanges);
#else /* WSM */
XConfigureWindow (DISPLAY, pCD->iconFrameWin,
CWSibling | CWStackMode, &windowChanges);
#endif /* WSM */
pCD->iconEntry.type = MINIMIZED_STATE;
pCD->iconEntry.pCD = pCD;
pCD->iconEntry.nextSibling = NULL;
pCD->iconEntry.prevSibling = pSD->lastClient;
pSD->lastClient->nextSibling = &pCD->iconEntry;
pSD->lastClient = &pCD->iconEntry;
}
}
} /* END OF FUNCTION AddClientToList */
/*************************************<->*************************************
*
* AddEntryToList (pWS, pEntry, onTop, pStackEntry)
*
*
* Description:
* -----------
* This function adds a client list entry to the client window list.
* This is usually done as part of the process of changing the ordering
* of the window list.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
* pEntry = pointer to a client list entry to be added to the client list
*
* onTop = if True then the client list entry is added on top of the
* specified client list stack entry (if the stack entry is not
* specified then the entry is added to the front of the list);
* otherwise the entry is added after the specified stacking entry
* (or to the end of the list if the stacking entry is not specified).
*
* pStackEntry = pointer to a client list entry to be used as a reference
* in adding an entry to the client list.
*
* Outputs:
* -------
* pWS = (clientList, lastClient)
*
*************************************<->***********************************/
void AddEntryToList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
{
WmScreenData *pSD = pWS->pSD;
if (onTop)
{
if (pStackEntry)
{
if (pEntry != pStackEntry)
{
pEntry->nextSibling = pStackEntry;
pEntry->prevSibling = pStackEntry->prevSibling;
pStackEntry->prevSibling = pEntry;
if (pEntry->prevSibling)
{
pEntry->prevSibling->nextSibling = pEntry;
}
else
{
pSD->clientList = pEntry;
}
}
}
else
{
if (pSD->clientList != pEntry)
{
pEntry->nextSibling = pSD->clientList;
pEntry->prevSibling = NULL;
if (pSD->clientList)
{
pSD->clientList->prevSibling = pEntry;
}
else
{
pSD->lastClient = pEntry;
}
pSD->clientList = pEntry;
}
}
}
else
{
if (pStackEntry)
{
if (pEntry != pStackEntry)
{
pEntry->nextSibling = pStackEntry->nextSibling;
pEntry->prevSibling = pStackEntry;
pStackEntry->nextSibling = pEntry;
if (pEntry->nextSibling)
{
pEntry->nextSibling->prevSibling = pEntry;
}
else
{
pSD->lastClient = pEntry;
}
}
}
else
{
if (pSD->lastClient != pEntry)
{
pEntry->nextSibling = NULL;
pEntry->prevSibling = pSD->lastClient;
if (pSD->clientList)
{
pSD->lastClient->nextSibling = pEntry;
}
else
{
pSD->clientList = pEntry;
}
pSD->lastClient = pEntry;
}
}
}
} /* END OF FUNCTION AddEntryToList */
/*************************************<->*************************************
*
* MoveEntryInList (pWS, pEntry, onTop, pStackEntry)
*
*
* Description:
* -----------
* This function moves a client list entry in the client window list.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
*
* pEntry = pointer to a client list entry to be moved in the client list
*
* onTop = if True then the client list entry is moved on top of the
* specified client list stack entry (if the stack entry is not
* specified then the entry is moved to the front of the list);
* otherwise the entry is moved after the specified stacking entry
* (or to the end of the list if the stacking entry is not specified).
*
* pStackEntry = pointer to a client list entry to be used as a reference
* in moving an entry in the client list.
*
* Outputs:
* -------
* pWS = (clientList, lastClient)
*
*************************************<->***********************************/
void MoveEntryInList (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
{
DeleteEntryFromList (pWS, pEntry);
AddEntryToList (pWS, pEntry, onTop, pStackEntry);
} /* END OF FUNCTION MoveEntryInList */
/*************************************<->*************************************
*
* DeleteEntryFromList (pWS, pListEntry)
*
*
* Description:
* -----------
* This function deletes a client list entry from the client window list.
* This is usually done as part of the process of changing the ordering
* of the window list.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
* listEntry = pointer to a client list entry
*
* Outputs:
* -------
* pWS = (clientList, lastClient)
*
*************************************<->***********************************/
void DeleteEntryFromList (WmWorkspaceData *pWS, ClientListEntry *pListEntry)
{
if (pListEntry->prevSibling)
{
pListEntry->prevSibling->nextSibling = pListEntry->nextSibling;
}
else
{
pWS->pSD->clientList = pListEntry->nextSibling;
}
if (pListEntry->nextSibling)
{
pListEntry->nextSibling->prevSibling = pListEntry->prevSibling;
}
else
{
pWS->pSD->lastClient = pListEntry->prevSibling;
}
} /* END OF FUNCTION DeleteEntryFromList */
/*************************************<->*************************************
*
* DeleteClientFromList (pWS, pCD)
*
*
* Description:
* -----------
* This function deletes a client from the client window list. If this is
* a transient window then it is deleted from its transient window tree.
* If this is a system modal window then clean up the system modal state.
*
*
* Inputs:
* ------
* pCD = pointer to client data for the window to be added to the list
*
* Outputs:
* -------
* pWS = (clientList, lastClient)
*
*************************************<->***********************************/
void DeleteClientFromList (WmWorkspaceData *pWS, ClientData *pCD)
{
#ifdef WSM
WsClientData *pWsc = GetWsClientData (pWS, pCD);
#endif /* WSM */
WmScreenData *pSD = pWS->pSD;
if (pCD->transientLeader)
{
DeleteTransient (pCD);
}
else
{
/*
* If this is a system modal window then clean up the system modal
* state.
*/
if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
{
UndoSystemModalState ();
}
/*
* Remove the client and icon entries from the window list.
*/
#ifdef WSM
if (!pWsc->pIconBox && pWsc->iconFrameWin)
#else /* WSM */
if (!pCD->pIconBox && pCD->iconFrameWin)
#endif /* WSM */
{
if (pCD->iconEntry.prevSibling)
{
pCD->iconEntry.prevSibling->nextSibling =
pCD->iconEntry.nextSibling;
}
else
{
pSD->clientList = pCD->iconEntry.nextSibling;
}
if (pCD->iconEntry.nextSibling)
{
pCD->iconEntry.nextSibling->prevSibling =
pCD->iconEntry.prevSibling;
}
else
{
pSD->lastClient = pCD->iconEntry.prevSibling;
}
}
if (pCD->clientEntry.prevSibling)
{
pCD->clientEntry.prevSibling->nextSibling =
pCD->clientEntry.nextSibling;
}
else
{
pSD->clientList = pCD->clientEntry.nextSibling;
}
if (pCD->clientEntry.nextSibling)
{
pCD->clientEntry.nextSibling->prevSibling =
pCD->clientEntry.prevSibling;
}
else
{
pSD->lastClient = pCD->clientEntry.prevSibling;
}
}
} /* END OF FUNCTION DeleteClientFromList */
/*************************************<->*************************************
*
* AddTransient (pWS, pCD)
*
*
* Description:
* -----------
* This function adds the transient window to the lead window's list of
* transients.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
* pCD = pointer to client data of a transient window
*
*
* Outputs:
* -------
* pCD->transientLeader = (transientChildren, modalCount)
*
*************************************<->***********************************/
void AddTransient (WmWorkspaceData *pWS, ClientData *pCD)
{
ClientData *pcdLeader = pCD->transientLeader;
ClientData *pcdTop = FindTransientTreeLeader (pCD);
Boolean restackTransients;
WmScreenData *pSD = pWS->pSD;
pCD->transientSiblings = pcdLeader->transientChildren;
pcdLeader->transientChildren = pCD;
/*
* Insure that the new transient window is on top of its siblings
* and that the transient window tree is on top of the window
* stack (this is the standard behavior for newly mapped and
* managed windows). If there is a system modal window that the
* transient window is not associated with then don't raise the
* transient tree.
*/
restackTransients = PutTransientOnTop (pCD);
/*
* Handle application modal transient windows
*/
if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
{
/*
* If this is a primary application modal window then increment
* the modal count for transient leaders that are directly up
* the transient tree.
*
* (This is the old MWM_INPUT_APPLICATION_MODAL behavior.)
*/
while (pcdLeader)
{
MarkModalTransient (pcdLeader, pCD);
pcdLeader = pcdLeader->transientLeader;
}
}
else if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
{
/*
* If this is a full application modal window then increment
* the modal count for the rest of the transient tree.
*/
MarkModalSubtree (pcdTop, pCD);
}
else if (pcdTop->fullModalCount)
{
/*
* There is already a full application modal window in the tree
*/
pcdLeader = pCD->transientLeader;
if ((pcdLeader->inputMode != MWM_INPUT_FULL_APPLICATION_MODAL) ||
(IS_APP_MODALIZED(pcdLeader)))
{
/*
* The immediate parent of this transient is not the
* current full application modal window. Set the full
* modal count to the parent's so that they both become
* unmodalized at the same time. This allows a full
* app modal window to have active, non-modal transients.
*/
pCD->fullModalCount = pcdLeader->fullModalCount;
}
}
/*
* Do the actual restacking in the X window stack if necessary.
*/
if ((pSD->clientList != &pcdTop->clientEntry) && !wmGD.systemModalActive)
{
F_Raise (NULL, pCD, NULL);
}
else if (restackTransients)
{
RestackTransientsAtWindow (pCD);
}
else if (pCD != FindTransientOnTop (pcdTop))
{
StackTransientWindow (pCD);
}
} /* END OF FUNCTION AddTransient */
/*************************************<->*************************************
*
* MarkModalSubtree (pcdTree, pcdAvoid)
*
*
* Description:
* -----------
* This function marks the transient tree with pcdTree as its leader.
* If pcdAvoid is in the tree, it is not marked.
*
* Inputs:
* ------
* pcdTree = pointer to client data of the tree to mark
* pcdAvoid = pointer to client data to not mark if in tree
*
*
*************************************<->***********************************/
void MarkModalSubtree (ClientData *pcdTree, ClientData *pcdAvoid)
{
/* Mark children, if any */
if (pcdTree->transientChildren)
MarkModalSubtree (pcdTree->transientChildren, pcdAvoid);
/* Mark this node */
if (pcdTree != pcdAvoid)
{
MarkModalTransient (pcdTree, pcdAvoid);
}
/* Mark siblings */
if (pcdTree->transientSiblings)
MarkModalSubtree (pcdTree->transientSiblings, pcdAvoid);
}
/*************************************<->*************************************
*
* MarkModalTransient (pcdLeader, pCD)
*
*
* Description:
* -----------
* This function marks a transient window for application modal processing.
* Grabs are done to eat up pointer button events.
*
* Inputs:
* ------
* pcdLeader = pointer to client data to mark
* pCD = pointer to client data of new transient
*
*
*************************************<->***********************************/
void MarkModalTransient (ClientData *pcdLeader, ClientData *pCD)
{
if (!IS_APP_MODALIZED(pcdLeader))
{
/*
* Eat pointer button events while application modal.
*/
XGrabButton (DISPLAY, AnyButton, AnyModifier,
pcdLeader->clientBaseWin, True,
ButtonPressMask | ButtonMotionMask, GrabModeAsync,
GrabModeAsync, None, wmGD.workspaceCursor);
}
/* bump application modal count */
if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
pcdLeader->fullModalCount++;
else
pcdLeader->primaryModalCount++;
}
/*************************************<->*************************************
*
* DeleteTransient (pCD)
*
*
* Description:
* -----------
* This function deletes the transient window from the lead window's list
* of transients
*
* Much of the complication of this code arises from trying to handle
* mixtures of both full- and primary-application modal transients.
* It also tries to handle the case where a sequence of application
* modal transients appear in different places in the transient tree
* (i.e. not as descendents of a previously existing full app modal
* transient).
*
* Inputs:
* ------
* pCD = pointer to client data of transient.
*
*************************************<->***********************************/
void DeleteTransient (ClientData *pCD)
{
ClientData *pcdLeader;
ClientData *pcdPrev;
int modalCount;
/*
* Handle primary application modality.
* Reset the modal window counts for the leader windows up through the
* transient window tree.
*/
modalCount = pCD->primaryModalCount;
if (pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
{
modalCount += 1;
}
if (modalCount)
{
pcdLeader = pCD->transientLeader;
while (pcdLeader)
{
if (modalCount)
UnMarkModalTransient (pcdLeader, modalCount, pCD);
pcdLeader = pcdLeader->transientLeader;
}
}
/*
* Handle full application modality.
* Undo application modal windows in a depth first manner.
*/
pcdLeader = FindTransientTreeLeader (pCD);
if (pCD->transientChildren)
{
DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
}
if (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
{
/*
* If this is a full application modal window then decrement
* the modal count for the rest of the transient tree.
*/
FixupFullAppModalCounts (pcdLeader, pCD);
}
/*
* Delete this transient from its parent's list of transient windows.
*/
pcdPrev = pCD->transientLeader->transientChildren;
if(pcdPrev)
{
if (pcdPrev == pCD)
{
pCD->transientLeader->transientChildren = pCD->transientSiblings;
}
else
{
while (pcdPrev && (pcdPrev->transientSiblings != pCD))
{
pcdPrev = pcdPrev->transientSiblings;
}
if (pcdPrev)
pcdPrev->transientSiblings = pCD->transientSiblings;
}
}
} /* END OF FUNCTION DeleteTransient */
/*************************************<->*************************************
*
* DeleteFullAppModalChildren (pcdLeader, pCD)
*
*
* Description:
* -----------
* This function handles the clean-up of nested full application modal
* windows. The deletion has to be handled carefully to keep a correct
* fullModalCount on the transients that remain in the tree.
*
* The algorithm is to traverse the transient children depth first and
* fix up the tree's fullModalCount for each full application modal
* window that's found.
*
* Inputs:
* ------
* pcdLeader = pointer to client data of transient tree root.
* pCD = pointer to client data of transient subtree to delete.
*
*************************************<->***********************************/
void DeleteFullAppModalChildren (ClientData *pcdLeader, ClientData *pCD)
{
/* recursively do children first */
if (pCD->transientChildren)
DeleteFullAppModalChildren (pcdLeader, pCD->transientChildren);
/* do fullAppModal fixup for this guy */
FixupFullAppModalCounts (pcdLeader, pCD);
/* do siblings of passed transient */
if (pCD->transientSiblings)
DeleteFullAppModalChildren (pcdLeader, pCD->transientSiblings);
} /* END OF FUNCTION DeleteFullAppModalChildren */
/*************************************<->*************************************
*
* FixupFullAppModalCounts (pcdLeader, pcdDelete)
*
*
* Description:
* -----------
* This function traverses the entire transient tree (pointed to by
* pcdLeader) and fixes up the fullModalCounts to reflect the removal
* of pcdDelete.
*
* The fix-up consists of decrementing the count
* of the remaining full app modal windows in the tree iff the remaining
* window's fullModalCount is greater than the fullModalCount of the
* transient being deleted.
*
* Inputs:
* ------
* pcdLeader = pointer to client data for head of transient tree.
* pcdDelet = pointer to client data of transient being deleted.
*
*************************************<->***********************************/
void
FixupFullAppModalCounts (ClientData *pcdLeader, ClientData *pcdDelete)
{
/* fixup children */
if (pcdLeader->transientChildren)
{
FixupFullAppModalCounts (pcdLeader->transientChildren, pcdDelete);
}
/*
* fixup leader: decrement the count if it is greater than
* the transient being deleted.
*
*/
if (pcdLeader->fullModalCount > pcdDelete->fullModalCount)
{
UnMarkModalTransient (pcdLeader, 1, pcdDelete);
}
/* fixup siblings */
if (pcdLeader->transientSiblings)
{
FixupFullAppModalCounts (pcdLeader->transientSiblings, pcdDelete);
}
} /* END OF FUNCTION FixupFullAppModalCounts */
/*************************************<->*************************************
*
* UnMarkModalTransient (pcdModee, modalCount, pcdModal)
*
*
* Description:
* -----------
* This function unmarks a transient window for application modal processing.
* Original grabs are restored.
*
* Inputs:
* ------
* pcdModee = pointer to client data for transient to unmark
* pcdModal = pointer to client data for modal transient
* modalCount = amount to decrement the client's modal count by
*
*
*************************************<->***********************************/
void UnMarkModalTransient (ClientData *pcdModee, int modalCount, ClientData *pcdModal)
{
/* decrement application modal count */
if (pcdModal->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)
pcdModee->fullModalCount -= modalCount;
else if (pcdModal->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL)
pcdModee->primaryModalCount -= modalCount;
/*
* Restore original button bindings/grabs if not modal anymore
*/
if (!IS_APP_MODALIZED(pcdModee))
{
XUngrabButton (DISPLAY, AnyButton, AnyModifier,
pcdModee->clientBaseWin);
SetupCButtonBindings (pcdModee->clientBaseWin, BUTTON_SPECS(pcdModee));
if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
(wmGD.keyboardFocus != pcdModee))
{
DoExplicitSelectGrab (pcdModee->clientBaseWin);
}
}
}
/*************************************<->*************************************
*
* PutTransientOnTop (pcd)
*
*
* Description:
* -----------
* This function changes the transient window list to insure that the
* specified transient window is on top of its siblings and its parent
* is on top of its siblings, etc. The sibling list is ordered such
* that the first window in the list is on top of second window in the
* list, etc.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a transient window
*
*
* Outputs:
* -------
* pcdLeader = (transientSiblings)
*
* RETURN = True if the transient tree needs to be restacked
*
*************************************<->***********************************/
Boolean PutTransientOnTop (ClientData *pcd)
{
ClientData *pcdLeader;
ClientData *pcdPrev;
Boolean restack = False;
pcdLeader = pcd->transientLeader;
if (pcdLeader != NULL)
{
pcdPrev = pcdLeader->transientChildren;
if (pcdPrev != pcd)
{
while (pcdPrev->transientSiblings != pcd)
{
pcdPrev = pcdPrev->transientSiblings;
}
pcdPrev->transientSiblings = pcd->transientSiblings;
pcd->transientSiblings = pcdLeader->transientChildren;
pcdLeader->transientChildren = pcd;
restack = True;
}
if (PutTransientOnTop (pcdLeader))
{
restack = True;
}
#ifdef WSM
if (BumpPrimaryToBottom (pcdLeader))
{
restack = True;
}
#endif /* WSM */
}
return (restack);
} /* END OF FUNCTION PutTransientOnTop */
/*************************************<->*************************************
*
* PutTransientBelowSiblings (pcd)
*
*
* Description:
* -----------
* This function changes the transient window list to insure that the
* specified transient window is below its sibling windows.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a transient window
*
*
* Outputs:
* -------
* pcdLeader = (transientSiblings)
*
* RETURN = True if restacking has been done in the transient window tree.
*
*************************************<->***********************************/
Boolean PutTransientBelowSiblings (ClientData *pcd)
{
ClientData *pcdLeader;
ClientData *pcdNext;
Boolean restack = False;
pcdLeader = pcd->transientLeader;
if (pcdLeader)
{
if (pcd->transientSiblings || (pcdLeader->transientChildren != pcd))
{
restack = True;
if (pcdLeader->transientChildren == pcd)
{
pcdLeader->transientChildren = pcd->transientSiblings;
}
pcdNext = pcdLeader->transientChildren;
while (pcdNext->transientSiblings)
{
if (pcdNext->transientSiblings == pcd)
{
pcdNext->transientSiblings = pcd->transientSiblings;
}
else
{
pcdNext = pcdNext->transientSiblings;
}
}
pcdNext->transientSiblings = pcd;
}
pcd->transientSiblings = NULL;
}
return (restack);
} /* END OF FUNCTION PutTransientBelowSiblings */
/*************************************<->*************************************
*
* RestackTransients (pcd)
*
*
* Description:
* -----------
* This function restacks windows in a transient window tree. Secondary
* (transient) windows are stacked on top of their associated primary
* windows and the first secondary window in the transientSiblings list
* is stacked on top of the second window in the list, etc.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree
*
*************************************<->***********************************/
void RestackTransients (ClientData *pcd)
{
ClientData *pcdLeader;
int count;
static int size = 0;
static Window *windows = NULL;
#ifndef WSM
Window *nextWindow;
#endif /* WSM */
XWindowChanges windowChanges;
int i;
int leaderIndex;
/*
* Build a restacking list and do the restacking.
*/
pcdLeader = FindTransientTreeLeader (pcd);
count = CountTransientChildren (pcdLeader);
/* No work to do if no transient children; count includes leader. */
if (count < 2)
return;
if (count > size)
{
/*
* Expand the (static) windows buffer that is used in restacking.
*/
if (!(windows =
(Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
{
/* cannot get memory space */
size = 0;
return;
}
size = count + 5;
}
#ifdef WSM
MakeTransientFamilyStackingList (windows, pcdLeader);
#else /* WSM */
nextWindow = MakeTransientWindowList (windows, pcdLeader);
*nextWindow = pcdLeader->clientFrameWin;
#endif /* WSM */
/*
* Changes for CDExc19397.
* XRestackWindows may move pcdLeader; that messes up the
* global window stack. Call XConfigureWindow() instead,
* and don't change location of pcdLeader.
*/
for (leaderIndex = 0; leaderIndex < count; leaderIndex++)
{
if (windows[leaderIndex] == pcdLeader->clientFrameWin)
break;
}
if (leaderIndex >= count) /* ? Couldn't find leader; should NOT happen. */
leaderIndex = count - 1;
windowChanges.stack_mode = Above;
for (i = leaderIndex; i > 0; i--)
{
windowChanges.sibling = windows[i];
XConfigureWindow (DISPLAY, windows[i - 1],
CWSibling | CWStackMode, &windowChanges);
}
windowChanges.stack_mode = Below;
for (i = leaderIndex; i < count - 1; i++)
{
windowChanges.sibling = windows[i];
XConfigureWindow (DISPLAY, windows[i + 1],
CWSibling | CWStackMode, &windowChanges);
}
} /* END OF FUNCTION RestackTransients */
/*************************************<->*************************************
*
* RestackTransientsAtWindow (pcd)
*
*
* Description:
* -----------
* This function restacks windows in a transient window tree. The
* "anchor point" in the stack for the transient window tree is the
* specified window.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree
*
*************************************<->***********************************/
void RestackTransientsAtWindow (ClientData *pcd)
{
ClientData *pcdLeader;
XWindowChanges windowChanges;
pcdLeader = FindTransientTreeLeader (pcd);
if (pcdLeader && (pcdLeader != pcd))
{
windowChanges.sibling = pcd->clientFrameWin;
windowChanges.stack_mode = Below;
XConfigureWindow (DISPLAY, pcdLeader->clientFrameWin,
CWSibling | CWStackMode, &windowChanges);
}
RestackTransients (pcd);
} /* END OF FUNCTION RestackTransientsAtWindow */
/*************************************<->*************************************
*
* FindTransientTreeLeader (pcd)
*
*
* Description:
* -----------
* This function identifies the leader of the transient tree that
* contains the specified client.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree.
*
* Outputs:
* -------
* RETURN = pointer to the client data for the transient tree leader.
*
*************************************<->***********************************/
ClientData * FindTransientTreeLeader (ClientData *pcd)
{
/*
* Find the head of the transient window tree.
*/
while (pcd->transientLeader)
{
pcd = pcd->transientLeader;
}
return (pcd);
} /* END OF FUNCTION FindTransientTreeLeader */
/*************************************<->*************************************
*
* CountTransientChildren (pcd)
*
*
* Description:
* -----------
* This function returns a count of the number of children in the
* transient window tree headed by the specified client window.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree
*
* Outputs:
* -------
* RETURN = count of transient windows in the transient window tree
*
*************************************<->***********************************/
int
CountTransientChildren (ClientData *pcd)
{
ClientData *pcdNext;
int count = 1;
pcdNext = pcd->transientChildren;
while (pcdNext)
{
if (pcdNext->transientChildren)
{
count += CountTransientChildren (pcdNext);
}
else
{
count++;
}
pcdNext = pcdNext->transientSiblings;
}
return (count);
} /* END OF FUNCTION CountTransientChildren */
/*************************************<->*************************************
*
* MakeTransientWindowList (windows, pcd)
*
*
* Description:
* -----------
* This function makes a transient window list of windows in the
* transient window tree headed by the specified client. This list is
* to be passed to XRestackWindows.
*
*
* Inputs:
* ------
* windows = pointer to the windows list to be filled out
*
* pcd = pointer to client data of a window in a transient tree
*
* Outputs:
* -------
* RETURN = pointer to the next entry in the windows list
*
*************************************<->***********************************/
Window * MakeTransientWindowList (Window *windows, ClientData *pcd)
{
ClientData *pcdNext;
pcdNext = pcd->transientChildren;
while (pcdNext)
{
if (pcdNext->transientChildren)
{
windows = MakeTransientWindowList (windows, pcdNext);
}
*windows = pcdNext->clientFrameWin;
windows++;
pcdNext = pcdNext->transientSiblings;
}
return (windows);
} /* END OF FUNCTION MakeTransientWindowList */
/*************************************<->*************************************
*
* FindTransientFocus (pcd)
*
*
* Description:
* -----------
* This function identifies a window in the transient tree that is headed
* by the specified client that can accept the keyboard input. The
* effect of application modal windows is taken into account.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree.
*
* Outputs:
* -------
* RETURN = pointer to the client data for a window that can accept the
* keyboard input focus.
*
*************************************<->***********************************/
ClientData * FindTransientFocus (ClientData *pcd)
{
ClientData *pcdFocus;
/*
* Find a window that does not have an application modal subordinate.
* First, search descendents
*/
pcdFocus = pcd;
while (pcdFocus->transientChildren && IS_APP_MODALIZED(pcdFocus))
{
pcdFocus = pcdFocus->transientChildren;
}
/*
* If (search of descendents FAILS) then search siblings.
*/
if (IS_APP_MODALIZED(pcdFocus))
{
ClientData *pcdSibling;
pcdFocus = pcd;
while (pcdFocus && IS_APP_MODALIZED(pcdFocus))
{
pcdSibling = pcdFocus;
while (pcdSibling->transientSiblings && IS_APP_MODALIZED(pcdFocus))
{
pcdSibling = pcdSibling->transientSiblings;
}
if (IS_APP_MODALIZED(pcdSibling))
{
pcdFocus = pcdFocus->transientChildren;
}
else
{
pcdFocus = pcdSibling;
break;
}
}
}
return (pcdFocus ? pcdFocus : wmGD.keyboardFocus);
} /* END OF FUNCTION FindTransientFocus */
/*************************************<->*************************************
*
* FindTransientOnTop (pcd)
*
*
* Description:
* -----------
* This function identifies the top-most transient window in the
* transient window tree that contains the specified client.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree.
*
* Outputs:
* -------
* RETURN = pointer to the client data for the top-most transient window.
*
*************************************<->***********************************/
ClientData * FindTransientOnTop (ClientData *pcd)
{
/*
* Find the head of the transient window tree.
*/
pcd = FindTransientTreeLeader (pcd);
#ifdef WSM
if (!(pcd->secondariesOnTop) &&
(LeaderOnTop (pcd)))
{
ClientData *pcdSub;
if (LeaderOnTop (pcd))
{
/* The primary window is on top! */
return (pcd);
}
else
{
pcdSub = FindSubLeaderToTop (pcd);
if (pcdSub)
return (pcdSub);
}
}
#endif /* WSM */
/*
* Find the top-most transient window (the window in the transient tree
* that is highest in the window stack).
*/
while (pcd->transientChildren)
{
pcd = pcd->transientChildren;
}
return (pcd);
} /* END OF FUNCTION FindTransientOnTop */
/*************************************<->*************************************
*
* StackWindow (pWS, pEntry, onTop, pStackEntry)
*
*
* Description:
* -----------
* This function stacks a window of a particular type (normal or icon)
* to the top or botton of the window stack on the screen.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
*
* pEntry = pointer to the client list entry for the window to be restacked.
*
* onTop = if True then the window is to be restacked on top of the
* specified stack window (if the stack window is not specified then
* the entry is added to the top of the window stack)
* otherwise the window is stacked below the specified stack window
* (or at the bottom of the window stack if the stack window is not
* specified).
*
* pStackEntry = pointer to a client list entry for a window in the window
* stack that is to be used as a reference in restacking.
*
*************************************<->***********************************/
void StackWindow (WmWorkspaceData *pWS, ClientListEntry *pEntry, Boolean onTop, ClientListEntry *pStackEntry)
{
Window stackWindow;
Boolean stackTransientTreeWindows = False;
Window activeIconWindow;
Window window;
XWindowChanges changes;
WmScreenData *pSD = pWS->pSD;
if (pStackEntry)
{
if (pStackEntry->type == MINIMIZED_STATE)
{
stackWindow = ICON_FRAME_WIN(pStackEntry->pCD);
}
else
{
stackWindow = pStackEntry->pCD->clientFrameWin;
}
}
else
{
stackWindow = (Window)0;
}
if (pEntry->type == MINIMIZED_STATE)
{
window = ICON_FRAME_WIN(pEntry->pCD);
}
else
{
/*
* Restack the transient tree if appropriate.
*/
if (pEntry->pCD->transientLeader || pEntry->pCD->transientChildren)
{
stackTransientTreeWindows = True;
window = (FindTransientOnTop (pEntry->pCD))->clientFrameWin;
}
else
{
window = pEntry->pCD->clientFrameWin;
}
}
/*
* The active icon text label must be restacked along with the associated
* icon.
*/
if ((pEntry->type == MINIMIZED_STATE) &&
(pEntry->pCD == wmGD.keyboardFocus) &&
(ICON_DECORATION(pEntry->pCD) & ICON_ACTIVE_LABEL_PART) &&
(ACTIVE_ICON_TEXT_WIN))
{
activeIconWindow = ACTIVE_ICON_TEXT_WIN;
}
else
{
activeIconWindow = (Window)0;
}
if (onTop)
{
if ((stackWindow == 0) && (pSD->clientList))
{
if (pSD->clientList->type == MINIMIZED_STATE)
{
stackWindow = ICON_FRAME_WIN(pSD->clientList->pCD);
}
else
{
if (pSD->clientList->pCD->transientChildren)
{
stackWindow =
(FindTransientOnTop(pSD->clientList->pCD))->clientFrameWin;
}
else
{
stackWindow = pSD->clientList->pCD->clientFrameWin;
}
}
}
if (activeIconWindow)
{
changes.sibling = stackWindow;
changes.stack_mode = Above;
XConfigureWindow (DISPLAY, activeIconWindow,
(CWSibling | CWStackMode), &changes);
changes.sibling = activeIconWindow;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
&changes);
}
else
{
changes.sibling = stackWindow;
changes.stack_mode = Above;
XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
&changes);
if (stackTransientTreeWindows)
{
/* make sure that the leader is in the correct spot */
changes.sibling = window;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, pEntry->pCD->clientFrameWin,
(CWSibling | CWStackMode), &changes);
RestackTransients (pEntry->pCD);
}
}
}
else
{
#ifdef WSM
/*
* Adjust stack entry window if we're stacking below a
* transient tree.
*/
if (pStackEntry && pStackEntry->pCD->transientChildren)
{
stackWindow = LowestWindowInTransientFamily (pStackEntry->pCD);
}
#endif /* WSM */
if (stackWindow == 0)
{
if (pSD->lastClient->type == MINIMIZED_STATE)
{
stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
}
else
{
#ifdef WSM
if (pSD->lastClient->pCD->transientChildren)
{
stackWindow =
LowestWindowInTransientFamily (pSD->lastClient->pCD);
}
else
#endif /* WSM */
stackWindow = pSD->lastClient->pCD->clientFrameWin;
}
}
if (activeIconWindow)
{
changes.sibling = stackWindow;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, activeIconWindow,
(CWSibling | CWStackMode), &changes);
changes.sibling = activeIconWindow;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
&changes);
}
else
{
changes.sibling = stackWindow;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, window, (CWSibling | CWStackMode),
&changes);
if (stackTransientTreeWindows)
{
/* make sure that the leader is in the correct spot */
changes.sibling = window;
changes.stack_mode = Below;
XConfigureWindow (DISPLAY, pEntry->pCD->clientFrameWin,
(CWSibling | CWStackMode), &changes);
RestackTransients (pEntry->pCD);
}
}
}
} /* END OF FUNCTION StackWindow */
/*************************************<->*************************************
*
* StackTransientWindow (pcd)
*
*
* Description:
* -----------
* This function stacks a transient window within its transient window
* tree on the screen. The transient window tree should indicate the
* intended stacking position.
*
*
* Inputs:
* ------
* pcd = pointer to client data of a window in a transient tree
*
*************************************<->***********************************/
void StackTransientWindow (ClientData *pcd)
{
XWindowChanges changes;
ClientData *pcdPrev;
if (pcd->transientLeader->transientChildren == pcd)
{
if (pcd->transientSiblings)
{
changes.sibling = pcd->transientSiblings->clientFrameWin;
}
else
{
changes.sibling = pcd->transientLeader->clientFrameWin;
}
changes.stack_mode = Above;
}
else
{
pcdPrev = pcd->transientLeader;
while (pcdPrev->transientSiblings != pcd)
{
pcdPrev = pcdPrev->transientSiblings;
}
changes.sibling = pcdPrev->clientFrameWin;
changes.stack_mode = Below;
}
XConfigureWindow (DISPLAY, pcd->clientFrameWin, (CWSibling | CWStackMode),
&changes);
} /* END OF FUNCTION StackTransientWindow */
/*************************************<->*************************************
*
* CheckIfClientObscuring (pcdTop, pcd)
*
*
* Description:
* -----------
* This function determines whether a window or a transient window tree
* is obscuring (at least partially) a window or a transient window tree
* that is below it in the window stack.
*
*
* Inputs:
* ------
* pcdTop = pointer to client data for a window (it may be the leader of
* a transient tree; this window is the higher in the window stack
* than the window it is be checked against.
*
* pcd = pointer to client data for a window (it may be the leader of
* a transient tree.
*
*
* Outputs:
* -------
* RETURN = True if the top window(s) overlap the lower window(s)
*
*************************************<->***********************************/
Boolean CheckIfClientObscuring (ClientData *pcdTop, ClientData *pcd)
{
Boolean obscuring = False;
ClientData *pcdNext;
/*
* Check only if the top window is visible onscreen.
*/
if (pcdTop->transientChildren && (pcdTop->clientState != MINIMIZED_STATE))
{
pcdNext = pcdTop->transientChildren;
while (pcdNext && !obscuring)
{
obscuring = CheckIfClientObscuring (pcdNext, pcd);
pcdNext = pcdNext->transientSiblings;
}
}
if (!obscuring && pcd->transientChildren &&
(pcd->clientState != MINIMIZED_STATE))
{
pcdNext = pcd->transientChildren;
while (pcdNext && !obscuring)
{
obscuring = CheckIfClientObscuring (pcdTop, pcdNext);
pcdNext = pcdNext->transientSiblings;
}
}
if (!obscuring)
{
obscuring = CheckIfObscuring (pcdTop, pcd);
}
return (obscuring);
} /* END OF FUNCTION CheckIfClientObscuring */
/*************************************<->*************************************
*
* CheckIfObscuring (pcdA, pcdB)
*
*
* Description:
* -----------
* This function determines whether a window (not a transient tree)
* is obscuring (at least partially) a window (not a transient tree)
* that is below it in the window stack.
*
*
* Inputs:
* ------
* pcdA = pointer to client data for a window; this window is higher in
* the window stack than the window it is be checked against.
*
* pcdB = pointer to client data for a window.
*
*
* Outputs:
* -------
* RETURN = True if the top window overlaps the lower window
*
*************************************<->***********************************/
Boolean CheckIfObscuring (ClientData *pcdA, ClientData *pcdB)
{
Boolean obscuring = False;
int aX1;
int aX2;
int aY1;
int aY2;
int bX1;
int bX2;
int bY1;
int bY2;
#ifdef WSM
/*
* For workspace stuff: if either is unseen, then neither
* is obscured.
*/
if ((pcdA->clientState & UNSEEN_STATE) ||
(pcdB->clientState & UNSEEN_STATE))
{
return (False);
}
#endif /* WSM */
if (pcdA->clientState == NORMAL_STATE)
{
aX1 = pcdA->clientX - pcdA->clientOffset.x;
aY1 = pcdA->clientY - pcdA->clientOffset.y;
aX2 = aX1 + pcdA->clientWidth + (2 * pcdA->clientOffset.x) - 1;
aY2 = aY1 + pcdA->clientHeight + pcdA->clientOffset.y +
pcdA->clientOffset.x - 1;
}
else if (pcdA->clientState == MINIMIZED_STATE)
{
aX1 = ICON_X(pcdA);
aY1 = ICON_Y(pcdA);
aX2 = aX1 + ICON_WIDTH(pcdA) - 1;
aY2 = aY1 + ICON_HEIGHT(pcdA) - 1;
}
else /* (pcdA->clientState == MAXIMIZED_STATE) */
{
aX1 = pcdA->maxX - pcdA->clientOffset.x;
aY1 = pcdA->maxY - pcdA->clientOffset.y;
aX2 = aX1 + pcdA->maxWidth + (2 * pcdA->clientOffset.x) - 1;
aY2 = aY1 + pcdA->maxHeight + pcdA->clientOffset.y +
pcdA->clientOffset.x - 1;
}
if (pcdB->clientState == NORMAL_STATE)
{
bX1 = pcdB->clientX - pcdB->clientOffset.x;
bY1 = pcdB->clientY - pcdB->clientOffset.y;
bX2 = bX1 + pcdB->clientWidth + (2 * pcdB->clientOffset.x) - 1;
bY2 = bY1 + pcdB->clientHeight + pcdB->clientOffset.y +
pcdB->clientOffset.x - 1;
}
else if (pcdB->clientState == MINIMIZED_STATE)
{
bX1 = ICON_X(pcdB);
bY1 = ICON_Y(pcdB);
bX2 = bX1 + ICON_WIDTH(pcdB) - 1;
bY2 = bY1 + ICON_HEIGHT(pcdB) - 1;
}
else /* (pcdB->clientState == MAXIMIZED_STATE) */
{
bX1 = pcdB->maxX - pcdB->clientOffset.x;
bY1 = pcdB->maxY - pcdB->clientOffset.y;
bX2 = bX1 + pcdB->maxWidth + (2 * pcdB->clientOffset.x) - 1;
bY2 = bY1 + pcdB->maxHeight + pcdB->clientOffset.y +
pcdB->clientOffset.x - 1;
}
/*
* Check if there is overlap in both dimensions.
*/
if (((aX1 >= bX1) && (aX1 <= bX2)) || ((aX2 >= bX1) && (aX2 <= bX2)) ||
((bX1 >= aX1) && (bX1 <= aX2)) || ((bX2 >= aX1) && (bX2 <= aX2)))
{
if (((aY1 >= bY1) && (aY1 <= bY2)) || ((aY2 >= bY1) && (aY2 <= bY2)) ||
((bY1 >= aY1) && (bY1 <= aY2)) || ((bY2 >= aY1) && (bY2 <= aY2)))
{
obscuring = True;
}
}
return (obscuring);
} /* END OF FUNCTION CheckIfObscuring */
/*************************************<->*************************************
*
* CheckIfClientObscuredByAny (pcd)
*
*
* Description:
* -----------
* This function determines whether a window or a transient window tree
* is obscured (at least partially) by any other window.
*
*
* Inputs:
* ------
* pcd = pointer to client data for a window (it may be the leader of
* a transient tree.
*
*
* Outputs:
* -------
* RETURN = True if the window(s) are overlapped.
*
*************************************<->***********************************/
Boolean CheckIfClientObscuredByAny (ClientData *pcd)
{
Boolean obscured = False;
ClientListEntry *pListEntry;
pListEntry = ACTIVE_PSD->clientList;
while (pListEntry && !obscured)
{
if (pListEntry->pCD == pcd)
{
if (((pListEntry->type == MINIMIZED_STATE) &&
(pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
((pListEntry->type != MINIMIZED_STATE) &&
(pListEntry->pCD->clientState != MINIMIZED_STATE)))
{
pListEntry = NULL;
}
}
else if (((pListEntry->type == MINIMIZED_STATE) &&
(pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
((pListEntry->type != MINIMIZED_STATE) &&
(pListEntry->pCD->clientState != MINIMIZED_STATE)))
{
/*
* The window for the entry is visible on screen. See if it
* obscures the indicated window.
*/
obscured = CheckIfClientObscuring (pListEntry->pCD, pcd);
}
if (pListEntry)
{
pListEntry = pListEntry->nextSibling;
}
}
return (obscured);
} /* END OF FUNCTION CheckIfClientObscuredByAny */
/*************************************<->*************************************
*
* CheckIfClientObscuringAny (pcd)
*
*
* Description:
* -----------
* This function determines whether a window or a transient window tree
* is obscuring another window.
*
*
* Inputs:
* ------
* pcd = pointer to client data for a window (it may be the leader of
* a transient tree.
*
*
* Outputs:
* -------
* RETURN = True if the window(s) overlaps anther window.
*
*************************************<->***********************************/
Boolean CheckIfClientObscuringAny (ClientData *pcd)
{
Boolean obscuring = False;
ClientListEntry *pListEntry;
pListEntry = (pcd->clientState == MINIMIZED_STATE) ?
&pcd->iconEntry : &pcd->clientEntry;
while (pListEntry && !obscuring)
{
if ((pListEntry->pCD != pcd) &&
(((pListEntry->type == MINIMIZED_STATE) &&
(pListEntry->pCD->clientState == MINIMIZED_STATE)) ||
((pListEntry->type != MINIMIZED_STATE) &&
(pListEntry->pCD->clientState != MINIMIZED_STATE))))
{
obscuring = CheckIfClientObscuring (pcd, pListEntry->pCD);
}
pListEntry = pListEntry->nextSibling;
}
return (obscuring);
} /* END OF FUNCTION CheckIfClientObscuringAny */
/*************************************<->*************************************
*
* SetupSystemModalState (pCD)
*
*
* Description:
* -----------
* This function prepares for mapping a system modal window. An input
* screen window is mapped below the system modal window to prevent input
* to the windows not related to the system modal window.
*
*
* Inputs:
* ------
* pCD = pointer to client data for the system modal window; if NULL the
* system modal window is a special window manager dialog box
*
*
* Outputs:
* -------
* wmGD = changes to system modal state data
*
*************************************<->***********************************/
void SetupSystemModalState (ClientData *pCD)
{
XWindowChanges windowChanges;
unsigned int width, height;
unsigned int x_hot, y_hot;
unsigned char *bits;
unsigned char *mask_bits;
WmScreenData *pSD;
int scr;
/*
* If we've got a menu active, then unpost it first
* so that grabs from the menu don't interfere with
* the system modal dialog. We want to avoid lock-ups.
*/
if (wmGD.menuActive != NULL)
{
UnpostMenu (wmGD.menuActive);
XSync (DISPLAY, False);
}
/*
* Try to grab the pointer and keyboard. If either
* fails because event processing is frozen by another grab, then
* don't do system modal for fear of leaving the system unusable.
*/
if (XGrabPointer(DISPLAY,
ROOT_FOR_CLIENT(pCD),
FALSE, /* owner_events */
(unsigned int) 0, /* event mask */
GrabModeAsync, /* pointer_mode */
GrabModeAsync, /* keyboard_mode */
None, /* confine_to window */
None, /* cursor */
CurrentTime) == GrabFrozen)
{
return;
}
else
{
XUngrabPointer (DISPLAY, CurrentTime);
}
if (XGrabKeyboard(DISPLAY,
ROOT_FOR_CLIENT(pCD),
FALSE, /* owner_events */
GrabModeAsync, /* pointer_mode */
GrabModeAsync, /* keyboard_mode */
CurrentTime) == GrabFrozen)
{
return;
}
else
{
XUngrabKeyboard (DISPLAY, CurrentTime);
}
#ifdef LARGECURSORS
if (wmGD.useLargeCursors)
{
width = noenter32_width;
height = noenter32_height;
x_hot = noenter32_x_hot;
y_hot = noenter32_y_hot;
bits = noenter32_bits;
mask_bits = noenter32m_bits;
}
else
#endif /* LARGECURSORS */
{
width = noenter16_width;
height = noenter16_height;
x_hot = noenter16_x_hot;
y_hot = noenter16_y_hot;
bits = noenter16_bits;
mask_bits = noenter16m_bits;
}
for (scr=0; scr<wmGD.numScreens; scr++)
{
pSD = &(wmGD.Screens[scr]);
/*
* Make the system modal input screen window if necessary.
*/
if (pSD->managed && pSD->inputScreenWindow == 0)
{
XSetWindowAttributes windowAttributes;
Pixmap pixmap;
Pixmap maskPixmap;
XColor xcolors[2];
windowAttributes.event_mask = ButtonPressMask;
if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
{
windowAttributes.event_mask |= EnterWindowMask;
}
windowAttributes.override_redirect = True;
pixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow,
(char *)bits, width, height);
maskPixmap = XCreateBitmapFromData (DISPLAY, pSD->rootWindow,
(char *)mask_bits, width, height);
xcolors[0].pixel = BlackPixel (DISPLAY, pSD->screen);
xcolors[1].pixel = WhitePixel (DISPLAY, pSD->screen);
XQueryColors (DISPLAY, DefaultColormap (DISPLAY, pSD->screen),
xcolors, 2);
windowAttributes.cursor =
XCreatePixmapCursor (DISPLAY, pixmap, maskPixmap,
&(xcolors[0]), &(xcolors[1]),
x_hot, y_hot);
XFreePixmap (DISPLAY, pixmap);
XFreePixmap (DISPLAY, maskPixmap);
pSD->inputScreenWindow =
XCreateWindow (DISPLAY, pSD->rootWindow, 0, 0,
DisplayWidth (DISPLAY, pSD->screen),
DisplayHeight (DISPLAY, pSD->screen),
0,
0,
InputOnly,
CopyFromParent,
CWEventMask | CWOverrideRedirect | CWCursor,
&windowAttributes);
}
if (pSD->managed && pSD != ACTIVE_PSD)
{
XMapRaised (DISPLAY, pSD->inputScreenWindow);
}
}
if (pCD)
{
wmGD.systemModalWindow = pCD->clientFrameWin;
}
else
{
/*
* ELSE: the system modal window is a special window manager dialog
* box and wmGD.systemModalWindow is set prior to the call to
* SetupSystemModalState. Set the focus to the special window manager
* dialog box.
*/
SetKeyboardFocus (NULL, REFRESH_LAST_FOCUS);
XSetInputFocus (DISPLAY, wmGD.systemModalWindow, RevertToPointerRoot,
CurrentTime);
}
/*
* Map the system modal input screen window below the system modal
* window.
*/
windowChanges.sibling = wmGD.systemModalWindow;
windowChanges.stack_mode = Below;
XConfigureWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow,
CWSibling | CWStackMode, &windowChanges);
XMapWindow (DISPLAY, ACTIVE_PSD->inputScreenWindow);
/*
* Setup the system modal global data.
*/
wmGD.systemModalActive = True;
wmGD.systemModalClient = pCD;
} /* END OF FUNCTION SetupSystemModalState */
/*************************************<->*************************************
*
* UndoSystemModalState ()
*
*
* Description:
* -----------
* This function cleans up after a system modal window goes away.
*
*
* Inputs:
* ------
* wmGD = (system modal state data)
*
*
* Outputs:
* -------
* wmGD = changes to system modal state data
*
*************************************<->***********************************/
void UndoSystemModalState (void)
{
int scr;
/*
* Unmap the system modal input screen window.
*/
for (scr = 0; scr < wmGD.numScreens; scr++)
{
if(wmGD.Screens[scr].managed)
{
XUnmapWindow (DISPLAY, wmGD.Screens[scr].inputScreenWindow);
}
}
/*
* Reset the focus if a window manager system modal dialog box was
* being displayed.
*/
if (!wmGD.systemModalClient)
{
AutoResetKeyFocus (NULL, GetTimestamp());
}
/*
* Reset the system modal global data.
*/
wmGD.systemModalActive = False;
wmGD.systemModalClient = NULL;
wmGD.systemModalWindow = 0;
} /* END OF FUNCTION UndoSystemModalState */
/*************************************<->*************************************
*
* FindClientNameMatch (pStartingEntry, toNext, clientName, types)
*
*
* Description:
* -----------
* This function searches for a client that has a particular name or class.
* A match will be indicated if the client with the name or class also
* is in a particular state.
*
*
* Inputs:
* ------
* pEntry = pointer to the client list entry where the search is
* to begin.
*
* toNext = if True then search client list from first to last; otherwise
* search the client list last to first.
*
* clientName = string that indicates a client name or class.
*
* type = types of objects (icon, window, ...) that are to be matched.
*
*
* Outputs:
* -------
* RETURN = pointer to client list entry for matched client.
*
*************************************<->***********************************/
ClientListEntry * FindClientNameMatch (ClientListEntry *pEntry,
Boolean toNext,
String clientName,
unsigned long types)
{
Boolean foundMatch = False;
Boolean checkEntry;
ClientData *pCD;
while (!foundMatch && pEntry)
{
checkEntry = False;
pCD = pEntry->pCD;
if (pEntry->type == MINIMIZED_STATE)
{
if ((pCD->clientState == MINIMIZED_STATE) &&
(types & F_GROUP_ICON))
{
checkEntry = True;
}
}
else
{
if ((pCD->clientState != MINIMIZED_STATE) &&
(types & F_GROUP_WINDOW))
{
checkEntry = True;
}
}
if (checkEntry &&
((pCD->clientName && (strcmp (clientName,pCD->clientName) == 0)) ||
(pCD->clientClass && (strcmp (clientName,pCD->clientClass) == 0))))
{
foundMatch = True;
}
else
{
pEntry = (toNext) ? pEntry->nextSibling : pEntry->prevSibling;
}
}
return (pEntry);
} /* END OF FUNCTION FindClientNameMatch */
#ifdef WSM
/*************************************<->*************************************
*
* BumpPrimaryToTop (pcdLeader)
*
*
* Description:
* -----------
* This function moves the primary window to the "top" of the transient
* tree.
*
* Inputs:
* ------
* pcdLeader = pointer to client data of transient tree root.
*
* Returns: True if stacking order of leader window changed.
* False if not stacking change.
*
* Comments:
* ---------
* This affects only the clientData structures. There is no immediate
* effect on the actual stacking order on the display. That is done
* by StackWindow and/or RestackTransients.
*
*************************************<->***********************************/
Boolean BumpPrimaryToTop (ClientData *pcdLeader)
{
int count;
Boolean rval;
count = CountTransientChildren (pcdLeader);
if (pcdLeader->primaryStackPosition != (count-1))
{
pcdLeader->primaryStackPosition = count - 1;
rval = True;
}
else
{
rval = False;
}
return (rval);
}
/*************************************<->*************************************
*
* BumpPrimaryToBottom (pcdLeader)
*
*
* Description:
* -----------
* This function moves the primary window to the "bottom" of the transient
* tree.
*
* Inputs:
* ------
* pcdLeader = pointer to client data of transient tree root.
*
* Returns: True if stacking order of leader window changed.
* False if not stacking change.
*
* Comments:
* ---------
* This affects only the clientData structures. There is no immediate
* effect on the actual stacking order on the display. That is done
* by StackWindow and/or RestackTransients.
*
*************************************<->***********************************/
Boolean BumpPrimaryToBottom (ClientData *pcdLeader)
{
Boolean rval;
if (pcdLeader->primaryStackPosition != 0)
{
pcdLeader->primaryStackPosition = 0;
rval = True;
}
else
{
rval = False;
}
return (rval);
}
/*************************************<->*************************************
*
* LowestWindowInTransientFamily (pcdLeader)
*
*
* Description:
* -----------
* This function returns the lowest stacked window in a transient
* tree family.
*
* Inputs:
* ------
* pcdLeader = pointer to client data of leader of a transient tree
*
* Returns: id of lowest window in the transient tree for this family
*
*************************************<->***********************************/
Window
LowestWindowInTransientFamily (ClientData *pcdLeader)
{
int count;
static int size = 0;
static Window *windows = NULL;
Window wReturn = None;
/*
* Build a window list
*/
count = CountTransientChildren (pcdLeader);
if (count > size)
{
/*
* Expand the (static) windows buffer
*/
if (!(windows =
(Window *)WmMalloc ((char*)windows, (count + 5) * sizeof (Window))))
{
/* cannot get memory space */
size = 0;
return;
}
size = count + 5;
}
MakeTransientFamilyStackingList (windows, pcdLeader);
if (count > 0)
{
wReturn = windows[count-1];
}
else
{
wReturn = None;
}
return (wReturn);
} /* END OF FUNCTION LowestWindowInTransientFamily */
/*************************************<->*************************************
*
* FindSubLeaderToTop (pcd)
*
*
* Description:
* -----------
* This function identifies a candidate window to top within the
* transient tree that is a local transient leader (the window has
* transients hanging off of it, too).
*
*
* Inputs:
* ------
* pcd = pointer to client data of a transient leader window
*
* Return: ptr to client data for client that should be topped, or NULL
*
*
* Comments:
* --------
*
*************************************<->***********************************/
ClientData *
FindSubLeaderToTop (
ClientData *pcd)
{
ClientData *pcdRet = NULL;
ClientData *pcdNext;
pcdNext = pcd->transientChildren;
while (pcdNext && (!pcdRet))
{
if (pcdNext->transientChildren)
{
if (LeaderOnTop (pcdNext))
{
pcdRet = pcdNext;
}
else
{
pcdRet = FindSubLeaderToTop (pcdNext);
}
}
pcdNext = pcdNext->transientSiblings;
}
return (pcdRet);
}
/*************************************<->*************************************
*
* MakeTransientFamilyStackingList (windows, pcdLeader)
*
*
* Description:
* -----------
* This function makes a transient window list of windows in the
* transient window tree headed by the specified client.
*
*
* Inputs:
* ------
* windows = pointer to the windows list to be filled out
*
* pcdLeader = pointer to client data of a window in a transient tree
*
* Outputs:
* -------
* The windows array is modified.
*
* Comments:
* --------
* This function puts the transient leader window in the list in the
* right place.
*
*************************************<->***********************************/
void
MakeTransientFamilyStackingList (
Window *windows,
ClientData *pcdLeader)
{
ClientData *pcdNext, *pcdSub;
Window *nextWindow, wSave, wTemp, wTop;
int count = CountTransientChildren (pcdLeader);
register int i, j;
/*
* Construct the transient stacking list according to
* normal Motif rules.
*/
nextWindow = MakeTransientWindowList (windows, pcdLeader);
if (!(pcdLeader->secondariesOnTop))
{
/*
* If the leader window shouldn't be on the bottom , then
* adjust the stacking of the list.
*/
if ((pcdLeader->primaryStackPosition > 0) &&
(pcdLeader->primaryStackPosition < count))
{
for (i=0; i<pcdLeader->primaryStackPosition; i++)
{
j = count - i - 1;
windows[j] = windows[j-1];
}
j = count - pcdLeader->primaryStackPosition - 1;
windows[j] = pcdLeader->clientFrameWin;
}
else
{
/*
* Put the leader at the bottom.
*/
*nextWindow = pcdLeader->clientFrameWin;
/*
* If one of the transients is also a local leader
* and wants to be on top, then adjust the list.
*/
pcdSub = FindSubLeaderToTop (pcdLeader);
if (pcdSub && (pcdSub->clientFrameWin != None))
{
/* insert this window at top */
wTop = wSave = pcdSub->clientFrameWin;
/* shuffle the rest down */
for (i=0; i<count; i++)
{
wTemp = windows[i];
windows[i] = wSave;
wSave = wTemp;
if (wTop == wSave)
break;
}
}
}
}
else
{
/*
* Put the leader at the bottom.
*/
*nextWindow = pcdLeader->clientFrameWin;
}
} /* END OF FUNCTION MakeTransientFamilyStackingList */
/*************************************<->*************************************
*
* NormalizeTransientTreeStacking (pcdLeader)
*
*
* Description:
* -----------
* This function traverses the transient tree and cleans up any
* local primary windows that are above their respective secondary
* windows.
*
*
* Inputs:
* ------
* pcdLeader = pointer to client data of a transient tree leader
*
* Return: True if any changes in stacking order were made
*
*
* Comments:
* --------
* This only touches the data structures.
*
*************************************<->***********************************/
Boolean
NormalizeTransientTreeStacking (
ClientData *pcdLeader)
{
ClientData *pcdNext;
Boolean bChanged = False;
pcdNext = pcdLeader->transientChildren;
bChanged = BumpPrimaryToBottom (pcdLeader);
while (pcdNext)
{
if (pcdNext->transientChildren)
{
bChanged |= BumpPrimaryToBottom (pcdNext);
bChanged |= NormalizeTransientTreeStacking (pcdNext);
}
pcdNext = pcdNext->transientSiblings;
}
return (bChanged);
}
/*************************************<->*************************************
*
* LeaderOnTop (pcdLeader)
*
*
* Description:
* -----------
* This function tests a leader of a transient (sub) tree to see if
* it should be on top of its transient windows.
*
*
* Inputs:
* ------
* pcdLeader = pointer to client data of a transient tree leader
*
* Return: True if this leader is on top of its transients
*
*
* Comments:
* --------
*
*************************************<->***********************************/
Boolean
LeaderOnTop (
ClientData *pcdLeader)
{
Boolean bOnTop = False;
int count = CountTransientChildren (pcdLeader);
if ((pcdLeader->primaryStackPosition > 0) &&
(pcdLeader->primaryStackPosition < count))
{
bOnTop = True;
}
return (bOnTop);
}
#endif /* WSM */