2781 lines
66 KiB
C
2781 lines
66 KiB
C
/*
|
||
* CDE - Common Desktop Environment
|
||
*
|
||
* Copyright (c) 1993-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 libraries and programs; if not, write
|
||
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
||
* Floor, Boston, MA 02110-1301 USA
|
||
*/
|
||
/*
|
||
* (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
|
||
* ALL RIGHTS RESERVED
|
||
*/
|
||
/*
|
||
* Motif Release 1.2.3
|
||
*/
|
||
/*
|
||
* (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"
|
||
|
||
/*
|
||
* include extern functions
|
||
*/
|
||
#include "WmWinList.h"
|
||
#include "WmCEvent.h"
|
||
#include "WmEvent.h"
|
||
#include "WmFunction.h"
|
||
#include "WmKeyFocus.h"
|
||
#include "WmMenu.h"
|
||
#include "WmResource.h"
|
||
#include "WmWinInfo.h"
|
||
#include "WmWrkspace.h"
|
||
|
||
#include <X11/bitmaps/xm_noenter16>
|
||
#include <X11/bitmaps/xm_noenter16m>
|
||
#include <X11/bitmaps/xm_noenter32>
|
||
#include <X11/bitmaps/xm_noenter32m>
|
||
|
||
|
||
/*
|
||
* 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;
|
||
WsClientData *pWsc = GetWsClientData (pWS, pCD);
|
||
|
||
|
||
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);
|
||
}
|
||
|
||
|
||
if (!pWsc->pIconBox && pWsc->iconFrameWin)
|
||
{
|
||
/*
|
||
* Put the icon on the bottom of the stack.
|
||
*/
|
||
|
||
if (pSD->lastClient->type == MINIMIZED_STATE)
|
||
{
|
||
WsClientData *pWsib;
|
||
|
||
pWsib = &pSD->lastClient->pCD->pWsList[0];
|
||
windowChanges.sibling = pWsib->iconFrameWin;
|
||
}
|
||
else
|
||
{
|
||
windowChanges.sibling = pSD->lastClient->pCD->clientFrameWin;
|
||
}
|
||
windowChanges.stack_mode = Below;
|
||
XConfigureWindow (DISPLAY, pWsc->iconFrameWin,
|
||
CWSibling | CWStackMode, &windowChanges);
|
||
|
||
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)
|
||
{
|
||
WsClientData *pWsc = GetWsClientData (pWS, pCD);
|
||
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.
|
||
*/
|
||
|
||
if (!pWsc->pIconBox && pWsc->iconFrameWin)
|
||
{
|
||
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;
|
||
}
|
||
if (BumpPrimaryToBottom (pcdLeader))
|
||
{
|
||
restack = True;
|
||
}
|
||
}
|
||
|
||
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;
|
||
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;
|
||
}
|
||
|
||
MakeTransientFamilyStackingList (windows, pcdLeader);
|
||
|
||
/*
|
||
* 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);
|
||
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);
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* 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
|
||
{
|
||
/*
|
||
* Adjust stack entry window if we're stacking below a
|
||
* transient tree.
|
||
*/
|
||
if (pStackEntry && pStackEntry->pCD->transientChildren)
|
||
{
|
||
stackWindow = LowestWindowInTransientFamily (pStackEntry->pCD);
|
||
}
|
||
|
||
if (stackWindow == 0)
|
||
{
|
||
if (pSD->lastClient->type == MINIMIZED_STATE)
|
||
{
|
||
stackWindow = ICON_FRAME_WIN(pSD->lastClient->pCD);
|
||
}
|
||
else
|
||
{
|
||
if (pSD->lastClient->pCD->transientChildren)
|
||
{
|
||
stackWindow =
|
||
LowestWindowInTransientFamily (pSD->lastClient->pCD);
|
||
}
|
||
else
|
||
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;
|
||
|
||
/*
|
||
* For workspace stuff: if either is unseen, then neither
|
||
* is obscured.
|
||
*/
|
||
if ((pcdA->clientState & UNSEEN_STATE) ||
|
||
(pcdB->clientState & UNSEEN_STATE))
|
||
{
|
||
return (False);
|
||
}
|
||
|
||
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 */
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* 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 None;
|
||
}
|
||
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 *pcdSub;
|
||
Window *nextWindow, wSave, wTemp, wTop;
|
||
int count = CountTransientChildren (pcdLeader);
|
||
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);
|
||
}
|
||
|