OSDN Git Service

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