/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1989, 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * Motif Release 1.2.3 */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$XConsortium: WmKeyFocus.c /main/5 1996/05/17 12:53:16 rswiston $" #endif #endif /* * (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) { #ifdef WSM Boolean bUnseen; bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False; if (bUnseen) pCD->clientState &= ~UNSEEN_STATE; #endif /* WSM */ 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? !!! */ } #ifdef WSM if (bUnseen) pCD->clientState |= UNSEEN_STATE; #endif /* WSM */ } /* 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; #ifdef WSM Boolean bUnseen; #endif /* WSM */ /* * 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; #ifdef WSM bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False; if (bUnseen) pCD->clientState &= ~UNSEEN_STATE; #endif /* WSM */ 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); } #ifdef WSM if (bUnseen) pCD->clientState |= UNSEEN_STATE; #endif /* WSM */ /* 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 (pSameScreen) 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 (pCD, pcdNoFocus) 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 (pCD, startAt) 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 (pCD, startAt) 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) && #ifdef WSM (!(pCD->clientState & UNSEEN_STATE)) && #endif /* WSM */ (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) && #ifdef WSM (!(pCD->clientState & UNSEEN_STATE)) && #endif /* WSM */ (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 */