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 149
|
/*
* tkUnixFocus.c --
*
* This file contains platform specific functions 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.
*/
#include "tkUnixInt.h"
/*
*----------------------------------------------------------------------
*
* TkpChangeFocus --
*
* This function 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 function 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 function.
*
*----------------------------------------------------------------------
*/
int
TkpChangeFocus(
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, NULL,NULL);
if (winPtr->window == None) {
Tcl_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;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|