1 |
578 |
markom |
/*
|
2 |
|
|
* tkUnixFocus.c --
|
3 |
|
|
*
|
4 |
|
|
* This file contains platform specific procedures that manage
|
5 |
|
|
* focus for Tk.
|
6 |
|
|
*
|
7 |
|
|
* Copyright (c) 1997 Sun Microsystems, Inc.
|
8 |
|
|
*
|
9 |
|
|
* See the file "license.terms" for information on usage and redistribution
|
10 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
11 |
|
|
*
|
12 |
|
|
* RCS: @(#) $Id: tkUnixFocus.c,v 1.1.1.1 2002-01-16 10:26:01 markom Exp $
|
13 |
|
|
*/
|
14 |
|
|
|
15 |
|
|
#include "tkInt.h"
|
16 |
|
|
#include "tkPort.h"
|
17 |
|
|
#include "tkUnixInt.h"
|
18 |
|
|
|
19 |
|
|
extern int tclFocusDebug;
|
20 |
|
|
|
21 |
|
|
/*
|
22 |
|
|
*----------------------------------------------------------------------
|
23 |
|
|
*
|
24 |
|
|
* TkpChangeFocus --
|
25 |
|
|
*
|
26 |
|
|
* This procedure is invoked to move the official X focus from
|
27 |
|
|
* one window to another.
|
28 |
|
|
*
|
29 |
|
|
* Results:
|
30 |
|
|
* The return value is the serial number of the command that
|
31 |
|
|
* changed the focus. It may be needed by the caller to filter
|
32 |
|
|
* out focus change events that were queued before the command.
|
33 |
|
|
* If the procedure doesn't actually change the focus then
|
34 |
|
|
* it returns 0.
|
35 |
|
|
*
|
36 |
|
|
* Side effects:
|
37 |
|
|
* The official X focus window changes; the application's focus
|
38 |
|
|
* window isn't changed by this procedure.
|
39 |
|
|
*
|
40 |
|
|
*----------------------------------------------------------------------
|
41 |
|
|
*/
|
42 |
|
|
|
43 |
|
|
int
|
44 |
|
|
TkpChangeFocus(winPtr, force)
|
45 |
|
|
TkWindow *winPtr; /* Window that is to receive the X focus. */
|
46 |
|
|
int force; /* Non-zero means claim the focus even
|
47 |
|
|
* if it didn't originally belong to
|
48 |
|
|
* topLevelPtr's application. */
|
49 |
|
|
{
|
50 |
|
|
TkDisplay *dispPtr = winPtr->dispPtr;
|
51 |
|
|
Tk_ErrorHandler errHandler;
|
52 |
|
|
Window window, root, parent, *children;
|
53 |
|
|
unsigned int numChildren, serial;
|
54 |
|
|
TkWindow *winPtr2;
|
55 |
|
|
int dummy;
|
56 |
|
|
|
57 |
|
|
/*
|
58 |
|
|
* Don't set the X focus to a window that's marked
|
59 |
|
|
* override-redirect. This is a hack to avoid problems with menus
|
60 |
|
|
* under olvwm: if we move the focus then the focus can get lost
|
61 |
|
|
* during keyboard traversal. Fortunately, we don't really need to
|
62 |
|
|
* move the focus for menus: events will still find their way to the
|
63 |
|
|
* focus window, and menus aren't decorated anyway so the window
|
64 |
|
|
* manager doesn't need to hear about the focus change in order to
|
65 |
|
|
* redecorate the menu.
|
66 |
|
|
*/
|
67 |
|
|
|
68 |
|
|
serial = 0;
|
69 |
|
|
if (winPtr->atts.override_redirect) {
|
70 |
|
|
return serial;
|
71 |
|
|
}
|
72 |
|
|
|
73 |
|
|
/*
|
74 |
|
|
* Check to make sure that the focus is still in one of the windows
|
75 |
|
|
* of this application or one of their descendants. Furthermore,
|
76 |
|
|
* grab the server to make sure that the focus doesn't change in the
|
77 |
|
|
* middle of this operation.
|
78 |
|
|
*/
|
79 |
|
|
|
80 |
|
|
XGrabServer(dispPtr->display);
|
81 |
|
|
if (!force) {
|
82 |
|
|
/*
|
83 |
|
|
* Find the focus window, then see if it or one of its ancestors
|
84 |
|
|
* is a window in our application (it's possible that the focus
|
85 |
|
|
* window is in an embedded application, which may or may not be
|
86 |
|
|
* in the same process.
|
87 |
|
|
*/
|
88 |
|
|
|
89 |
|
|
XGetInputFocus(dispPtr->display, &window, &dummy);
|
90 |
|
|
while (1) {
|
91 |
|
|
winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, window);
|
92 |
|
|
if ((winPtr2 != NULL) && (winPtr2->mainPtr == winPtr->mainPtr)) {
|
93 |
|
|
break;
|
94 |
|
|
}
|
95 |
|
|
if ((window == PointerRoot) || (window == None)) {
|
96 |
|
|
goto done;
|
97 |
|
|
}
|
98 |
|
|
XQueryTree(dispPtr->display, window, &root, &parent, &children,
|
99 |
|
|
&numChildren);
|
100 |
|
|
if (children != NULL) {
|
101 |
|
|
XFree((void *) children);
|
102 |
|
|
}
|
103 |
|
|
if (parent == root) {
|
104 |
|
|
goto done;
|
105 |
|
|
}
|
106 |
|
|
window = parent;
|
107 |
|
|
}
|
108 |
|
|
}
|
109 |
|
|
|
110 |
|
|
/*
|
111 |
|
|
* Tell X to change the focus. Ignore errors that occur when changing
|
112 |
|
|
* the focus: it is still possible that the window we're focussing
|
113 |
|
|
* to could have gotten unmapped, which will generate an error.
|
114 |
|
|
*/
|
115 |
|
|
|
116 |
|
|
errHandler = Tk_CreateErrorHandler(dispPtr->display, -1, -1, -1,
|
117 |
|
|
(Tk_ErrorProc *) NULL, (ClientData) NULL);
|
118 |
|
|
if (winPtr->window == None) {
|
119 |
|
|
panic("ChangeXFocus got null X window");
|
120 |
|
|
}
|
121 |
|
|
XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent,
|
122 |
|
|
CurrentTime);
|
123 |
|
|
Tk_DeleteErrorHandler(errHandler);
|
124 |
|
|
|
125 |
|
|
/*
|
126 |
|
|
* Remember the current serial number for the X server and issue
|
127 |
|
|
* a dummy server request. This marks the position at which we
|
128 |
|
|
* changed the focus, so we can distinguish FocusIn and FocusOut
|
129 |
|
|
* events on either side of the mark.
|
130 |
|
|
*/
|
131 |
|
|
|
132 |
|
|
serial = NextRequest(winPtr->display);
|
133 |
|
|
XNoOp(winPtr->display);
|
134 |
|
|
|
135 |
|
|
done:
|
136 |
|
|
XUngrabServer(dispPtr->display);
|
137 |
|
|
|
138 |
|
|
/*
|
139 |
|
|
* After ungrabbing the server, it's important to flush the output
|
140 |
|
|
* immediately so that the server sees the ungrab command. Otherwise
|
141 |
|
|
* we might do something else that needs to communicate with the
|
142 |
|
|
* server (such as invoking a subprocess that needs to do I/O to
|
143 |
|
|
* the screen); if the ungrab command is still sitting in our
|
144 |
|
|
* output buffer, we could deadlock.
|
145 |
|
|
*/
|
146 |
|
|
|
147 |
|
|
XFlush(dispPtr->display);
|
148 |
|
|
return serial;
|
149 |
|
|
}
|