1 |
dashley |
25 |
/* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkfocus.c,v 1.1.1.1 2001/06/13 05:00:25 dtashley Exp $ */
|
2 |
|
|
|
3 |
|
|
/*
|
4 |
|
|
* tkFocus.c --
|
5 |
|
|
*
|
6 |
|
|
* This file contains procedures that manage the input
|
7 |
|
|
* focus for Tk.
|
8 |
|
|
*
|
9 |
|
|
* Copyright (c) 1990-1994 The Regents of the University of California.
|
10 |
|
|
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
11 |
|
|
*
|
12 |
|
|
* See the file "license.terms" for information on usage and redistribution
|
13 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
14 |
|
|
*
|
15 |
|
|
* RCS: @(#) $Id: tkfocus.c,v 1.1.1.1 2001/06/13 05:00:25 dtashley Exp $
|
16 |
|
|
*/
|
17 |
|
|
|
18 |
|
|
#include "tkInt.h"
|
19 |
|
|
#include "tkPort.h"
|
20 |
|
|
|
21 |
|
|
|
22 |
|
|
/*
|
23 |
|
|
* For each top-level window that has ever received the focus, there
|
24 |
|
|
* is a record of the following type:
|
25 |
|
|
*/
|
26 |
|
|
|
27 |
|
|
typedef struct TkToplevelFocusInfo {
|
28 |
|
|
TkWindow *topLevelPtr; /* Information about top-level window. */
|
29 |
|
|
TkWindow *focusWinPtr; /* The next time the focus comes to this
|
30 |
|
|
* top-level, it will be given to this
|
31 |
|
|
* window. */
|
32 |
|
|
struct TkToplevelFocusInfo *nextPtr;
|
33 |
|
|
/* Next in list of all toplevel focus records
|
34 |
|
|
* for a given application. */
|
35 |
|
|
} ToplevelFocusInfo;
|
36 |
|
|
|
37 |
|
|
/*
|
38 |
|
|
* One of the following structures exists for each display used by
|
39 |
|
|
* each application. These are linked together from the TkMainInfo
|
40 |
|
|
* structure. These structures are needed because it isn't
|
41 |
|
|
* sufficient to store a single piece of focus information in each
|
42 |
|
|
* display or in each application: we need the cross-product.
|
43 |
|
|
* There needs to be separate information for each display, because
|
44 |
|
|
* it's possible to have multiple focus windows active simultaneously
|
45 |
|
|
* on different displays. There also needs to be separate information
|
46 |
|
|
* for each application, because of embedding: if an embedded
|
47 |
|
|
* application has the focus, its container application also has
|
48 |
|
|
* the focus. Thus we keep a list of structures for each application:
|
49 |
|
|
* the same display can appear in structures for several applications
|
50 |
|
|
* at once.
|
51 |
|
|
*/
|
52 |
|
|
|
53 |
|
|
typedef struct TkDisplayFocusInfo {
|
54 |
|
|
TkDisplay *dispPtr; /* Display that this information pertains
|
55 |
|
|
* to. */
|
56 |
|
|
struct TkWindow *focusWinPtr;
|
57 |
|
|
/* Window that currently has the focus for
|
58 |
|
|
* this application on this display, or NULL
|
59 |
|
|
* if none. */
|
60 |
|
|
struct TkWindow *focusOnMapPtr;
|
61 |
|
|
/* This points to a toplevel window that is
|
62 |
|
|
* supposed to receive the X input focus as
|
63 |
|
|
* soon as it is mapped (needed to handle the
|
64 |
|
|
* fact that X won't allow the focus on an
|
65 |
|
|
* unmapped window). NULL means no delayed
|
66 |
|
|
* focus op in progress for this display. */
|
67 |
|
|
int forceFocus; /* Associated with focusOnMapPtr: non-zero
|
68 |
|
|
* means claim the focus even if some other
|
69 |
|
|
* application currently has it. */
|
70 |
|
|
unsigned long focusSerial; /* Serial number of last request this
|
71 |
|
|
* application made to change the focus on
|
72 |
|
|
* this display. Used to identify stale
|
73 |
|
|
* focus notifications coming from the
|
74 |
|
|
* X server. */
|
75 |
|
|
struct TkDisplayFocusInfo *nextPtr;
|
76 |
|
|
/* Next in list of all display focus
|
77 |
|
|
* records for a given application. */
|
78 |
|
|
} DisplayFocusInfo;
|
79 |
|
|
|
80 |
|
|
/*
|
81 |
|
|
* The following magic value is stored in the "send_event" field of
|
82 |
|
|
* FocusIn and FocusOut events that are generated in this file. This
|
83 |
|
|
* allows us to separate "real" events coming from the server from
|
84 |
|
|
* those that we generated.
|
85 |
|
|
*/
|
86 |
|
|
|
87 |
|
|
#define GENERATED_EVENT_MAGIC ((Bool) 0x547321ac)
|
88 |
|
|
|
89 |
|
|
/*
|
90 |
|
|
* Forward declarations for procedures defined in this file:
|
91 |
|
|
*/
|
92 |
|
|
|
93 |
|
|
|
94 |
|
|
static DisplayFocusInfo *FindDisplayFocusInfo _ANSI_ARGS_((TkMainInfo *mainPtr,
|
95 |
|
|
TkDisplay *dispPtr));
|
96 |
|
|
static void FocusMapProc _ANSI_ARGS_((ClientData clientData,
|
97 |
|
|
XEvent *eventPtr));
|
98 |
|
|
static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr,
|
99 |
|
|
TkWindow *destPtr));
|
100 |
|
|
|
101 |
|
|
/*
|
102 |
|
|
*--------------------------------------------------------------
|
103 |
|
|
*
|
104 |
|
|
* Tk_FocusObjCmd --
|
105 |
|
|
*
|
106 |
|
|
* This procedure is invoked to process the "focus" Tcl command.
|
107 |
|
|
* See the user documentation for details on what it does.
|
108 |
|
|
*
|
109 |
|
|
* Results:
|
110 |
|
|
* A standard Tcl result.
|
111 |
|
|
*
|
112 |
|
|
* Side effects:
|
113 |
|
|
* See the user documentation.
|
114 |
|
|
*
|
115 |
|
|
*--------------------------------------------------------------
|
116 |
|
|
*/
|
117 |
|
|
|
118 |
|
|
int
|
119 |
|
|
Tk_FocusObjCmd(clientData, interp, objc, objv)
|
120 |
|
|
ClientData clientData; /* Main window associated with
|
121 |
|
|
* interpreter. */
|
122 |
|
|
Tcl_Interp *interp; /* Current interpreter. */
|
123 |
|
|
int objc; /* Number of arguments. */
|
124 |
|
|
Tcl_Obj *CONST objv[]; /* Argument objects. */
|
125 |
|
|
{
|
126 |
|
|
static char *focusOptions[] = {"-displayof", "-force", "-lastfor",
|
127 |
|
|
(char *) NULL};
|
128 |
|
|
Tk_Window tkwin = (Tk_Window) clientData;
|
129 |
|
|
TkWindow *winPtr = (TkWindow *) clientData;
|
130 |
|
|
TkWindow *newPtr, *focusWinPtr, *topLevelPtr;
|
131 |
|
|
ToplevelFocusInfo *tlFocusPtr;
|
132 |
|
|
char *windowName;
|
133 |
|
|
int index;
|
134 |
|
|
|
135 |
|
|
/*
|
136 |
|
|
* If invoked with no arguments, just return the current focus window.
|
137 |
|
|
*/
|
138 |
|
|
|
139 |
|
|
if (objc == 1) {
|
140 |
|
|
focusWinPtr = TkGetFocusWin(winPtr);
|
141 |
|
|
if (focusWinPtr != NULL) {
|
142 |
|
|
Tcl_SetResult(interp, focusWinPtr->pathName, TCL_STATIC);
|
143 |
|
|
}
|
144 |
|
|
return TCL_OK;
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
/*
|
148 |
|
|
* If invoked with a single argument beginning with "." then focus
|
149 |
|
|
* on that window.
|
150 |
|
|
*/
|
151 |
|
|
|
152 |
|
|
if (objc == 2) {
|
153 |
|
|
windowName = Tcl_GetStringFromObj(objv[1], (int *) NULL);
|
154 |
|
|
|
155 |
|
|
/*
|
156 |
|
|
* The empty string case exists for backwards compatibility.
|
157 |
|
|
*/
|
158 |
|
|
|
159 |
|
|
if (windowName[0] == '\0') {
|
160 |
|
|
return TCL_OK;
|
161 |
|
|
}
|
162 |
|
|
if (windowName[0] == '.') {
|
163 |
|
|
newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
|
164 |
|
|
if (newPtr == NULL) {
|
165 |
|
|
return TCL_ERROR;
|
166 |
|
|
}
|
167 |
|
|
if (!(newPtr->flags & TK_ALREADY_DEAD)) {
|
168 |
|
|
TkSetFocusWin(newPtr, 0);
|
169 |
|
|
}
|
170 |
|
|
return TCL_OK;
|
171 |
|
|
}
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
if (Tcl_GetIndexFromObj(interp, objv[1], focusOptions, "option", 0,
|
175 |
|
|
&index) != TCL_OK) {
|
176 |
|
|
return TCL_ERROR;
|
177 |
|
|
}
|
178 |
|
|
if (objc != 3) {
|
179 |
|
|
Tcl_WrongNumArgs(interp, 2, objv, "window");
|
180 |
|
|
return TCL_ERROR;
|
181 |
|
|
}
|
182 |
|
|
switch (index) {
|
183 |
|
|
case 0: { /* -displayof */
|
184 |
|
|
windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
|
185 |
|
|
newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
|
186 |
|
|
if (newPtr == NULL) {
|
187 |
|
|
return TCL_ERROR;
|
188 |
|
|
}
|
189 |
|
|
newPtr = TkGetFocusWin(newPtr);
|
190 |
|
|
if (newPtr != NULL) {
|
191 |
|
|
Tcl_SetResult(interp, newPtr->pathName, TCL_STATIC);
|
192 |
|
|
}
|
193 |
|
|
break;
|
194 |
|
|
}
|
195 |
|
|
case 1: { /* -force */
|
196 |
|
|
windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
|
197 |
|
|
|
198 |
|
|
/*
|
199 |
|
|
* The empty string case exists for backwards compatibility.
|
200 |
|
|
*/
|
201 |
|
|
|
202 |
|
|
if (windowName[0] == '\0') {
|
203 |
|
|
return TCL_OK;
|
204 |
|
|
}
|
205 |
|
|
newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
|
206 |
|
|
if (newPtr == NULL) {
|
207 |
|
|
return TCL_ERROR;
|
208 |
|
|
}
|
209 |
|
|
TkSetFocusWin(newPtr, 1);
|
210 |
|
|
break;
|
211 |
|
|
}
|
212 |
|
|
case 2: { /* -lastfor */
|
213 |
|
|
windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
|
214 |
|
|
newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
|
215 |
|
|
if (newPtr == NULL) {
|
216 |
|
|
return TCL_ERROR;
|
217 |
|
|
}
|
218 |
|
|
for (topLevelPtr = newPtr; topLevelPtr != NULL;
|
219 |
|
|
topLevelPtr = topLevelPtr->parentPtr) {
|
220 |
|
|
if (topLevelPtr->flags & TK_TOP_LEVEL) {
|
221 |
|
|
for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr;
|
222 |
|
|
tlFocusPtr != NULL;
|
223 |
|
|
tlFocusPtr = tlFocusPtr->nextPtr) {
|
224 |
|
|
if (tlFocusPtr->topLevelPtr == topLevelPtr) {
|
225 |
|
|
Tcl_SetResult(interp,
|
226 |
|
|
tlFocusPtr->focusWinPtr->pathName,
|
227 |
|
|
TCL_STATIC);
|
228 |
|
|
return TCL_OK;
|
229 |
|
|
}
|
230 |
|
|
}
|
231 |
|
|
Tcl_SetResult(interp, topLevelPtr->pathName, TCL_STATIC);
|
232 |
|
|
return TCL_OK;
|
233 |
|
|
}
|
234 |
|
|
}
|
235 |
|
|
break;
|
236 |
|
|
}
|
237 |
|
|
default: {
|
238 |
|
|
panic("bad const entries to focusOptions in focus command");
|
239 |
|
|
}
|
240 |
|
|
}
|
241 |
|
|
return TCL_OK;
|
242 |
|
|
}
|
243 |
|
|
|
244 |
|
|
/*
|
245 |
|
|
*--------------------------------------------------------------
|
246 |
|
|
*
|
247 |
|
|
* TkFocusFilterEvent --
|
248 |
|
|
*
|
249 |
|
|
* This procedure is invoked by Tk_HandleEvent when it encounters
|
250 |
|
|
* a FocusIn, FocusOut, Enter, or Leave event.
|
251 |
|
|
*
|
252 |
|
|
* Results:
|
253 |
|
|
* A return value of 1 means that Tk_HandleEvent should process
|
254 |
|
|
* the event normally (i.e. event handlers should be invoked).
|
255 |
|
|
* A return value of 0 means that this event should be ignored.
|
256 |
|
|
*
|
257 |
|
|
* Side effects:
|
258 |
|
|
* Additional events may be generated, and the focus may switch.
|
259 |
|
|
*
|
260 |
|
|
*--------------------------------------------------------------
|
261 |
|
|
*/
|
262 |
|
|
|
263 |
|
|
int
|
264 |
|
|
TkFocusFilterEvent(winPtr, eventPtr)
|
265 |
|
|
TkWindow *winPtr; /* Window that focus event is directed to. */
|
266 |
|
|
XEvent *eventPtr; /* FocusIn, FocusOut, Enter, or Leave
|
267 |
|
|
* event. */
|
268 |
|
|
{
|
269 |
|
|
/*
|
270 |
|
|
* Design notes: the window manager and X server work together to
|
271 |
|
|
* transfer the focus among top-level windows. This procedure takes
|
272 |
|
|
* care of transferring the focus from a top-level or wrapper window
|
273 |
|
|
* to the actual window within that top-level that has the focus.
|
274 |
|
|
* We do this by synthesizing X events to move the focus around.
|
275 |
|
|
* None of the FocusIn and FocusOut events generated by X are ever
|
276 |
|
|
* used outside of this procedure; only the synthesized events get
|
277 |
|
|
* through to the rest of the application. At one point (e.g.
|
278 |
|
|
* Tk4.0b1) Tk used to call X to move the focus from a top-level to
|
279 |
|
|
* one of its descendants, then just pass through the events
|
280 |
|
|
* generated by X. This approach didn't work very well, for a
|
281 |
|
|
* variety of reasons. For example, if X generates the events they
|
282 |
|
|
* go at the back of the event queue, which could cause problems if
|
283 |
|
|
* other things have already happened, such as moving the focus to
|
284 |
|
|
* yet another window.
|
285 |
|
|
*/
|
286 |
|
|
|
287 |
|
|
ToplevelFocusInfo *tlFocusPtr;
|
288 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
289 |
|
|
TkDisplay *dispPtr = winPtr->dispPtr;
|
290 |
|
|
TkWindow *newFocusPtr;
|
291 |
|
|
int retValue, delta;
|
292 |
|
|
|
293 |
|
|
/*
|
294 |
|
|
* If this was a generated event, just turn off the generated
|
295 |
|
|
* flag and pass the event through to Tk bindings.
|
296 |
|
|
*/
|
297 |
|
|
|
298 |
|
|
if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) {
|
299 |
|
|
eventPtr->xfocus.send_event = 0;
|
300 |
|
|
return 1;
|
301 |
|
|
}
|
302 |
|
|
|
303 |
|
|
/*
|
304 |
|
|
* Check for special events generated by embedded applications to
|
305 |
|
|
* request the input focus. If this is one of those events, make
|
306 |
|
|
* the change in focus and return without any additional processing
|
307 |
|
|
* of the event (note: the "detail" field of the event indicates
|
308 |
|
|
* whether to claim the focus even if we don't already have it).
|
309 |
|
|
*/
|
310 |
|
|
|
311 |
|
|
if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
|
312 |
|
|
&& (eventPtr->type == FocusIn)) {
|
313 |
|
|
TkSetFocusWin(winPtr, eventPtr->xfocus.detail);
|
314 |
|
|
return 0;
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
/*
|
318 |
|
|
* This was not a generated event. We'll return 1 (so that the
|
319 |
|
|
* event will be processed) if it's an Enter or Leave event, and
|
320 |
|
|
* 0 (so that the event won't be processed) if it's a FocusIn or
|
321 |
|
|
* FocusOut event.
|
322 |
|
|
*/
|
323 |
|
|
|
324 |
|
|
retValue = 0;
|
325 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
|
326 |
|
|
if (eventPtr->type == FocusIn) {
|
327 |
|
|
/*
|
328 |
|
|
* Skip FocusIn events that cause confusion
|
329 |
|
|
* NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur
|
330 |
|
|
* on windows in between the origin and destination of the
|
331 |
|
|
* focus change. For FocusIn we may see this when focus
|
332 |
|
|
* goes into an embedded child. We don't care about this,
|
333 |
|
|
* although we may end up getting a NotifyPointer later.
|
334 |
|
|
* NotifyInferior - focus is coming to us from an embedded child.
|
335 |
|
|
* When focus is on an embeded focus, we still think we have
|
336 |
|
|
* the focus, too, so this message doesn't change our state.
|
337 |
|
|
* NotifyPointerRoot - should never happen because this is sent
|
338 |
|
|
* to the root window.
|
339 |
|
|
*
|
340 |
|
|
* Interesting FocusIn events are
|
341 |
|
|
* NotifyAncestor - focus is coming from our parent, probably the root.
|
342 |
|
|
* NotifyNonlinear - focus is coming from a different branch, probably
|
343 |
|
|
* another toplevel.
|
344 |
|
|
* NotifyPointer - implicit focus because of the mouse position.
|
345 |
|
|
* This is only interesting on toplevels, when it means that the
|
346 |
|
|
* focus has been set to the root window but the mouse is over
|
347 |
|
|
* this toplevel. We take the focus implicitly (probably no
|
348 |
|
|
* window manager)
|
349 |
|
|
*/
|
350 |
|
|
|
351 |
|
|
if ((eventPtr->xfocus.detail == NotifyVirtual)
|
352 |
|
|
|| (eventPtr->xfocus.detail == NotifyNonlinearVirtual)
|
353 |
|
|
|| (eventPtr->xfocus.detail == NotifyPointerRoot)
|
354 |
|
|
|| (eventPtr->xfocus.detail == NotifyInferior)) {
|
355 |
|
|
return retValue;
|
356 |
|
|
}
|
357 |
|
|
} else if (eventPtr->type == FocusOut) {
|
358 |
|
|
/*
|
359 |
|
|
* Skip FocusOut events that cause confusion.
|
360 |
|
|
* NotifyPointer - the pointer is in us or a child, and we are losing
|
361 |
|
|
* focus because of an XSetInputFocus. Other focus events
|
362 |
|
|
* will set our state properly.
|
363 |
|
|
* NotifyPointerRoot - should never happen because this is sent
|
364 |
|
|
* to the root window.
|
365 |
|
|
* NotifyInferior - focus leaving us for an embedded child. We
|
366 |
|
|
* retain a notion of focus when an embedded child has focus.
|
367 |
|
|
*
|
368 |
|
|
* Interesting events are:
|
369 |
|
|
* NotifyAncestor - focus is going to root.
|
370 |
|
|
* NotifyNonlinear - focus is going to another branch, probably
|
371 |
|
|
* another toplevel.
|
372 |
|
|
* NotifyVirtual, NotifyNonlinearVirtual - focus is passing through,
|
373 |
|
|
* and we need to make sure we track this.
|
374 |
|
|
*/
|
375 |
|
|
|
376 |
|
|
if ((eventPtr->xfocus.detail == NotifyPointer)
|
377 |
|
|
|| (eventPtr->xfocus.detail == NotifyPointerRoot)
|
378 |
|
|
|| (eventPtr->xfocus.detail == NotifyInferior)) {
|
379 |
|
|
return retValue;
|
380 |
|
|
}
|
381 |
|
|
} else {
|
382 |
|
|
retValue = 1;
|
383 |
|
|
if (eventPtr->xcrossing.detail == NotifyInferior) {
|
384 |
|
|
return retValue;
|
385 |
|
|
}
|
386 |
|
|
}
|
387 |
|
|
|
388 |
|
|
/*
|
389 |
|
|
* If winPtr isn't a top-level window than just ignore the event.
|
390 |
|
|
*/
|
391 |
|
|
|
392 |
|
|
winPtr = TkWmFocusToplevel(winPtr);
|
393 |
|
|
if (winPtr == NULL) {
|
394 |
|
|
return retValue;
|
395 |
|
|
}
|
396 |
|
|
|
397 |
|
|
/*
|
398 |
|
|
* If there is a grab in effect and this window is outside the
|
399 |
|
|
* grabbed tree, then ignore the event.
|
400 |
|
|
*/
|
401 |
|
|
|
402 |
|
|
if (TkGrabState(winPtr) == TK_GRAB_EXCLUDED) {
|
403 |
|
|
return retValue;
|
404 |
|
|
}
|
405 |
|
|
|
406 |
|
|
/*
|
407 |
|
|
* It is possible that there were outstanding FocusIn and FocusOut
|
408 |
|
|
* events on their way to us at the time the focus was changed
|
409 |
|
|
* internally with the "focus" command. If so, these events could
|
410 |
|
|
* potentially cause us to lose the focus (switch it to the window
|
411 |
|
|
* of the last FocusIn event) even though the focus change occurred
|
412 |
|
|
* after those events. The following code detects this and ignores
|
413 |
|
|
* the stale events.
|
414 |
|
|
*
|
415 |
|
|
* Note: the focusSerial is only generated by TkpChangeFocus,
|
416 |
|
|
* whereas in Tk 4.2 there was always a nop marker generated.
|
417 |
|
|
*/
|
418 |
|
|
|
419 |
|
|
delta = eventPtr->xfocus.serial - displayFocusPtr->focusSerial;
|
420 |
|
|
if (delta < 0) {
|
421 |
|
|
return retValue;
|
422 |
|
|
}
|
423 |
|
|
|
424 |
|
|
/*
|
425 |
|
|
* Find the ToplevelFocusInfo structure for the window, and make a new one
|
426 |
|
|
* if there isn't one already.
|
427 |
|
|
*/
|
428 |
|
|
|
429 |
|
|
for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
|
430 |
|
|
tlFocusPtr = tlFocusPtr->nextPtr) {
|
431 |
|
|
if (tlFocusPtr->topLevelPtr == winPtr) {
|
432 |
|
|
break;
|
433 |
|
|
}
|
434 |
|
|
}
|
435 |
|
|
if (tlFocusPtr == NULL) {
|
436 |
|
|
tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
|
437 |
|
|
tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr;
|
438 |
|
|
tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
|
439 |
|
|
winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
|
440 |
|
|
}
|
441 |
|
|
newFocusPtr = tlFocusPtr->focusWinPtr;
|
442 |
|
|
|
443 |
|
|
if (eventPtr->type == FocusIn) {
|
444 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
|
445 |
|
|
displayFocusPtr->focusWinPtr = newFocusPtr;
|
446 |
|
|
dispPtr->focusPtr = newFocusPtr;
|
447 |
|
|
|
448 |
|
|
/*
|
449 |
|
|
* NotifyPointer gets set when the focus has been set to the root window
|
450 |
|
|
* but we have the pointer. We'll treat this like an implicit
|
451 |
|
|
* focus in event so that upon Leave events we release focus.
|
452 |
|
|
*/
|
453 |
|
|
|
454 |
|
|
if (!(winPtr->flags & TK_EMBEDDED)) {
|
455 |
|
|
if (eventPtr->xfocus.detail == NotifyPointer) {
|
456 |
|
|
dispPtr->implicitWinPtr = winPtr;
|
457 |
|
|
} else {
|
458 |
|
|
dispPtr->implicitWinPtr = NULL;
|
459 |
|
|
}
|
460 |
|
|
}
|
461 |
|
|
} else if (eventPtr->type == FocusOut) {
|
462 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr, (TkWindow *) NULL);
|
463 |
|
|
|
464 |
|
|
/*
|
465 |
|
|
* Reset dispPtr->focusPtr, but only if it currently is the same
|
466 |
|
|
* as this application's focusWinPtr: this check is needed to
|
467 |
|
|
* handle embedded applications in the same process.
|
468 |
|
|
*/
|
469 |
|
|
|
470 |
|
|
if (dispPtr->focusPtr == displayFocusPtr->focusWinPtr) {
|
471 |
|
|
dispPtr->focusPtr = NULL;
|
472 |
|
|
}
|
473 |
|
|
displayFocusPtr->focusWinPtr = NULL;
|
474 |
|
|
} else if (eventPtr->type == EnterNotify) {
|
475 |
|
|
/*
|
476 |
|
|
* If there is no window manager, or if the window manager isn't
|
477 |
|
|
* moving the focus around (e.g. the disgusting "NoTitleFocus"
|
478 |
|
|
* option has been selected in twm), then we won't get FocusIn
|
479 |
|
|
* or FocusOut events. Instead, the "focus" field will be set
|
480 |
|
|
* in an Enter event to indicate that we've already got the focus
|
481 |
|
|
* when the mouse enters the window (even though we didn't get
|
482 |
|
|
* a FocusIn event). Watch for this and grab the focus when it
|
483 |
|
|
* happens. Note: if this is an embedded application then don't
|
484 |
|
|
* accept the focus implicitly like this; the container
|
485 |
|
|
* application will give us the focus explicitly if it wants us
|
486 |
|
|
* to have it.
|
487 |
|
|
*/
|
488 |
|
|
|
489 |
|
|
if (eventPtr->xcrossing.focus &&
|
490 |
|
|
(displayFocusPtr->focusWinPtr == NULL)
|
491 |
|
|
&& !(winPtr->flags & TK_EMBEDDED)) {
|
492 |
|
|
if (dispPtr->focusDebug) {
|
493 |
|
|
printf("Focussed implicitly on %s\n",
|
494 |
|
|
newFocusPtr->pathName);
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
|
498 |
|
|
displayFocusPtr->focusWinPtr = newFocusPtr;
|
499 |
|
|
dispPtr->implicitWinPtr = winPtr;
|
500 |
|
|
dispPtr->focusPtr = newFocusPtr;
|
501 |
|
|
}
|
502 |
|
|
} else if (eventPtr->type == LeaveNotify) {
|
503 |
|
|
/*
|
504 |
|
|
* If the pointer just left a window for which we automatically
|
505 |
|
|
* claimed the focus on enter, move the focus back to the root
|
506 |
|
|
* window, where it was before we claimed it above. Note:
|
507 |
|
|
* dispPtr->implicitWinPtr may not be the same as
|
508 |
|
|
* displayFocusPtr->focusWinPtr (e.g. because the "focus"
|
509 |
|
|
* command was used to redirect the focus after it arrived at
|
510 |
|
|
* dispPtr->implicitWinPtr)!! In addition, we generate events
|
511 |
|
|
* because the window manager won't give us a FocusOut event when
|
512 |
|
|
* we focus on the root.
|
513 |
|
|
*/
|
514 |
|
|
|
515 |
|
|
if ((dispPtr->implicitWinPtr != NULL)
|
516 |
|
|
&& !(winPtr->flags & TK_EMBEDDED)) {
|
517 |
|
|
if (dispPtr->focusDebug) {
|
518 |
|
|
printf("Defocussed implicit Async\n");
|
519 |
|
|
}
|
520 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr,
|
521 |
|
|
(TkWindow *) NULL);
|
522 |
|
|
XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot,
|
523 |
|
|
CurrentTime);
|
524 |
|
|
displayFocusPtr->focusWinPtr = NULL;
|
525 |
|
|
dispPtr->implicitWinPtr = NULL;
|
526 |
|
|
}
|
527 |
|
|
}
|
528 |
|
|
return retValue;
|
529 |
|
|
}
|
530 |
|
|
|
531 |
|
|
/*
|
532 |
|
|
*----------------------------------------------------------------------
|
533 |
|
|
*
|
534 |
|
|
* TkSetFocusWin --
|
535 |
|
|
*
|
536 |
|
|
* This procedure is invoked to change the focus window for a
|
537 |
|
|
* given display in a given application.
|
538 |
|
|
*
|
539 |
|
|
* Results:
|
540 |
|
|
* None.
|
541 |
|
|
*
|
542 |
|
|
* Side effects:
|
543 |
|
|
* Event handlers may be invoked to process the change of
|
544 |
|
|
* focus.
|
545 |
|
|
*
|
546 |
|
|
*----------------------------------------------------------------------
|
547 |
|
|
*/
|
548 |
|
|
|
549 |
|
|
void
|
550 |
|
|
TkSetFocusWin(winPtr, force)
|
551 |
|
|
TkWindow *winPtr; /* Window that is to be the new focus for
|
552 |
|
|
* its display and application. */
|
553 |
|
|
int force; /* If non-zero, set the X focus to this
|
554 |
|
|
* window even if the application doesn't
|
555 |
|
|
* currently have the X focus. */
|
556 |
|
|
{
|
557 |
|
|
ToplevelFocusInfo *tlFocusPtr;
|
558 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
559 |
|
|
TkWindow *topLevelPtr;
|
560 |
|
|
int allMapped, serial;
|
561 |
|
|
|
562 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
|
563 |
|
|
|
564 |
|
|
/*
|
565 |
|
|
* If force is set, we should make sure we grab the focus regardless
|
566 |
|
|
* of the current focus window since under Windows, we may need to
|
567 |
|
|
* take control away from another application.
|
568 |
|
|
*/
|
569 |
|
|
|
570 |
|
|
if (winPtr == displayFocusPtr->focusWinPtr && !force) {
|
571 |
|
|
return;
|
572 |
|
|
}
|
573 |
|
|
|
574 |
|
|
/*
|
575 |
|
|
* Find the top-level window for winPtr, then find (or create)
|
576 |
|
|
* a record for the top-level. Also see whether winPtr and all its
|
577 |
|
|
* ancestors are mapped.
|
578 |
|
|
*/
|
579 |
|
|
|
580 |
|
|
allMapped = 1;
|
581 |
|
|
for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr) {
|
582 |
|
|
if (topLevelPtr == NULL) {
|
583 |
|
|
/*
|
584 |
|
|
* The window is being deleted. No point in worrying about
|
585 |
|
|
* giving it the focus.
|
586 |
|
|
*/
|
587 |
|
|
return;
|
588 |
|
|
}
|
589 |
|
|
if (!(topLevelPtr->flags & TK_MAPPED)) {
|
590 |
|
|
allMapped = 0;
|
591 |
|
|
}
|
592 |
|
|
if (topLevelPtr->flags & TK_TOP_LEVEL) {
|
593 |
|
|
break;
|
594 |
|
|
}
|
595 |
|
|
}
|
596 |
|
|
|
597 |
|
|
/*
|
598 |
|
|
* If the new focus window isn't mapped, then we can't focus on it
|
599 |
|
|
* (X will generate an error, for example). Instead, create an
|
600 |
|
|
* event handler that will set the focus to this window once it gets
|
601 |
|
|
* mapped. At the same time, delete any old handler that might be
|
602 |
|
|
* around; it's no longer relevant.
|
603 |
|
|
*/
|
604 |
|
|
|
605 |
|
|
if (displayFocusPtr->focusOnMapPtr != NULL) {
|
606 |
|
|
Tk_DeleteEventHandler(
|
607 |
|
|
(Tk_Window) displayFocusPtr->focusOnMapPtr,
|
608 |
|
|
StructureNotifyMask, FocusMapProc,
|
609 |
|
|
(ClientData) displayFocusPtr->focusOnMapPtr);
|
610 |
|
|
displayFocusPtr->focusOnMapPtr = NULL;
|
611 |
|
|
}
|
612 |
|
|
if (!allMapped) {
|
613 |
|
|
Tk_CreateEventHandler((Tk_Window) winPtr,
|
614 |
|
|
VisibilityChangeMask, FocusMapProc,
|
615 |
|
|
(ClientData) winPtr);
|
616 |
|
|
displayFocusPtr->focusOnMapPtr = winPtr;
|
617 |
|
|
displayFocusPtr->forceFocus = force;
|
618 |
|
|
return;
|
619 |
|
|
}
|
620 |
|
|
|
621 |
|
|
for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
|
622 |
|
|
tlFocusPtr = tlFocusPtr->nextPtr) {
|
623 |
|
|
if (tlFocusPtr->topLevelPtr == topLevelPtr) {
|
624 |
|
|
break;
|
625 |
|
|
}
|
626 |
|
|
}
|
627 |
|
|
if (tlFocusPtr == NULL) {
|
628 |
|
|
tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
|
629 |
|
|
tlFocusPtr->topLevelPtr = topLevelPtr;
|
630 |
|
|
tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
|
631 |
|
|
winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
|
632 |
|
|
}
|
633 |
|
|
tlFocusPtr->focusWinPtr = winPtr;
|
634 |
|
|
|
635 |
|
|
/*
|
636 |
|
|
* Reset the window system's focus window and generate focus events,
|
637 |
|
|
* with two special cases:
|
638 |
|
|
*
|
639 |
|
|
* 1. If the application is embedded and doesn't currently have the
|
640 |
|
|
* focus, don't set the focus directly. Instead, see if the
|
641 |
|
|
* embedding code can claim the focus from the enclosing
|
642 |
|
|
* container.
|
643 |
|
|
* 2. Otherwise, if the application doesn't currently have the
|
644 |
|
|
* focus, don't change the window system's focus unless it was
|
645 |
|
|
* already in this application or "force" was specified.
|
646 |
|
|
*/
|
647 |
|
|
|
648 |
|
|
if ((topLevelPtr->flags & TK_EMBEDDED)
|
649 |
|
|
&& (displayFocusPtr->focusWinPtr == NULL)) {
|
650 |
|
|
TkpClaimFocus(topLevelPtr, force);
|
651 |
|
|
} else if ((displayFocusPtr->focusWinPtr != NULL) || force) {
|
652 |
|
|
/*
|
653 |
|
|
* Generate events to shift focus between Tk windows.
|
654 |
|
|
* We do this regardless of what TkpChangeFocus does with
|
655 |
|
|
* the real X focus so that Tk widgets track focus commands
|
656 |
|
|
* when there is no window manager. GenerateFocusEvents will
|
657 |
|
|
* set up a serial number marker so we discard focus events
|
658 |
|
|
* that are triggered by the ChangeFocus.
|
659 |
|
|
*/
|
660 |
|
|
|
661 |
|
|
serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force);
|
662 |
|
|
if (serial != 0) {
|
663 |
|
|
displayFocusPtr->focusSerial = serial;
|
664 |
|
|
}
|
665 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr, winPtr);
|
666 |
|
|
displayFocusPtr->focusWinPtr = winPtr;
|
667 |
|
|
winPtr->dispPtr->focusPtr = winPtr;
|
668 |
|
|
}
|
669 |
|
|
}
|
670 |
|
|
|
671 |
|
|
/*
|
672 |
|
|
*----------------------------------------------------------------------
|
673 |
|
|
*
|
674 |
|
|
* TkGetFocusWin --
|
675 |
|
|
*
|
676 |
|
|
* Given a window, this procedure returns the current focus
|
677 |
|
|
* window for its application and display.
|
678 |
|
|
*
|
679 |
|
|
* Results:
|
680 |
|
|
* The return value is a pointer to the window that currently
|
681 |
|
|
* has the input focus for the specified application and
|
682 |
|
|
* display, or NULL if none.
|
683 |
|
|
*
|
684 |
|
|
* Side effects:
|
685 |
|
|
* None.
|
686 |
|
|
*
|
687 |
|
|
*----------------------------------------------------------------------
|
688 |
|
|
*/
|
689 |
|
|
|
690 |
|
|
TkWindow *
|
691 |
|
|
TkGetFocusWin(winPtr)
|
692 |
|
|
TkWindow *winPtr; /* Window that selects an application
|
693 |
|
|
* and a display. */
|
694 |
|
|
{
|
695 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
696 |
|
|
|
697 |
|
|
if (winPtr == NULL) {
|
698 |
|
|
return (TkWindow *) NULL;
|
699 |
|
|
}
|
700 |
|
|
|
701 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
|
702 |
|
|
return displayFocusPtr->focusWinPtr;
|
703 |
|
|
}
|
704 |
|
|
|
705 |
|
|
/*
|
706 |
|
|
*----------------------------------------------------------------------
|
707 |
|
|
*
|
708 |
|
|
* TkFocusKeyEvent --
|
709 |
|
|
*
|
710 |
|
|
* Given a window and a key press or release event that arrived for
|
711 |
|
|
* the window, use information about the keyboard focus to compute
|
712 |
|
|
* which window should really get the event. In addition, update
|
713 |
|
|
* the event to refer to its new window.
|
714 |
|
|
*
|
715 |
|
|
* Results:
|
716 |
|
|
* The return value is a pointer to the window that has the input
|
717 |
|
|
* focus in winPtr's application, or NULL if winPtr's application
|
718 |
|
|
* doesn't have the input focus. If a non-NULL value is returned,
|
719 |
|
|
* eventPtr will be updated to refer properly to the focus window.
|
720 |
|
|
*
|
721 |
|
|
* Side effects:
|
722 |
|
|
* None.
|
723 |
|
|
*
|
724 |
|
|
*----------------------------------------------------------------------
|
725 |
|
|
*/
|
726 |
|
|
|
727 |
|
|
TkWindow *
|
728 |
|
|
TkFocusKeyEvent(winPtr, eventPtr)
|
729 |
|
|
TkWindow *winPtr; /* Window that selects an application
|
730 |
|
|
* and a display. */
|
731 |
|
|
XEvent *eventPtr; /* X event to redirect (should be KeyPress
|
732 |
|
|
* or KeyRelease). */
|
733 |
|
|
{
|
734 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
735 |
|
|
TkWindow *focusWinPtr;
|
736 |
|
|
int focusX, focusY, vRootX, vRootY, vRootWidth, vRootHeight;
|
737 |
|
|
|
738 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
|
739 |
|
|
focusWinPtr = displayFocusPtr->focusWinPtr;
|
740 |
|
|
|
741 |
|
|
/*
|
742 |
|
|
* The code below is a debugging aid to make sure that dispPtr->focusPtr
|
743 |
|
|
* is kept properly in sync with the "truth", which is the value in
|
744 |
|
|
* displayFocusPtr->focusWinPtr.
|
745 |
|
|
*/
|
746 |
|
|
|
747 |
|
|
#ifdef TCL_MEM_DEBUG
|
748 |
|
|
if (focusWinPtr != winPtr->dispPtr->focusPtr) {
|
749 |
|
|
printf("TkFocusKeyEvent found dispPtr->focusPtr out of sync:\n");
|
750 |
|
|
printf("expected %s, got %s\n",
|
751 |
|
|
(focusWinPtr != NULL) ? focusWinPtr->pathName : "??",
|
752 |
|
|
(winPtr->dispPtr->focusPtr != NULL) ?
|
753 |
|
|
winPtr->dispPtr->focusPtr->pathName : "??");
|
754 |
|
|
}
|
755 |
|
|
#endif
|
756 |
|
|
|
757 |
|
|
if ((focusWinPtr != NULL) && (focusWinPtr->mainPtr == winPtr->mainPtr)) {
|
758 |
|
|
/*
|
759 |
|
|
* Map the x and y coordinates to make sense in the context of
|
760 |
|
|
* the focus window, if possible (make both -1 if the map-from
|
761 |
|
|
* and map-to windows don't share the same screen).
|
762 |
|
|
*/
|
763 |
|
|
|
764 |
|
|
if ((focusWinPtr->display != winPtr->display)
|
765 |
|
|
|| (focusWinPtr->screenNum != winPtr->screenNum)) {
|
766 |
|
|
eventPtr->xkey.x = -1;
|
767 |
|
|
eventPtr->xkey.y = -1;
|
768 |
|
|
} else {
|
769 |
|
|
Tk_GetVRootGeometry((Tk_Window) focusWinPtr, &vRootX, &vRootY,
|
770 |
|
|
&vRootWidth, &vRootHeight);
|
771 |
|
|
Tk_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY);
|
772 |
|
|
eventPtr->xkey.x = eventPtr->xkey.x_root - vRootX - focusX;
|
773 |
|
|
eventPtr->xkey.y = eventPtr->xkey.y_root - vRootY - focusY;
|
774 |
|
|
}
|
775 |
|
|
eventPtr->xkey.window = focusWinPtr->window;
|
776 |
|
|
return focusWinPtr;
|
777 |
|
|
}
|
778 |
|
|
|
779 |
|
|
/*
|
780 |
|
|
* The event doesn't belong to us. Perhaps, due to embedding, it
|
781 |
|
|
* really belongs to someone else. Give the embedding code a chance
|
782 |
|
|
* to redirect the event.
|
783 |
|
|
*/
|
784 |
|
|
|
785 |
|
|
TkpRedirectKeyEvent(winPtr, eventPtr);
|
786 |
|
|
return (TkWindow *) NULL;
|
787 |
|
|
}
|
788 |
|
|
|
789 |
|
|
/*
|
790 |
|
|
*----------------------------------------------------------------------
|
791 |
|
|
*
|
792 |
|
|
* TkFocusDeadWindow --
|
793 |
|
|
*
|
794 |
|
|
* This procedure is invoked when it is determined that
|
795 |
|
|
* a window is dead. It cleans up focus-related information
|
796 |
|
|
* about the window.
|
797 |
|
|
*
|
798 |
|
|
* Results:
|
799 |
|
|
* None.
|
800 |
|
|
*
|
801 |
|
|
* Side effects:
|
802 |
|
|
* Various things get cleaned up and recycled.
|
803 |
|
|
*
|
804 |
|
|
*----------------------------------------------------------------------
|
805 |
|
|
*/
|
806 |
|
|
|
807 |
|
|
void
|
808 |
|
|
TkFocusDeadWindow(winPtr)
|
809 |
|
|
register TkWindow *winPtr; /* Information about the window
|
810 |
|
|
* that is being deleted. */
|
811 |
|
|
{
|
812 |
|
|
ToplevelFocusInfo *tlFocusPtr, *prevPtr;
|
813 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
814 |
|
|
TkDisplay *dispPtr = winPtr->dispPtr;
|
815 |
|
|
|
816 |
|
|
/*
|
817 |
|
|
* Search for focus records that refer to this window either as
|
818 |
|
|
* the top-level window or the current focus window.
|
819 |
|
|
*/
|
820 |
|
|
|
821 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
|
822 |
|
|
for (prevPtr = NULL, tlFocusPtr = winPtr->mainPtr->tlFocusPtr;
|
823 |
|
|
tlFocusPtr != NULL;
|
824 |
|
|
prevPtr = tlFocusPtr, tlFocusPtr = tlFocusPtr->nextPtr) {
|
825 |
|
|
if (winPtr == tlFocusPtr->topLevelPtr) {
|
826 |
|
|
/*
|
827 |
|
|
* The top-level window is the one being deleted: free
|
828 |
|
|
* the focus record and release the focus back to PointerRoot
|
829 |
|
|
* if we acquired it implicitly.
|
830 |
|
|
*/
|
831 |
|
|
|
832 |
|
|
if (dispPtr->implicitWinPtr == winPtr) {
|
833 |
|
|
if (dispPtr->focusDebug) {
|
834 |
|
|
printf("releasing focus to root after %s died\n",
|
835 |
|
|
tlFocusPtr->topLevelPtr->pathName);
|
836 |
|
|
}
|
837 |
|
|
dispPtr->implicitWinPtr = NULL;
|
838 |
|
|
displayFocusPtr->focusWinPtr = NULL;
|
839 |
|
|
dispPtr->focusPtr = NULL;
|
840 |
|
|
}
|
841 |
|
|
if (displayFocusPtr->focusWinPtr == tlFocusPtr->focusWinPtr) {
|
842 |
|
|
displayFocusPtr->focusWinPtr = NULL;
|
843 |
|
|
dispPtr->focusPtr = NULL;
|
844 |
|
|
}
|
845 |
|
|
if (prevPtr == NULL) {
|
846 |
|
|
winPtr->mainPtr->tlFocusPtr = tlFocusPtr->nextPtr;
|
847 |
|
|
} else {
|
848 |
|
|
prevPtr->nextPtr = tlFocusPtr->nextPtr;
|
849 |
|
|
}
|
850 |
|
|
ckfree((char *) tlFocusPtr);
|
851 |
|
|
break;
|
852 |
|
|
} else if (winPtr == tlFocusPtr->focusWinPtr) {
|
853 |
|
|
/*
|
854 |
|
|
* The deleted window had the focus for its top-level:
|
855 |
|
|
* move the focus to the top-level itself.
|
856 |
|
|
*/
|
857 |
|
|
|
858 |
|
|
tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
|
859 |
|
|
if ((displayFocusPtr->focusWinPtr == winPtr)
|
860 |
|
|
&& !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) {
|
861 |
|
|
if (dispPtr->focusDebug) {
|
862 |
|
|
printf("forwarding focus to %s after %s died\n",
|
863 |
|
|
tlFocusPtr->topLevelPtr->pathName,
|
864 |
|
|
winPtr->pathName);
|
865 |
|
|
}
|
866 |
|
|
GenerateFocusEvents(displayFocusPtr->focusWinPtr,
|
867 |
|
|
tlFocusPtr->topLevelPtr);
|
868 |
|
|
displayFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
|
869 |
|
|
dispPtr->focusPtr = tlFocusPtr->topLevelPtr;
|
870 |
|
|
}
|
871 |
|
|
break;
|
872 |
|
|
}
|
873 |
|
|
}
|
874 |
|
|
|
875 |
|
|
if (displayFocusPtr->focusOnMapPtr == winPtr) {
|
876 |
|
|
displayFocusPtr->focusOnMapPtr = NULL;
|
877 |
|
|
}
|
878 |
|
|
}
|
879 |
|
|
|
880 |
|
|
/*
|
881 |
|
|
*----------------------------------------------------------------------
|
882 |
|
|
*
|
883 |
|
|
* GenerateFocusEvents --
|
884 |
|
|
*
|
885 |
|
|
* This procedure is called to create FocusIn and FocusOut events to
|
886 |
|
|
* move the input focus from one window to another.
|
887 |
|
|
*
|
888 |
|
|
* Results:
|
889 |
|
|
* None.
|
890 |
|
|
*
|
891 |
|
|
* Side effects:
|
892 |
|
|
* FocusIn and FocusOut events are generated.
|
893 |
|
|
*
|
894 |
|
|
*----------------------------------------------------------------------
|
895 |
|
|
*/
|
896 |
|
|
|
897 |
|
|
static void
|
898 |
|
|
GenerateFocusEvents(sourcePtr, destPtr)
|
899 |
|
|
TkWindow *sourcePtr; /* Window that used to have the focus (may
|
900 |
|
|
* be NULL). */
|
901 |
|
|
TkWindow *destPtr; /* New window to have the focus (may be
|
902 |
|
|
* NULL). */
|
903 |
|
|
|
904 |
|
|
{
|
905 |
|
|
XEvent event;
|
906 |
|
|
TkWindow *winPtr;
|
907 |
|
|
|
908 |
|
|
winPtr = sourcePtr;
|
909 |
|
|
if (winPtr == NULL) {
|
910 |
|
|
winPtr = destPtr;
|
911 |
|
|
if (winPtr == NULL) {
|
912 |
|
|
return;
|
913 |
|
|
}
|
914 |
|
|
}
|
915 |
|
|
|
916 |
|
|
event.xfocus.serial = LastKnownRequestProcessed(winPtr->display);
|
917 |
|
|
event.xfocus.send_event = GENERATED_EVENT_MAGIC;
|
918 |
|
|
event.xfocus.display = winPtr->display;
|
919 |
|
|
event.xfocus.mode = NotifyNormal;
|
920 |
|
|
TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn,
|
921 |
|
|
TCL_QUEUE_MARK);
|
922 |
|
|
}
|
923 |
|
|
|
924 |
|
|
/*
|
925 |
|
|
*----------------------------------------------------------------------
|
926 |
|
|
*
|
927 |
|
|
* FocusMapProc --
|
928 |
|
|
*
|
929 |
|
|
* This procedure is called as an event handler for VisibilityNotify
|
930 |
|
|
* events, if a window receives the focus at a time when its
|
931 |
|
|
* toplevel isn't mapped. The procedure is needed because X
|
932 |
|
|
* won't allow the focus to be set to an unmapped window; we
|
933 |
|
|
* detect when the toplevel is mapped and set the focus to it then.
|
934 |
|
|
*
|
935 |
|
|
* Results:
|
936 |
|
|
* None.
|
937 |
|
|
*
|
938 |
|
|
* Side effects:
|
939 |
|
|
* If this is a map event, the focus gets set to the toplevel
|
940 |
|
|
* given by clientData.
|
941 |
|
|
*
|
942 |
|
|
*----------------------------------------------------------------------
|
943 |
|
|
*/
|
944 |
|
|
|
945 |
|
|
static void
|
946 |
|
|
FocusMapProc(clientData, eventPtr)
|
947 |
|
|
ClientData clientData; /* Toplevel window. */
|
948 |
|
|
XEvent *eventPtr; /* Information about event. */
|
949 |
|
|
{
|
950 |
|
|
TkWindow *winPtr = (TkWindow *) clientData;
|
951 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
952 |
|
|
|
953 |
|
|
if (eventPtr->type == VisibilityNotify) {
|
954 |
|
|
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr,
|
955 |
|
|
winPtr->dispPtr);
|
956 |
|
|
if (winPtr->dispPtr->focusDebug) {
|
957 |
|
|
printf("auto-focussing on %s, force %d\n", winPtr->pathName,
|
958 |
|
|
displayFocusPtr->forceFocus);
|
959 |
|
|
}
|
960 |
|
|
Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask,
|
961 |
|
|
FocusMapProc, clientData);
|
962 |
|
|
displayFocusPtr->focusOnMapPtr = NULL;
|
963 |
|
|
TkSetFocusWin(winPtr, displayFocusPtr->forceFocus);
|
964 |
|
|
}
|
965 |
|
|
}
|
966 |
|
|
|
967 |
|
|
/*
|
968 |
|
|
*----------------------------------------------------------------------
|
969 |
|
|
*
|
970 |
|
|
* FindDisplayFocusInfo --
|
971 |
|
|
*
|
972 |
|
|
* Given an application and a display, this procedure locate the
|
973 |
|
|
* focus record for that combination. If no such record exists,
|
974 |
|
|
* it creates a new record and initializes it.
|
975 |
|
|
*
|
976 |
|
|
* Results:
|
977 |
|
|
* The return value is a pointer to the record.
|
978 |
|
|
*
|
979 |
|
|
* Side effects:
|
980 |
|
|
* A new record will be allocated if there wasn't one already.
|
981 |
|
|
*
|
982 |
|
|
*----------------------------------------------------------------------
|
983 |
|
|
*/
|
984 |
|
|
|
985 |
|
|
static DisplayFocusInfo *
|
986 |
|
|
FindDisplayFocusInfo(mainPtr, dispPtr)
|
987 |
|
|
TkMainInfo *mainPtr; /* Record that identifies a particular
|
988 |
|
|
* application. */
|
989 |
|
|
TkDisplay *dispPtr; /* Display whose focus information is
|
990 |
|
|
* needed. */
|
991 |
|
|
{
|
992 |
|
|
DisplayFocusInfo *displayFocusPtr;
|
993 |
|
|
|
994 |
|
|
for (displayFocusPtr = mainPtr->displayFocusPtr;
|
995 |
|
|
displayFocusPtr != NULL;
|
996 |
|
|
displayFocusPtr = displayFocusPtr->nextPtr) {
|
997 |
|
|
if (displayFocusPtr->dispPtr == dispPtr) {
|
998 |
|
|
return displayFocusPtr;
|
999 |
|
|
}
|
1000 |
|
|
}
|
1001 |
|
|
|
1002 |
|
|
/*
|
1003 |
|
|
* The record doesn't exist yet. Make a new one.
|
1004 |
|
|
*/
|
1005 |
|
|
|
1006 |
|
|
displayFocusPtr = (DisplayFocusInfo *) ckalloc(sizeof(DisplayFocusInfo));
|
1007 |
|
|
displayFocusPtr->dispPtr = dispPtr;
|
1008 |
|
|
displayFocusPtr->focusWinPtr = NULL;
|
1009 |
|
|
displayFocusPtr->focusOnMapPtr = NULL;
|
1010 |
|
|
displayFocusPtr->forceFocus = 0;
|
1011 |
|
|
displayFocusPtr->focusSerial = 0;
|
1012 |
|
|
displayFocusPtr->nextPtr = mainPtr->displayFocusPtr;
|
1013 |
|
|
mainPtr->displayFocusPtr = displayFocusPtr;
|
1014 |
|
|
return displayFocusPtr;
|
1015 |
|
|
}
|
1016 |
|
|
|
1017 |
|
|
|
1018 |
|
|
/* $History: tkFocus.c $
|
1019 |
|
|
*
|
1020 |
|
|
* ***************** Version 1 *****************
|
1021 |
|
|
* User: Dtashley Date: 1/02/01 Time: 2:49a
|
1022 |
|
|
* Created in $/IjuScripter, IjuConsole/Source/Tk Base
|
1023 |
|
|
* Initial check-in.
|
1024 |
|
|
*/
|
1025 |
|
|
|
1026 |
|
|
/* End of TKFOCUS.C */ |