/* * 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 */