/* * tkUnixFocus.c -- * * This file contains platform specific procedures that manage * focus for Tk. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkUnixFocus.c 1.7 97/08/11 09:47:20 */ #include "tkInt.h" #include "tkPort.h" #include "tkUnixInt.h" extern int tclFocusDebug; /* *---------------------------------------------------------------------- * * TkpChangeFocus -- * * This procedure is invoked to move the official X focus from * one window to another. * * Results: * None. * * Side effects: * The official X focus window changes; the application's focus * window isn't changed by this procedure. * *---------------------------------------------------------------------- */ void TkpChangeFocus(winPtr, force) TkWindow *winPtr; /* Window that is to receive the X focus. */ int force; /* Non-zero means claim the focus even * if it didn't originally belong to * topLevelPtr's application. */ { TkDisplay *dispPtr = winPtr->dispPtr; Tk_ErrorHandler errHandler; Window window, root, parent, *children; unsigned int numChildren; TkWindow *winPtr2; int dummy; /* * Don't set the X focus to a window that's marked * override-redirect. This is a hack to avoid problems with menus * under olvwm: if we move the focus then the focus can get lost * during keyboard traversal. Fortunately, we don't really need to * move the focus for menus: events will still find their way to the * focus window, and menus aren't decorated anyway so the window * manager doesn't need to hear about the focus change in order to * redecorate the menu. */ if (winPtr->atts.override_redirect) { return; } /* * Check to make sure that the focus is still in one of the windows * of this application or one of their descendants. Furthermore, * grab the server to make sure that the focus doesn't change in the * middle of this operation. */ XGrabServer(dispPtr->display); if (!force) { /* * Find the focus window, then see if it or one of its ancestors * is a window in our application (it's possible that the focus * window is in an embedded application, which may or may not be * in the same process. */ XGetInputFocus(dispPtr->display, &window, &dummy); while (1) { winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, window); if ((winPtr2 != NULL) && (winPtr2->mainPtr == winPtr->mainPtr)) { break; } if ((window == PointerRoot) || (window == None)) { goto done; } XQueryTree(dispPtr->display, window, &root, &parent, &children, &numChildren); if (children != NULL) { XFree((void *) children); } if (parent == root) { goto done; } window = parent; } } /* * Tell X to change the focus. Ignore errors that occur when changing * the focus: it is still possible that the window we're focussing * to could have gotten unmapped, which will generate an error. */ errHandler = Tk_CreateErrorHandler(dispPtr->display, -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); if (winPtr->window == None) { panic("ChangeXFocus got null X window"); } XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent, CurrentTime); Tk_DeleteErrorHandler(errHandler); /* * Remember the current serial number for the X server and issue * a dummy server request. This marks the position at which we * changed the focus, so we can distinguish FocusIn and FocusOut * events on either side of the mark. */ winPtr->mainPtr->focusSerial = NextRequest(winPtr->display); XNoOp(winPtr->display); done: XUngrabServer(dispPtr->display); return; }