1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
/*
* 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.
*
* RCS: @(#) $Id: tkUnixFocus.c,v 1.3 1999/04/16 01:51:46 stanton Exp $
*/
#include "tkInt.h"
#include "tkPort.h"
#include "tkUnixInt.h"
/*
*----------------------------------------------------------------------
*
* TkpChangeFocus --
*
* This procedure is invoked to move the official X focus from
* one window to another.
*
* Results:
* The return value is the serial number of the command that
* changed the focus. It may be needed by the caller to filter
* out focus change events that were queued before the command.
* If the procedure doesn't actually change the focus then
* it returns 0.
*
* Side effects:
* The official X focus window changes; the application's focus
* window isn't changed by this procedure.
*
*----------------------------------------------------------------------
*/
int
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, serial;
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.
*/
serial = 0;
if (winPtr->atts.override_redirect) {
return serial;
}
/*
* 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.
*/
serial = NextRequest(winPtr->display);
XNoOp(winPtr->display);
done:
XUngrabServer(dispPtr->display);
/*
* After ungrabbing the server, it's important to flush the output
* immediately so that the server sees the ungrab command. Otherwise
* we might do something else that needs to communicate with the
* server (such as invoking a subprocess that needs to do I/O to
* the screen); if the ungrab command is still sitting in our
* output buffer, we could deadlock.
*/
XFlush(dispPtr->display);
return serial;
}
|