1498 lines
34 KiB
C
1498 lines
34 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 HEWLETT-PACKARD COMPANY */
|
||
|
||
/*
|
||
* Included Files:
|
||
*/
|
||
|
||
#include "WmGlobal.h"
|
||
/*
|
||
* include extern functions
|
||
*/
|
||
#include "WmKeyFocus.h"
|
||
#include "WmCDecor.h"
|
||
#include "WmColormap.h"
|
||
#include "WmEvent.h"
|
||
#include "WmCEvent.h"
|
||
#include "WmFunction.h"
|
||
#include "WmIDecor.h"
|
||
#include "WmProtocol.h"
|
||
#include "WmWinInfo.h"
|
||
#include "WmWinList.h"
|
||
|
||
|
||
|
||
/*
|
||
* Global Variables:
|
||
*/
|
||
|
||
static Boolean removeSelectGrab = True;
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* InitKeyboardFocus ()
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function sets the keyboard input focus to a client window or icon
|
||
* when the window manager starts up.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* wmGD = (keyboardFocusPolicy, colormapFocusPolicy)
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void InitKeyboardFocus (void)
|
||
{
|
||
ClientData *pCD;
|
||
Boolean sameScreen;
|
||
Boolean focusSet = False;
|
||
int scr;
|
||
int junk;
|
||
Window junk_win, root_returned;
|
||
int currentX, currentY;
|
||
|
||
|
||
/*
|
||
* Set the keyboard focus based on the keyboard focus policy.
|
||
*/
|
||
|
||
wmGD.keyboardFocus = NULL;
|
||
wmGD.nextKeyboardFocus = NULL;
|
||
|
||
for (scr = 0; scr < wmGD.numScreens; scr++)
|
||
{
|
||
if (wmGD.Screens[scr].managed)
|
||
{
|
||
wmGD.Screens[scr].focusPriority = 0;
|
||
|
||
if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
|
||
{
|
||
/*
|
||
* Set the keyboard focus to the window that
|
||
* currently contains the pointer.
|
||
*/
|
||
|
||
pCD = GetClientUnderPointer (&sameScreen);
|
||
|
||
if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
|
||
{
|
||
/*
|
||
* Do some colormap installation that has been
|
||
* deferred from the InitColormapFocus routine.
|
||
*/
|
||
|
||
SetColormapFocus (ACTIVE_PSD, pCD);
|
||
}
|
||
|
||
if (pCD)
|
||
{
|
||
Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
|
||
focusSet = True;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ButtonSpec *buttonSpec;
|
||
|
||
/*
|
||
* Prepare to do explicit selection button grabs.
|
||
*/
|
||
|
||
buttonSpec = wmGD.Screens[scr].buttonSpecs;
|
||
while (buttonSpec)
|
||
{
|
||
if ((buttonSpec->button == FOCUS_SELECT_BUTTON) &&
|
||
(buttonSpec->context & F_CONTEXT_WINDOW) &&
|
||
(buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
|
||
{
|
||
if (buttonSpec->state == 0)
|
||
{
|
||
removeSelectGrab = False;
|
||
}
|
||
}
|
||
buttonSpec = buttonSpec->nextButtonSpec;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (!focusSet)
|
||
{
|
||
/*
|
||
* This is keyboard focus policy is either "explicit" or it it
|
||
* "pointer"
|
||
* and there is no window under the pointer. No window currently has
|
||
* the keyboard input focus. Set the keyboard focus to the window
|
||
* manager default (non-client) OR to the last client with focus.
|
||
*
|
||
* In Mwm 1.1.4 and later, calling Do_Focus_Key with NULL will try
|
||
* to find a 'reasonable' window to put focus. This means that on
|
||
* startup and restarts, a Mwm window will have focus! Yeah!
|
||
*/
|
||
|
||
/*
|
||
* Set Active Screen First
|
||
*/
|
||
if (XQueryPointer(DISPLAY, DefaultRootWindow(DISPLAY),
|
||
&root_returned, &junk_win,
|
||
¤tX, ¤tY,
|
||
&junk, &junk, (unsigned int *)&junk))
|
||
{
|
||
for (scr = 0; scr < wmGD.numScreens; scr++)
|
||
{
|
||
if (wmGD.Screens[scr].managed &&
|
||
wmGD.Screens[scr].rootWindow == root_returned)
|
||
{
|
||
SetActiveScreen(&(wmGD.Screens[scr]));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
Do_Focus_Key ((ClientData *)NULL, CurrentTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
|
||
} /* END OF FUNCTION InitKeyboardFocus */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* SetKeyboardFocus (pCD, focusFlags)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to handle a client window getting the input
|
||
* focus (as the RESULT of an XSetInput call - probably done by
|
||
* Do_Focus_Key).
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to client data for window that is to get the focus
|
||
*
|
||
* focusFlags = flags that indicate focus change details
|
||
* {REFRESH_LAST_FOCUS}
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* wmGD = (keyboardFocus)
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void SetKeyboardFocus (ClientData *pCD, long focusFlags)
|
||
{
|
||
ClientData *currentFocus;
|
||
|
||
|
||
/*
|
||
* Don't set the keyboard input focus if it is already set to
|
||
* the client window.
|
||
*/
|
||
|
||
if (wmGD.keyboardFocus == pCD)
|
||
{
|
||
return;
|
||
}
|
||
currentFocus = wmGD.keyboardFocus;
|
||
ACTIVE_PSD->focusPriority++;
|
||
|
||
|
||
/*
|
||
* If the keyboard input focus policy is "explicit" then reset the
|
||
* selection button event handling.
|
||
*/
|
||
|
||
if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
|
||
{
|
||
/*
|
||
* Reset explicit focus selection event tracking on the last focus
|
||
* window (reset the passive grab on the focus button).
|
||
*/
|
||
|
||
if (currentFocus)
|
||
{
|
||
ResetExplicitSelectHandling (currentFocus);
|
||
wmGD.keyboardFocus = NULL;
|
||
}
|
||
|
||
if (pCD && ((pCD->clientState == NORMAL_STATE) ||
|
||
(pCD->clientState == MAXIMIZED_STATE)))
|
||
{
|
||
/*
|
||
* The focus is to be set to a client window (not the root).
|
||
* Stop explicit focus selection event tracking on the new focus
|
||
* window.
|
||
*/
|
||
|
||
if (removeSelectGrab)
|
||
{
|
||
WmUngrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0,
|
||
pCD->clientBaseWin);
|
||
}
|
||
}
|
||
}
|
||
|
||
wmGD.keyboardFocus = pCD;
|
||
|
||
|
||
/*
|
||
* Do focus auto raise if specified.
|
||
*/
|
||
|
||
if (pCD && pCD->focusAutoRaise)
|
||
{
|
||
if (wmGD.autoRaiseDelay &&
|
||
(wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER))
|
||
{
|
||
AddWmTimer (TIMER_RAISE, (unsigned long)wmGD.autoRaiseDelay,
|
||
pCD);
|
||
}
|
||
else
|
||
{
|
||
Boolean sameScreen;
|
||
|
||
if (((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
|
||
(!pCD->focusAutoRaiseDisabled)) ||
|
||
((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
|
||
(pCD == GetClientUnderPointer (&sameScreen))))
|
||
{
|
||
Do_Raise (pCD, (ClientListEntry *)NULL, STACK_NORMAL);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* Clear the focus indication if it is set for a client window or icon.
|
||
*/
|
||
|
||
if (currentFocus)
|
||
{
|
||
ClearFocusIndication (currentFocus,
|
||
((focusFlags & REFRESH_LAST_FOCUS) ? True : False));
|
||
}
|
||
|
||
|
||
/*
|
||
* Install the client window colormap if the colormap focus policy is
|
||
* "keyboard".
|
||
*/
|
||
|
||
if ((wmGD.colormapFocusPolicy == CMAP_FOCUS_KEYBOARD) &&
|
||
(!(focusFlags & SCREEN_SWITCH_FOCUS)))
|
||
{
|
||
SetColormapFocus (ACTIVE_PSD, pCD);
|
||
}
|
||
|
||
|
||
/*
|
||
* Set the focus window or icon visual indication.
|
||
*/
|
||
|
||
if (pCD)
|
||
{
|
||
pCD->focusPriority = ACTIVE_PSD->focusPriority;
|
||
SetFocusIndication (pCD);
|
||
}
|
||
|
||
} /* END OF FUNCTION SetKeyboardFocus */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* ResetExplicitSelectHandling (pCD)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function resets the selection button event handling for a client
|
||
* window or icon. This applies only if the keyboard focus policy is
|
||
* "explicit".
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to client data for window that has focus handling reset
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void ResetExplicitSelectHandling (ClientData *pCD)
|
||
{
|
||
Boolean bUnseen;
|
||
|
||
bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
|
||
if (bUnseen)
|
||
pCD->clientState &= ~UNSEEN_STATE;
|
||
|
||
if ((pCD->clientState == NORMAL_STATE) ||
|
||
(pCD->clientState == MAXIMIZED_STATE))
|
||
{
|
||
/*
|
||
* A client window was selected.
|
||
*/
|
||
|
||
DoExplicitSelectGrab (pCD->clientBaseWin);
|
||
}
|
||
else if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
/*
|
||
* An icon was selected.
|
||
*/
|
||
|
||
/* !!! grab reset if client icon window? !!! */
|
||
}
|
||
|
||
if (bUnseen)
|
||
pCD->clientState |= UNSEEN_STATE;
|
||
|
||
|
||
} /* END OF FUNCTION ResetExplicitSelectHandling */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* DoExplicitSelectGrab (window)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to do a grab button on the specified window. The
|
||
* grab is intended to catch the keyboard focus select button.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* widow = grab widow for the select button
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void DoExplicitSelectGrab (Window window)
|
||
{
|
||
|
||
WmGrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0, window,
|
||
False, ButtonReleaseMask, GrabModeSync, GrabModeSync, None,
|
||
None);
|
||
|
||
} /* END OF FUNCTION DoExplicitSelectGrab */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* SetFocusIndication (pCD)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function changes the client window or icon decoration to have it
|
||
* indicate that the window or icon has the keyboard input focus.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to client data for window/icon that is getting the focus
|
||
*
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void SetFocusIndication (ClientData *pCD)
|
||
{
|
||
ClientData *saveCD;
|
||
|
||
/*
|
||
* Set the "focus" to pCD to insure correct display of the frame
|
||
* This is necessary because the called routines get GCs based
|
||
* on the current keyboard focus.
|
||
*/
|
||
saveCD = wmGD.keyboardFocus;
|
||
wmGD.keyboardFocus = pCD;
|
||
|
||
if ((pCD->clientState == NORMAL_STATE) ||
|
||
(pCD->clientState == MAXIMIZED_STATE))
|
||
{
|
||
/*
|
||
* A client window has the input focus.
|
||
*/
|
||
|
||
ShowActiveClientFrame (pCD);
|
||
}
|
||
else if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
/*
|
||
* An icon has the input focus.
|
||
*/
|
||
|
||
ShowActiveIcon (pCD);
|
||
}
|
||
|
||
/* restore old keyboard focus */
|
||
wmGD.keyboardFocus = saveCD;
|
||
|
||
} /* END OF FUNCTION SetFocusIndication */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* ClearFocusIndication (pCD, refresh)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function changes the client window or icon decoration to have it
|
||
* indicate that the window or icon does not have the keyboard input focus
|
||
* (i.e. it is inactive).
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to client data for window/icon that is losing the focus
|
||
*
|
||
* refresh = True if window/icon frame is to redrawn
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void ClearFocusIndication (ClientData *pCD, Boolean refresh)
|
||
{
|
||
ClientData *saveCD;
|
||
Boolean bUnseen;
|
||
|
||
/*
|
||
* Set the "focus" to NULL to insure correct display of the frame
|
||
* This is necessary because the called routines get GCs based
|
||
* on the current keyboard focus.
|
||
*/
|
||
|
||
saveCD = wmGD.keyboardFocus;
|
||
wmGD.keyboardFocus = NULL;
|
||
bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
|
||
if (bUnseen)
|
||
pCD->clientState &= ~UNSEEN_STATE;
|
||
|
||
if ((pCD->clientState == NORMAL_STATE) ||
|
||
(pCD->clientState == MAXIMIZED_STATE))
|
||
{
|
||
/*
|
||
* A client window no longer has the input focus.
|
||
*/
|
||
|
||
ShowInactiveClientFrame (pCD);
|
||
}
|
||
else if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
/*
|
||
* An icon no longer has the input focus.
|
||
*/
|
||
|
||
ShowInactiveIcon (pCD, refresh);
|
||
}
|
||
|
||
if (bUnseen)
|
||
pCD->clientState |= UNSEEN_STATE;
|
||
|
||
/* restore old keyboard focus */
|
||
wmGD.keyboardFocus = saveCD;
|
||
|
||
} /* END OF FUNCTION ClearFocusIndication */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* GetClientUnderPointer (pSameScreen)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function identifies the managed client window or icon that is under
|
||
* the pointer.
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* pSameScreen = pointer to flag that indicates if pointer is on the wm screen
|
||
*
|
||
* Return = client data pointer for the client window / icon under the
|
||
* mouse cursor
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
ClientData *GetClientUnderPointer (Boolean *pSameScreen)
|
||
{
|
||
Window root;
|
||
Window child;
|
||
int rootX;
|
||
int rootY;
|
||
int winX;
|
||
int winY;
|
||
unsigned int mask;
|
||
ClientData *pCD;
|
||
|
||
|
||
if ((*pSameScreen = XQueryPointer (DISPLAY, ACTIVE_ROOT, &root, &child,
|
||
&rootX, &rootY, &winX, &winY, &mask)) != False)
|
||
{
|
||
if (child &&
|
||
!XFindContext (DISPLAY, child, wmGD.windowContextType,
|
||
(caddr_t *)&pCD))
|
||
{
|
||
/*
|
||
* There is a client window or icon under the pointer.
|
||
*/
|
||
|
||
return (pCD);
|
||
}
|
||
}
|
||
|
||
return (NULL);
|
||
|
||
} /* END OF FUNCTION GetClientUnderPointer */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FocusNextWindow (type, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to change the focus to the next window in the
|
||
* window stacking order. The next focus window must be of the specified
|
||
* type(s). If the focus traversal cannot be done because there is not
|
||
* an object of the specified type (accepting focus) then don't change the
|
||
* focus (!!!should the focus be unset in this case!!!).
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* type = type of objects to change the focus to
|
||
*
|
||
* focusTime = timestamp to be used for setting the input focus
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
Boolean FocusNextWindow (unsigned long type, Time focusTime)
|
||
{
|
||
ClientListEntry *pCurrentEntry;
|
||
ClientListEntry *pNextEntry;
|
||
Boolean focused = False;
|
||
ClientData *pCD;
|
||
|
||
|
||
/*
|
||
* Identify the window or icon that currently has the focus and start
|
||
* traversing to the next object.
|
||
*/
|
||
|
||
if (type & F_GROUP_TRANSIENT)
|
||
{
|
||
/*
|
||
* Move the keyboard input focus around in a transient tree.
|
||
*/
|
||
|
||
focused = FocusNextTransient (wmGD.keyboardFocus, type, False,
|
||
focusTime);
|
||
}
|
||
|
||
if (!focused)
|
||
{
|
||
if (wmGD.systemModalActive)
|
||
{
|
||
focused = True;
|
||
}
|
||
else if (wmGD.keyboardFocus)
|
||
{
|
||
if (wmGD.keyboardFocus->transientLeader)
|
||
{
|
||
pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
|
||
}
|
||
else
|
||
{
|
||
pCD = wmGD.keyboardFocus;
|
||
}
|
||
|
||
if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
pCurrentEntry = &pCD->iconEntry;
|
||
}
|
||
else
|
||
{
|
||
pCurrentEntry = &pCD->clientEntry;
|
||
}
|
||
|
||
pNextEntry = pCurrentEntry->nextSibling;
|
||
if (!pNextEntry)
|
||
{
|
||
pNextEntry = ACTIVE_PSD->clientList;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pCurrentEntry = ACTIVE_PSD->clientList;
|
||
pNextEntry = pCurrentEntry;
|
||
}
|
||
}
|
||
|
||
|
||
while (!focused && pNextEntry)
|
||
{
|
||
focused = CheckForKeyFocus (pNextEntry, type, True /*next*/, focusTime);
|
||
if (!focused)
|
||
{
|
||
pNextEntry = pNextEntry->nextSibling;
|
||
}
|
||
}
|
||
|
||
if (!focused)
|
||
{
|
||
pNextEntry = ACTIVE_PSD->clientList;
|
||
while ((pNextEntry != pCurrentEntry) && !focused)
|
||
{
|
||
focused = CheckForKeyFocus (pNextEntry, type, True/*next*/,
|
||
focusTime);
|
||
if (!focused)
|
||
{
|
||
pNextEntry = pNextEntry->nextSibling;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (focused);
|
||
|
||
} /* END OF FUNCTION FocusNextWindow */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FocusNextTransient (pCD, type, initiate, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to determine if another window in a transient
|
||
* tree should get the input focus.
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to the client data for the client window that has the focus
|
||
*
|
||
* type = type of objects to change the focus to
|
||
*
|
||
* initiate = set True if transient focus traversal is to be initiated;
|
||
* set to False if transient focus traversal is to be continued
|
||
*
|
||
* focusTime = timestamp to be used to set the input focus
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* RETURN = True if the focus window has been identified and the focus
|
||
* has been set (or is already set)
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
Boolean FocusNextTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
|
||
{
|
||
Boolean focused = False;
|
||
unsigned long startAt;
|
||
ClientData *pcdLeader;
|
||
ClientData *pcdLowerLeader;
|
||
ClientData *pcdFocus;
|
||
|
||
|
||
if (initiate && !(type & F_GROUP_TRANSIENT))
|
||
{
|
||
/*
|
||
* If in a transient tree focus on the last transient window that
|
||
* had the focus.
|
||
*/
|
||
|
||
if (pCD->transientChildren)
|
||
{
|
||
pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
|
||
if (pcdFocus != wmGD.keyboardFocus)
|
||
{
|
||
pcdLeader = FindTransientTreeLeader (pcdFocus);
|
||
if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
|
||
(wmGD.keyboardFocus != pcdLeader))
|
||
{
|
||
pcdLowerLeader =
|
||
FindTransientTreeLeader (wmGD.keyboardFocus);
|
||
if (pcdLowerLeader == pcdLeader)
|
||
{
|
||
if (PutTransientBelowSiblings (wmGD.keyboardFocus))
|
||
{
|
||
RestackTransients (pcdLeader);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
F_Lower (NULL, wmGD.keyboardFocus, (XEvent *) NULL);
|
||
}
|
||
}
|
||
Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
focused = True;
|
||
}
|
||
else
|
||
{
|
||
focused = False;
|
||
}
|
||
}
|
||
else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
|
||
(pCD->transientLeader || pCD->transientChildren))
|
||
{
|
||
startAt = (initiate) ? (ACTIVE_PSD->clientCounter + 1) :
|
||
pCD->clientID;
|
||
pcdLeader = FindTransientTreeLeader (pCD);
|
||
pcdFocus = FindNextTFocusInSeq (pcdLeader, startAt);
|
||
if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
|
||
{
|
||
/*
|
||
* Wrap around and find a focus window.
|
||
*/
|
||
|
||
pcdFocus = FindNextTFocusInSeq (pcdLeader,
|
||
(unsigned long) (ACTIVE_PSD->clientCounter + 1));
|
||
}
|
||
if (pcdFocus)
|
||
{
|
||
if (pcdFocus != wmGD.keyboardFocus)
|
||
{
|
||
if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
|
||
(wmGD.keyboardFocus != pcdLeader))
|
||
{
|
||
pcdLowerLeader =
|
||
FindTransientTreeLeader (wmGD.keyboardFocus);
|
||
if (pcdLowerLeader == pcdLeader)
|
||
{
|
||
if (PutTransientBelowSiblings (wmGD.keyboardFocus))
|
||
{
|
||
RestackTransients (pcdLeader);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
|
||
}
|
||
}
|
||
Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
focused = True;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (type == F_GROUP_TRANSIENT)
|
||
{
|
||
/*
|
||
* Focus only within a transient tree. In this case the current
|
||
* or prospective focus is not within a transient tree so leave
|
||
* the focus where it is.
|
||
*/
|
||
|
||
focused = True;
|
||
}
|
||
}
|
||
|
||
return (focused);
|
||
|
||
} /* END OF FUNCTION FocusNextTransient */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FindLastTransientTreeFocus (pCD, pcdNoFocus)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to scan a transient tree for the last window in
|
||
* the tree that had the focus.
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to the client data for the transient tree (or subtree)
|
||
* leader.
|
||
*
|
||
* pcdNoFocus = pointer to the client data for a client window that is not
|
||
* to get the input focus (NULL if no client window restriction).
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* RETURN = pointer to the client data of the window that last had the
|
||
* focus.
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
ClientData *FindLastTransientTreeFocus (ClientData *pCD, ClientData *pcdNoFocus)
|
||
|
||
{
|
||
ClientData *pcdNext;
|
||
ClientData *pcdFocus;
|
||
ClientData *pcdLastFocus = NULL;
|
||
|
||
|
||
pcdNext = pCD->transientChildren;
|
||
while (pcdNext)
|
||
{
|
||
pcdFocus = FindLastTransientTreeFocus (pcdNext, pcdNoFocus);
|
||
if (pcdFocus &&
|
||
(!IS_APP_MODALIZED(pcdFocus)) &&
|
||
((pcdLastFocus == NULL) ||
|
||
(pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
|
||
{
|
||
pcdLastFocus = pcdFocus;
|
||
}
|
||
pcdNext = pcdNext->transientSiblings;
|
||
}
|
||
|
||
if ((!IS_APP_MODALIZED(pCD)) &&
|
||
((pcdLastFocus == NULL) ||
|
||
(pCD->focusPriority > pcdLastFocus->focusPriority)))
|
||
{
|
||
pcdLastFocus = pCD;
|
||
}
|
||
|
||
return (pcdLastFocus);
|
||
|
||
|
||
} /* END OF FUNCTION FindLastTransientTreeFocus */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FindNextTFocusInSeq (pCD, startAt)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to scan a transient tree for the next window that
|
||
* can accept the focus.
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to the client data for the transient tree (or subtree)
|
||
* leader.
|
||
*
|
||
* startAt = focus window should have a lower id then this client id
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* RETURN = pointer to the client data of the window that should get the
|
||
* focus.
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
ClientData *FindNextTFocusInSeq (ClientData *pCD, unsigned long startAt)
|
||
{
|
||
ClientData *pcdNextFocus = NULL;
|
||
ClientData *pcdNext;
|
||
ClientData *pcdFocus;
|
||
|
||
|
||
pcdNext = pCD->transientChildren;
|
||
while (pcdNext)
|
||
{
|
||
pcdFocus = FindNextTFocusInSeq (pcdNext, startAt);
|
||
if (pcdFocus)
|
||
{
|
||
if ((pcdNextFocus == NULL) ||
|
||
(pcdFocus->clientID > pcdNextFocus->clientID))
|
||
{
|
||
pcdNextFocus = pcdFocus;
|
||
}
|
||
}
|
||
pcdNext = pcdNext->transientSiblings;
|
||
}
|
||
|
||
if ((pcdNextFocus == NULL) ||
|
||
(pCD->clientID > pcdNextFocus->clientID))
|
||
{
|
||
if ((!IS_APP_MODALIZED(pCD)) && (pCD->clientID < startAt))
|
||
{
|
||
pcdNextFocus = pCD;
|
||
}
|
||
}
|
||
|
||
return (pcdNextFocus);
|
||
|
||
|
||
} /* END OF FUNCTION FindNextTFocusInSeq */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FocusPrevWindow (type, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to change the focus to the previous window in the
|
||
* window stacking order. The next focus window must be of the specified
|
||
* type(s). If the focus traversal cannot be done because there is not
|
||
* an object of the specified type (accepting focus) then don't change the
|
||
* focus (!!!should the focus be unset in this case!!!).
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* type = type of objects to change the focus to
|
||
*
|
||
* focusTime = timestamp to be used to set the input focus
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
Boolean FocusPrevWindow (unsigned long type, Time focusTime)
|
||
{
|
||
ClientListEntry *pCurrentEntry;
|
||
ClientListEntry *pNextEntry;
|
||
Boolean focused = False;
|
||
ClientData *pCD;
|
||
|
||
|
||
/*
|
||
* Identify the window or icon that currently has the focus and start
|
||
* traversing to the previous object.
|
||
*/
|
||
|
||
if (type & F_GROUP_TRANSIENT)
|
||
{
|
||
/*
|
||
* Move the keyboard input focus around in a transient tree.
|
||
*/
|
||
|
||
focused = FocusPrevTransient (wmGD.keyboardFocus, type, False,
|
||
focusTime);
|
||
}
|
||
|
||
if (!focused)
|
||
{
|
||
if (wmGD.systemModalActive)
|
||
{
|
||
focused = True;
|
||
}
|
||
else if (wmGD.keyboardFocus)
|
||
{
|
||
if (wmGD.keyboardFocus->transientLeader)
|
||
{
|
||
pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
|
||
}
|
||
else
|
||
{
|
||
pCD = wmGD.keyboardFocus;
|
||
}
|
||
|
||
if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
pCurrentEntry = &pCD->iconEntry;
|
||
}
|
||
else
|
||
{
|
||
pCurrentEntry = &pCD->clientEntry;
|
||
}
|
||
|
||
pNextEntry = pCurrentEntry->prevSibling;
|
||
if (!pNextEntry)
|
||
{
|
||
pNextEntry = ACTIVE_PSD->lastClient;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pCurrentEntry = ACTIVE_PSD->lastClient;
|
||
pNextEntry = pCurrentEntry;
|
||
}
|
||
}
|
||
|
||
|
||
while (!focused && pNextEntry)
|
||
{
|
||
focused = CheckForKeyFocus (pNextEntry, type, False /*previous*/,
|
||
focusTime);
|
||
if (!focused)
|
||
{
|
||
pNextEntry = pNextEntry->prevSibling;
|
||
}
|
||
}
|
||
|
||
if (!focused)
|
||
{
|
||
pNextEntry = ACTIVE_PSD->lastClient;
|
||
while ((pNextEntry != pCurrentEntry) && !focused)
|
||
{
|
||
focused = CheckForKeyFocus (pNextEntry, type, False/*previous*/,
|
||
focusTime);
|
||
if (!focused)
|
||
{
|
||
pNextEntry = pNextEntry->prevSibling;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (focused);
|
||
|
||
} /* END OF FUNCTION FocusPrevWindow */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FocusPrevTransient (pCD, type, initiate, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to determine if another (previous) window in a
|
||
* transient tree should get the input focus.
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to the client data for the client window that has the focus
|
||
*
|
||
* type = type of objects to change the focus to
|
||
*
|
||
* initiate = set True if transient focus traversal is to be initiated;
|
||
* set to False if transient focus traversal is to be continued
|
||
*
|
||
* focusTime = timestamp to be used to set the input focus
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* RETURN = True if the focus window has been identified and the focus
|
||
* has been set (or is already set)
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
Boolean FocusPrevTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
|
||
{
|
||
Boolean focused = False;
|
||
unsigned long startAt;
|
||
ClientData *pcdLeader;
|
||
ClientData *pcdFocus;
|
||
|
||
|
||
if (initiate && !(type & F_GROUP_TRANSIENT))
|
||
{
|
||
/*
|
||
* If in a transient tree focus on the last transient window that
|
||
* had the focus.
|
||
*/
|
||
|
||
if (pCD->transientChildren)
|
||
{
|
||
pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
|
||
if (pcdFocus != wmGD.keyboardFocus)
|
||
{
|
||
Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
focused = True;
|
||
}
|
||
else
|
||
{
|
||
focused = False;
|
||
}
|
||
}
|
||
else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
|
||
(pCD->transientLeader || pCD->transientChildren))
|
||
{
|
||
startAt = (initiate) ? 0 : pCD->clientID;
|
||
pcdLeader = FindTransientTreeLeader (pCD);
|
||
pcdFocus = FindPrevTFocusInSeq (pcdLeader, startAt);
|
||
if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
|
||
{
|
||
/*
|
||
* Wrap around and find a focus window.
|
||
*/
|
||
|
||
pcdFocus = FindPrevTFocusInSeq (pcdLeader, 0);
|
||
}
|
||
if (pcdFocus)
|
||
{
|
||
if (pcdFocus != wmGD.keyboardFocus)
|
||
{
|
||
Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
focused = True;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (type == F_GROUP_TRANSIENT)
|
||
{
|
||
/*
|
||
* Focus only within a transient tree. In this case the current
|
||
* or prospective focus is not within a transient tree so leave
|
||
* the focus where it is.
|
||
*/
|
||
|
||
focused = True;
|
||
}
|
||
}
|
||
|
||
return (focused);
|
||
|
||
} /* END OF FUNCTION FocusPrevTransient */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* FindPrevTFocusInSeq (pCD, startAt)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to scan a transient tree for the previous window that
|
||
* can accept the focus.
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pCD = pointer to the client data for the transient tree (or subtree)
|
||
* leader.
|
||
*
|
||
* startAt = focus window should have a higher id then this client id
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* RETURN = pointer to the client data of the window that should get the
|
||
* focus.
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
ClientData *FindPrevTFocusInSeq (ClientData *pCD, unsigned long startAt)
|
||
{
|
||
ClientData *pcdNextFocus = NULL;
|
||
ClientData *pcdNext;
|
||
ClientData *pcdFocus;
|
||
|
||
|
||
pcdNext = pCD->transientChildren;
|
||
while (pcdNext)
|
||
{
|
||
pcdFocus = FindPrevTFocusInSeq (pcdNext, startAt);
|
||
if (pcdFocus)
|
||
{
|
||
if ((pcdNextFocus == NULL) ||
|
||
(pcdFocus->clientID < pcdNextFocus->clientID))
|
||
{
|
||
pcdNextFocus = pcdFocus;
|
||
}
|
||
}
|
||
pcdNext = pcdNext->transientSiblings;
|
||
}
|
||
|
||
if ((pcdNextFocus == NULL) ||
|
||
(pCD->clientID < pcdNextFocus->clientID))
|
||
{
|
||
if (!(IS_APP_MODALIZED(pCD)) && (pCD->clientID > startAt))
|
||
{
|
||
pcdNextFocus = pCD;
|
||
}
|
||
}
|
||
|
||
return (pcdNextFocus);
|
||
|
||
|
||
} /* END OF FUNCTION FindPrevTFocusInSeq */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* CheckForKeyFocus (pNextEntry, type, focusNext, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function is used to determine if a window is a worthy candidate for
|
||
* getting the input focus (it is on-screen and is of the desired type).
|
||
* If it is, the window gets the keyboard input focus.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pNextEntry = the client list entry to be checked
|
||
*
|
||
* type = the desired type of the focus window
|
||
*
|
||
* focusNext = if true then focus the next window in the window stack
|
||
*
|
||
* focusTime = timestamp to be used to set the input focus
|
||
*
|
||
*
|
||
* Outputs:
|
||
* -------
|
||
* Return = True if the window gets the keyboard input focus otherwise False
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
Boolean CheckForKeyFocus (ClientListEntry *pNextEntry, unsigned long type, Boolean focusNext, Time focusTime)
|
||
{
|
||
ClientData *pCD = pNextEntry->pCD;
|
||
unsigned long windowType;
|
||
Boolean focused = False;
|
||
|
||
|
||
/*
|
||
* First check for focusing within a transient tree.
|
||
*/
|
||
|
||
|
||
/*
|
||
* Make sure the window is being displayed and is of the specified type.
|
||
*/
|
||
|
||
if (((pNextEntry->type == NORMAL_STATE) &&
|
||
(!(pCD->clientState & UNSEEN_STATE)) &&
|
||
(pCD->clientState != MINIMIZED_STATE)) ||
|
||
((pNextEntry->type == MINIMIZED_STATE) &&
|
||
(pCD->clientState == MINIMIZED_STATE)))
|
||
{
|
||
if (pCD->clientState == MINIMIZED_STATE)
|
||
{
|
||
windowType = F_GROUP_ICON;
|
||
}
|
||
else
|
||
{
|
||
if (focusNext)
|
||
{
|
||
focused = FocusNextTransient (pCD, type, True, focusTime);
|
||
}
|
||
else
|
||
{
|
||
focused = FocusPrevTransient (pCD, type, True, focusTime);
|
||
}
|
||
windowType = F_GROUP_WINDOW;
|
||
if (pCD->transientLeader || pCD->transientChildren)
|
||
{
|
||
windowType |= F_GROUP_TRANSIENT;
|
||
}
|
||
}
|
||
|
||
if (!focused && (type & windowType))
|
||
{
|
||
focused = True;
|
||
if (focusNext && wmGD.keyboardFocus &&
|
||
wmGD.keyboardFocus->focusAutoRaise)
|
||
{
|
||
F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
|
||
}
|
||
Do_Focus_Key (pCD, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
}
|
||
|
||
return (focused);
|
||
|
||
} /* END OF FUNCTION CheckForKeyFocus */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* RepairFocus ()
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function sets the keyboard and colormap focus to a client
|
||
* window or icon when the window manager is recovering from a
|
||
* configuration action.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
*
|
||
*
|
||
* Comments:
|
||
* --------
|
||
* o we only need to repair keyboard focus policy is "pointer"
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void RepairFocus (void)
|
||
{
|
||
ClientData *pCD;
|
||
Boolean sameScreen;
|
||
XEvent event;
|
||
|
||
|
||
/*
|
||
* Repair the keyboard and colormap focus based on the policies
|
||
*/
|
||
|
||
if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
|
||
(wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
|
||
{
|
||
/*
|
||
* Move old enter and leave events and then get the window that
|
||
* the pointer is currently in.
|
||
*/
|
||
|
||
XSync (DISPLAY, False);
|
||
while (XCheckMaskEvent (DISPLAY, EnterWindowMask | LeaveWindowMask,
|
||
&event))
|
||
{
|
||
}
|
||
|
||
pCD = GetClientUnderPointer (&sameScreen);
|
||
|
||
/*
|
||
* Set the keyboard focus to the window that currently contains the
|
||
* pointer.
|
||
*/
|
||
|
||
if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
|
||
{
|
||
/*
|
||
* This will also set colormap focus if it is CMAP_FOCUS_KEYBOARD.
|
||
*/
|
||
|
||
Do_Focus_Key (pCD, CurrentTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
else if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
|
||
{
|
||
SetColormapFocus (ACTIVE_PSD, pCD);
|
||
}
|
||
}
|
||
|
||
} /* END OF FUNCTION RepairFocus */
|
||
|
||
|
||
|
||
/*************************************<->*************************************
|
||
*
|
||
* AutoResetKeyFocus (pcdFocus, focusTime)
|
||
*
|
||
*
|
||
* Description:
|
||
* -----------
|
||
* This function resets the keyboard input focus when a window with the
|
||
* focus is withdrawn or iconified. The focus is set to the last window
|
||
* that had the focus. The focus is not set to an icon.
|
||
*
|
||
*
|
||
* Inputs:
|
||
* ------
|
||
* pcdFocus = pointer to the client data of the window with the focus or
|
||
* the leader of the transient tree that contains the focus window;
|
||
* the focus should not be set to the pcdFocus window or subordinates.
|
||
*
|
||
* focusTime = timestamp to be used in setting the keyboard input focus.
|
||
*
|
||
*************************************<->***********************************/
|
||
|
||
void AutoResetKeyFocus (ClientData *pcdNoFocus, Time focusTime)
|
||
{
|
||
ClientListEntry *pNextEntry;
|
||
ClientData *pCD;
|
||
ClientData *pcdLastFocus = NULL;
|
||
ClientData *pcdFocus;
|
||
|
||
|
||
/*
|
||
* Scan through the list of clients to find a window to get the focus.
|
||
*/
|
||
|
||
pNextEntry = ACTIVE_PSD->clientList;
|
||
|
||
while (pNextEntry)
|
||
{
|
||
pCD = pNextEntry->pCD;
|
||
if (!wmGD.systemModalActive ||
|
||
(wmGD.systemModalClient == pCD))
|
||
{
|
||
if ((pNextEntry->type != MINIMIZED_STATE) &&
|
||
(pCD->clientState != MINIMIZED_STATE) &&
|
||
(!(pCD->clientState & UNSEEN_STATE)) &&
|
||
(pCD != pcdNoFocus))
|
||
{
|
||
if (pCD->transientChildren)
|
||
{
|
||
pcdFocus = FindLastTransientTreeFocus (pCD, pcdNoFocus);
|
||
}
|
||
else
|
||
{
|
||
pcdFocus = pCD;
|
||
}
|
||
if (pcdFocus &&
|
||
((pcdLastFocus == NULL) ||
|
||
(pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
|
||
{
|
||
pcdLastFocus = pcdFocus;
|
||
}
|
||
}
|
||
}
|
||
pNextEntry = pNextEntry->nextSibling;
|
||
}
|
||
|
||
|
||
/*
|
||
* Set the focus if there is a window that is a good candidate for
|
||
* getting the focus.
|
||
*/
|
||
|
||
if (pcdLastFocus)
|
||
{
|
||
Do_Focus_Key (pcdLastFocus, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* !!! Immediately set the focus indication !!!
|
||
*/
|
||
|
||
Do_Focus_Key ((ClientData *)NULL, focusTime, ALWAYS_SET_FOCUS);
|
||
}
|
||
|
||
} /* END OF FUNCTION AutoResetKeyFocus */
|