4
* This file contains procedures that manage the input
7
* Copyright (c) 1990-1994 The Regents of the University of California.
8
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
10
* See the file "license.terms" for information on usage and redistribution
11
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
* RCS: @(#) $Id: tkFocus.c,v 1.3 1999/02/04 20:53:53 stanton Exp $
21
* For each top-level window that has ever received the focus, there
22
* is a record of the following type:
25
typedef struct TkToplevelFocusInfo {
26
TkWindow *topLevelPtr; /* Information about top-level window. */
27
TkWindow *focusWinPtr; /* The next time the focus comes to this
28
* top-level, it will be given to this
30
struct TkToplevelFocusInfo *nextPtr;
31
/* Next in list of all toplevel focus records
32
* for a given application. */
36
* One of the following structures exists for each display used by
37
* each application. These are linked together from the TkMainInfo
38
* structure. These structures are needed because it isn't
39
* sufficient to store a single piece of focus information in each
40
* display or in each application: we need the cross-product.
41
* There needs to be separate information for each display, because
42
* it's possible to have multiple focus windows active simultaneously
43
* on different displays. There also needs to be separate information
44
* for each application, because of embedding: if an embedded
45
* application has the focus, its container application also has
46
* the focus. Thus we keep a list of structures for each application:
47
* the same display can appear in structures for several applications
51
typedef struct TkDisplayFocusInfo {
52
TkDisplay *dispPtr; /* Display that this information pertains
54
struct TkWindow *focusWinPtr;
55
/* Window that currently has the focus for
56
* this application on this display, or NULL
58
struct TkWindow *focusOnMapPtr;
59
/* This points to a toplevel window that is
60
* supposed to receive the X input focus as
61
* soon as it is mapped (needed to handle the
62
* fact that X won't allow the focus on an
63
* unmapped window). NULL means no delayed
64
* focus op in progress for this display. */
65
int forceFocus; /* Associated with focusOnMapPtr: non-zero
66
* means claim the focus even if some other
67
* application currently has it. */
68
unsigned long focusSerial; /* Serial number of last request this
69
* application made to change the focus on
70
* this display. Used to identify stale
71
* focus notifications coming from the
73
struct TkDisplayFocusInfo *nextPtr;
74
/* Next in list of all display focus
75
* records for a given application. */
79
* Global used for debugging.
82
int tclFocusDebug = 0;
85
* The following magic value is stored in the "send_event" field of
86
* FocusIn and FocusOut events that are generated in this file. This
87
* allows us to separate "real" events coming from the server from
88
* those that we generated.
91
#define GENERATED_EVENT_MAGIC ((Bool) 0x547321ac)
94
* Forward declarations for procedures defined in this file:
98
static DisplayFocusInfo *FindDisplayFocusInfo _ANSI_ARGS_((TkMainInfo *mainPtr,
100
static void FocusMapProc _ANSI_ARGS_((ClientData clientData,
102
static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr,
104
static void SetFocus _ANSI_ARGS_((TkWindow *winPtr, int force));
107
*--------------------------------------------------------------
111
* This procedure is invoked to process the "focus" Tcl command.
112
* See the user documentation for details on what it does.
115
* A standard Tcl result.
118
* See the user documentation.
120
*--------------------------------------------------------------
124
Tk_FocusCmd(clientData, interp, argc, argv)
125
ClientData clientData; /* Main window associated with
127
Tcl_Interp *interp; /* Current interpreter. */
128
int argc; /* Number of arguments. */
129
char **argv; /* Argument strings. */
131
Tk_Window tkwin = (Tk_Window) clientData;
132
TkWindow *winPtr = (TkWindow *) clientData;
133
TkWindow *newPtr, *focusWinPtr, *topLevelPtr;
134
ToplevelFocusInfo *tlFocusPtr;
139
* If invoked with no arguments, just return the current focus window.
143
focusWinPtr = TkGetFocusWin(winPtr);
144
if (focusWinPtr != NULL) {
145
interp->result = focusWinPtr->pathName;
151
* If invoked with a single argument beginning with "." then focus
156
if (argv[1][0] == 0) {
159
if (argv[1][0] == '.') {
160
newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
161
if (newPtr == NULL) {
164
if (!(newPtr->flags & TK_ALREADY_DEAD)) {
171
length = strlen(argv[1]);
173
if ((c == 'd') && (strncmp(argv[1], "-displayof", length) == 0)) {
175
Tcl_AppendResult(interp, "wrong # args: should be \"",
176
argv[0], " -displayof window\"", (char *) NULL);
179
newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
180
if (newPtr == NULL) {
183
newPtr = TkGetFocusWin(newPtr);
184
if (newPtr != NULL) {
185
interp->result = newPtr->pathName;
187
} else if ((c == 'f') && (strncmp(argv[1], "-force", length) == 0)) {
189
Tcl_AppendResult(interp, "wrong # args: should be \"",
190
argv[0], " -force window\"", (char *) NULL);
193
if (argv[2][0] == 0) {
196
newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
197
if (newPtr == NULL) {
201
} else if ((c == 'l') && (strncmp(argv[1], "-lastfor", length) == 0)) {
203
Tcl_AppendResult(interp, "wrong # args: should be \"",
204
argv[0], " -lastfor window\"", (char *) NULL);
207
newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
208
if (newPtr == NULL) {
211
for (topLevelPtr = newPtr; topLevelPtr != NULL;
212
topLevelPtr = topLevelPtr->parentPtr) {
213
if (topLevelPtr->flags & TK_TOP_LEVEL) {
214
for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr;
216
tlFocusPtr = tlFocusPtr->nextPtr) {
217
if (tlFocusPtr->topLevelPtr == topLevelPtr) {
218
interp->result = tlFocusPtr->focusWinPtr->pathName;
222
interp->result = topLevelPtr->pathName;
227
Tcl_AppendResult(interp, "bad option \"", argv[1],
228
"\": must be -displayof, -force, or -lastfor", (char *) NULL);
235
*--------------------------------------------------------------
237
* TkFocusFilterEvent --
239
* This procedure is invoked by Tk_HandleEvent when it encounters
240
* a FocusIn, FocusOut, Enter, or Leave event.
243
* A return value of 1 means that Tk_HandleEvent should process
244
* the event normally (i.e. event handlers should be invoked).
245
* A return value of 0 means that this event should be ignored.
248
* Additional events may be generated, and the focus may switch.
250
*--------------------------------------------------------------
254
TkFocusFilterEvent(winPtr, eventPtr)
255
TkWindow *winPtr; /* Window that focus event is directed to. */
256
XEvent *eventPtr; /* FocusIn, FocusOut, Enter, or Leave
260
* Design notes: the window manager and X server work together to
261
* transfer the focus among top-level windows. This procedure takes
262
* care of transferring the focus from a top-level or wrapper window
263
* to the actual window within that top-level that has the focus.
264
* We do this by synthesizing X events to move the focus around.
265
* None of the FocusIn and FocusOut events generated by X are ever
266
* used outside of this procedure; only the synthesized events get
267
* through to the rest of the application. At one point (e.g.
268
* Tk4.0b1) Tk used to call X to move the focus from a top-level to
269
* one of its descendants, then just pass through the events
270
* generated by X. This approach didn't work very well, for a
271
* variety of reasons. For example, if X generates the events they
272
* go at the back of the event queue, which could cause problems if
273
* other things have already happened, such as moving the focus to
274
* yet another window.
277
ToplevelFocusInfo *tlFocusPtr;
278
DisplayFocusInfo *displayFocusPtr;
279
TkDisplay *dispPtr = winPtr->dispPtr;
280
TkWindow *newFocusPtr;
284
* If this was a generated event, just turn off the generated
285
* flag and pass the event through to Tk bindings.
288
if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) {
289
eventPtr->xfocus.send_event = 0;
294
* Check for special events generated by embedded applications to
295
* request the input focus. If this is one of those events, make
296
* the change in focus and return without any additional processing
297
* of the event (note: the "detail" field of the event indicates
298
* whether to claim the focus even if we don't already have it).
301
if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
302
&& (eventPtr->type == FocusIn)) {
303
SetFocus(winPtr, eventPtr->xfocus.detail);
308
* This was not a generated event. We'll return 1 (so that the
309
* event will be processed) if it's an Enter or Leave event, and
310
* 0 (so that the event won't be processed) if it's a FocusIn or
315
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
316
if (eventPtr->type == FocusIn) {
318
* Skip FocusIn events that cause confusion
319
* NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur
320
* on windows in between the origin and destination of the
321
* focus change. For FocusIn we may see this when focus
322
* goes into an embedded child. We don't care about this,
323
* although we may end up getting a NotifyPointer later.
324
* NotifyInferior - focus is coming to us from an embedded child.
325
* When focus is on an embeded focus, we still think we have
326
* the focus, too, so this message doesn't change our state.
327
* NotifyPointerRoot - should never happen because this is sent
328
* to the root window.
330
* Interesting FocusIn events are
331
* NotifyAncestor - focus is coming from our parent, probably the root.
332
* NotifyNonlinear - focus is coming from a different branch, probably
334
* NotifyPointer - implicit focus because of the mouse position.
335
* This is only interesting on toplevels, when it means that the
336
* focus has been set to the root window but the mouse is over
337
* this toplevel. We take the focus implicitly (probably no
341
if ((eventPtr->xfocus.detail == NotifyVirtual)
342
|| (eventPtr->xfocus.detail == NotifyNonlinearVirtual)
343
|| (eventPtr->xfocus.detail == NotifyPointerRoot)
344
|| (eventPtr->xfocus.detail == NotifyInferior)) {
347
} else if (eventPtr->type == FocusOut) {
349
* Skip FocusOut events that cause confusion.
350
* NotifyPointer - the pointer is in us or a child, and we are losing
351
* focus because of an XSetInputFocus. Other focus events
352
* will set our state properly.
353
* NotifyPointerRoot - should never happen because this is sent
354
* to the root window.
355
* NotifyInferior - focus leaving us for an embedded child. We
356
* retain a notion of focus when an embedded child has focus.
358
* Interesting events are:
359
* NotifyAncestor - focus is going to root.
360
* NotifyNonlinear - focus is going to another branch, probably
362
* NotifyVirtual, NotifyNonlinearVirtual - focus is passing through,
363
* and we need to make sure we track this.
366
if ((eventPtr->xfocus.detail == NotifyPointer)
367
|| (eventPtr->xfocus.detail == NotifyPointerRoot)
368
|| (eventPtr->xfocus.detail == NotifyInferior)) {
373
if (eventPtr->xcrossing.detail == NotifyInferior) {
379
* If winPtr isn't a top-level window than just ignore the event.
382
winPtr = TkWmFocusToplevel(winPtr);
383
if (winPtr == NULL) {
388
* If there is a grab in effect and this window is outside the
389
* grabbed tree, then ignore the event.
392
if (TkGrabState(winPtr) == TK_GRAB_EXCLUDED) {
397
* It is possible that there were outstanding FocusIn and FocusOut
398
* events on their way to us at the time the focus was changed
399
* internally with the "focus" command. If so, these events could
400
* potentially cause us to lose the focus (switch it to the window
401
* of the last FocusIn event) even though the focus change occurred
402
* after those events. The following code detects this and ignores
405
* Note: the focusSerial is only generated by TkpChangeFocus,
406
* whereas in Tk 4.2 there was always a nop marker generated.
409
delta = eventPtr->xfocus.serial - displayFocusPtr->focusSerial;
415
* Find the ToplevelFocusInfo structure for the window, and make a new one
416
* if there isn't one already.
419
for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
420
tlFocusPtr = tlFocusPtr->nextPtr) {
421
if (tlFocusPtr->topLevelPtr == winPtr) {
425
if (tlFocusPtr == NULL) {
426
tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
427
tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr;
428
tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
429
winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
431
newFocusPtr = tlFocusPtr->focusWinPtr;
433
if (eventPtr->type == FocusIn) {
434
GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
435
displayFocusPtr->focusWinPtr = newFocusPtr;
436
dispPtr->focusPtr = newFocusPtr;
439
* NotifyPointer gets set when the focus has been set to the root window
440
* but we have the pointer. We'll treat this like an implicit
441
* focus in event so that upon Leave events we release focus.
444
if (!(winPtr->flags & TK_EMBEDDED)) {
445
if (eventPtr->xfocus.detail == NotifyPointer) {
446
dispPtr->implicitWinPtr = winPtr;
448
dispPtr->implicitWinPtr = NULL;
451
} else if (eventPtr->type == FocusOut) {
452
GenerateFocusEvents(displayFocusPtr->focusWinPtr, (TkWindow *) NULL);
455
* Reset dispPtr->focusPtr, but only if it currently is the same
456
* as this application's focusWinPtr: this check is needed to
457
* handle embedded applications in the same process.
460
if (dispPtr->focusPtr == displayFocusPtr->focusWinPtr) {
461
dispPtr->focusPtr = NULL;
463
displayFocusPtr->focusWinPtr = NULL;
464
} else if (eventPtr->type == EnterNotify) {
466
* If there is no window manager, or if the window manager isn't
467
* moving the focus around (e.g. the disgusting "NoTitleFocus"
468
* option has been selected in twm), then we won't get FocusIn
469
* or FocusOut events. Instead, the "focus" field will be set
470
* in an Enter event to indicate that we've already got the focus
471
* when the mouse enters the window (even though we didn't get
472
* a FocusIn event). Watch for this and grab the focus when it
473
* happens. Note: if this is an embedded application then don't
474
* accept the focus implicitly like this; the container
475
* application will give us the focus explicitly if it wants us
479
if (eventPtr->xcrossing.focus &&
480
(displayFocusPtr->focusWinPtr == NULL)
481
&& !(winPtr->flags & TK_EMBEDDED)) {
483
printf("Focussed implicitly on %s\n",
484
newFocusPtr->pathName);
487
GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
488
displayFocusPtr->focusWinPtr = newFocusPtr;
489
dispPtr->implicitWinPtr = winPtr;
490
dispPtr->focusPtr = newFocusPtr;
492
} else if (eventPtr->type == LeaveNotify) {
494
* If the pointer just left a window for which we automatically
495
* claimed the focus on enter, move the focus back to the root
496
* window, where it was before we claimed it above. Note:
497
* dispPtr->implicitWinPtr may not be the same as
498
* displayFocusPtr->focusWinPtr (e.g. because the "focus"
499
* command was used to redirect the focus after it arrived at
500
* dispPtr->implicitWinPtr)!! In addition, we generate events
501
* because the window manager won't give us a FocusOut event when
502
* we focus on the root.
505
if ((dispPtr->implicitWinPtr != NULL)
506
&& !(winPtr->flags & TK_EMBEDDED)) {
508
printf("Defocussed implicit Async\n");
510
GenerateFocusEvents(displayFocusPtr->focusWinPtr,
512
XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot,
514
displayFocusPtr->focusWinPtr = NULL;
515
dispPtr->implicitWinPtr = NULL;
522
*----------------------------------------------------------------------
526
* This procedure is invoked to change the focus window for a
527
* given display in a given application.
533
* Event handlers may be invoked to process the change of
536
*----------------------------------------------------------------------
540
SetFocus(winPtr, force)
541
TkWindow *winPtr; /* Window that is to be the new focus for
542
* its display and application. */
543
int force; /* If non-zero, set the X focus to this
544
* window even if the application doesn't
545
* currently have the X focus. */
547
ToplevelFocusInfo *tlFocusPtr;
548
DisplayFocusInfo *displayFocusPtr;
549
TkWindow *topLevelPtr;
550
int allMapped, serial;
552
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
555
* If force is set, we should make sure we grab the focus regardless
556
* of the current focus window since under Windows, we may need to
557
* take control away from another application.
560
if (winPtr == displayFocusPtr->focusWinPtr && !force) {
565
* Find the top-level window for winPtr, then find (or create)
566
* a record for the top-level. Also see whether winPtr and all its
567
* ancestors are mapped.
571
for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr) {
572
if (topLevelPtr == NULL) {
574
* The window is being deleted. No point in worrying about
575
* giving it the focus.
579
if (!(topLevelPtr->flags & TK_MAPPED)) {
582
if (topLevelPtr->flags & TK_TOP_LEVEL) {
588
* If the new focus window isn't mapped, then we can't focus on it
589
* (X will generate an error, for example). Instead, create an
590
* event handler that will set the focus to this window once it gets
591
* mapped. At the same time, delete any old handler that might be
592
* around; it's no longer relevant.
595
if (displayFocusPtr->focusOnMapPtr != NULL) {
596
Tk_DeleteEventHandler(
597
(Tk_Window) displayFocusPtr->focusOnMapPtr,
598
StructureNotifyMask, FocusMapProc,
599
(ClientData) displayFocusPtr->focusOnMapPtr);
600
displayFocusPtr->focusOnMapPtr = NULL;
603
Tk_CreateEventHandler((Tk_Window) winPtr,
604
VisibilityChangeMask, FocusMapProc,
605
(ClientData) winPtr);
606
displayFocusPtr->focusOnMapPtr = winPtr;
607
displayFocusPtr->forceFocus = force;
611
for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
612
tlFocusPtr = tlFocusPtr->nextPtr) {
613
if (tlFocusPtr->topLevelPtr == topLevelPtr) {
617
if (tlFocusPtr == NULL) {
618
tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
619
tlFocusPtr->topLevelPtr = topLevelPtr;
620
tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
621
winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
623
tlFocusPtr->focusWinPtr = winPtr;
626
* Reset the window system's focus window and generate focus events,
627
* with two special cases:
629
* 1. If the application is embedded and doesn't currently have the
630
* focus, don't set the focus directly. Instead, see if the
631
* embedding code can claim the focus from the enclosing
633
* 2. Otherwise, if the application doesn't currently have the
634
* focus, don't change the window system's focus unless it was
635
* already in this application or "force" was specified.
638
if ((topLevelPtr->flags & TK_EMBEDDED)
639
&& (displayFocusPtr->focusWinPtr == NULL)) {
640
TkpClaimFocus(topLevelPtr, force);
641
} else if ((displayFocusPtr->focusWinPtr != NULL) || force) {
643
* Generate events to shift focus between Tk windows.
644
* We do this regardless of what TkpChangeFocus does with
645
* the real X focus so that Tk widgets track focus commands
646
* when there is no window manager. GenerateFocusEvents will
647
* set up a serial number marker so we discard focus events
648
* that are triggered by the ChangeFocus.
651
serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force);
653
displayFocusPtr->focusSerial = serial;
655
GenerateFocusEvents(displayFocusPtr->focusWinPtr, winPtr);
656
displayFocusPtr->focusWinPtr = winPtr;
657
winPtr->dispPtr->focusPtr = winPtr;
662
*----------------------------------------------------------------------
666
* Given a window, this procedure returns the current focus
667
* window for its application and display.
670
* The return value is a pointer to the window that currently
671
* has the input focus for the specified application and
672
* display, or NULL if none.
677
*----------------------------------------------------------------------
681
TkGetFocusWin(winPtr)
682
TkWindow *winPtr; /* Window that selects an application
685
DisplayFocusInfo *displayFocusPtr;
687
if (winPtr == NULL) {
688
return (TkWindow *) NULL;
691
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
692
return displayFocusPtr->focusWinPtr;
696
*----------------------------------------------------------------------
700
* Given a window and a key press or release event that arrived for
701
* the window, use information about the keyboard focus to compute
702
* which window should really get the event. In addition, update
703
* the event to refer to its new window.
706
* The return value is a pointer to the window that has the input
707
* focus in winPtr's application, or NULL if winPtr's application
708
* doesn't have the input focus. If a non-NULL value is returned,
709
* eventPtr will be updated to refer properly to the focus window.
714
*----------------------------------------------------------------------
718
TkFocusKeyEvent(winPtr, eventPtr)
719
TkWindow *winPtr; /* Window that selects an application
721
XEvent *eventPtr; /* X event to redirect (should be KeyPress
724
DisplayFocusInfo *displayFocusPtr;
725
TkWindow *focusWinPtr;
726
int focusX, focusY, vRootX, vRootY, vRootWidth, vRootHeight;
728
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
729
focusWinPtr = displayFocusPtr->focusWinPtr;
732
* The code below is a debugging aid to make sure that dispPtr->focusPtr
733
* is kept properly in sync with the "truth", which is the value in
734
* displayFocusPtr->focusWinPtr.
738
if (focusWinPtr != winPtr->dispPtr->focusPtr) {
739
printf("TkFocusKeyEvent found dispPtr->focusPtr out of sync:\n");
740
printf("expected %s, got %s\n",
741
(focusWinPtr != NULL) ? focusWinPtr->pathName : "??",
742
(winPtr->dispPtr->focusPtr != NULL) ?
743
winPtr->dispPtr->focusPtr->pathName : "??");
747
if ((focusWinPtr != NULL) && (focusWinPtr->mainPtr == winPtr->mainPtr)) {
749
* Map the x and y coordinates to make sense in the context of
750
* the focus window, if possible (make both -1 if the map-from
751
* and map-to windows don't share the same screen).
754
if ((focusWinPtr->display != winPtr->display)
755
|| (focusWinPtr->screenNum != winPtr->screenNum)) {
756
eventPtr->xkey.x = -1;
757
eventPtr->xkey.y = -1;
759
Tk_GetVRootGeometry((Tk_Window) focusWinPtr, &vRootX, &vRootY,
760
&vRootWidth, &vRootHeight);
761
Tk_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY);
762
eventPtr->xkey.x = eventPtr->xkey.x_root - vRootX - focusX;
763
eventPtr->xkey.y = eventPtr->xkey.y_root - vRootY - focusY;
765
eventPtr->xkey.window = focusWinPtr->window;
770
* The event doesn't belong to us. Perhaps, due to embedding, it
771
* really belongs to someone else. Give the embedding code a chance
772
* to redirect the event.
775
TkpRedirectKeyEvent(winPtr, eventPtr);
776
return (TkWindow *) NULL;
780
*----------------------------------------------------------------------
782
* TkFocusDeadWindow --
784
* This procedure is invoked when it is determined that
785
* a window is dead. It cleans up focus-related information
792
* Various things get cleaned up and recycled.
794
*----------------------------------------------------------------------
798
TkFocusDeadWindow(winPtr)
799
register TkWindow *winPtr; /* Information about the window
800
* that is being deleted. */
802
ToplevelFocusInfo *tlFocusPtr, *prevPtr;
803
DisplayFocusInfo *displayFocusPtr;
804
TkDisplay *dispPtr = winPtr->dispPtr;
807
* Search for focus records that refer to this window either as
808
* the top-level window or the current focus window.
811
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
812
for (prevPtr = NULL, tlFocusPtr = winPtr->mainPtr->tlFocusPtr;
814
prevPtr = tlFocusPtr, tlFocusPtr = tlFocusPtr->nextPtr) {
815
if (winPtr == tlFocusPtr->topLevelPtr) {
817
* The top-level window is the one being deleted: free
818
* the focus record and release the focus back to PointerRoot
819
* if we acquired it implicitly.
822
if (dispPtr->implicitWinPtr == winPtr) {
824
printf("releasing focus to root after %s died\n",
825
tlFocusPtr->topLevelPtr->pathName);
827
dispPtr->implicitWinPtr = NULL;
828
displayFocusPtr->focusWinPtr = NULL;
829
dispPtr->focusPtr = NULL;
831
if (displayFocusPtr->focusWinPtr == tlFocusPtr->focusWinPtr) {
832
displayFocusPtr->focusWinPtr = NULL;
833
dispPtr->focusPtr = NULL;
835
if (prevPtr == NULL) {
836
winPtr->mainPtr->tlFocusPtr = tlFocusPtr->nextPtr;
838
prevPtr->nextPtr = tlFocusPtr->nextPtr;
840
ckfree((char *) tlFocusPtr);
842
} else if (winPtr == tlFocusPtr->focusWinPtr) {
844
* The deleted window had the focus for its top-level:
845
* move the focus to the top-level itself.
848
tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
849
if ((displayFocusPtr->focusWinPtr == winPtr)
850
&& !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) {
852
printf("forwarding focus to %s after %s died\n",
853
tlFocusPtr->topLevelPtr->pathName,
856
GenerateFocusEvents(displayFocusPtr->focusWinPtr,
857
tlFocusPtr->topLevelPtr);
858
displayFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
859
dispPtr->focusPtr = tlFocusPtr->topLevelPtr;
865
if (displayFocusPtr->focusOnMapPtr == winPtr) {
866
displayFocusPtr->focusOnMapPtr = NULL;
871
*----------------------------------------------------------------------
873
* GenerateFocusEvents --
875
* This procedure is called to create FocusIn and FocusOut events to
876
* move the input focus from one window to another.
882
* FocusIn and FocusOut events are generated.
884
*----------------------------------------------------------------------
888
GenerateFocusEvents(sourcePtr, destPtr)
889
TkWindow *sourcePtr; /* Window that used to have the focus (may
891
TkWindow *destPtr; /* New window to have the focus (may be
899
if (winPtr == NULL) {
901
if (winPtr == NULL) {
906
event.xfocus.serial = LastKnownRequestProcessed(winPtr->display);
907
event.xfocus.send_event = GENERATED_EVENT_MAGIC;
908
event.xfocus.display = winPtr->display;
909
event.xfocus.mode = NotifyNormal;
910
TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn,
915
*----------------------------------------------------------------------
919
* This procedure is called as an event handler for VisibilityNotify
920
* events, if a window receives the focus at a time when its
921
* toplevel isn't mapped. The procedure is needed because X
922
* won't allow the focus to be set to an unmapped window; we
923
* detect when the toplevel is mapped and set the focus to it then.
929
* If this is a map event, the focus gets set to the toplevel
930
* given by clientData.
932
*----------------------------------------------------------------------
936
FocusMapProc(clientData, eventPtr)
937
ClientData clientData; /* Toplevel window. */
938
XEvent *eventPtr; /* Information about event. */
940
TkWindow *winPtr = (TkWindow *) clientData;
941
DisplayFocusInfo *displayFocusPtr;
943
if (eventPtr->type == VisibilityNotify) {
944
displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr,
947
printf("auto-focussing on %s, force %d\n", winPtr->pathName,
948
displayFocusPtr->forceFocus);
950
Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask,
951
FocusMapProc, clientData);
952
displayFocusPtr->focusOnMapPtr = NULL;
953
SetFocus(winPtr, displayFocusPtr->forceFocus);
958
*----------------------------------------------------------------------
960
* FindDisplayFocusInfo --
962
* Given an application and a display, this procedure locate the
963
* focus record for that combination. If no such record exists,
964
* it creates a new record and initializes it.
967
* The return value is a pointer to the record.
970
* A new record will be allocated if there wasn't one already.
972
*----------------------------------------------------------------------
975
static DisplayFocusInfo *
976
FindDisplayFocusInfo(mainPtr, dispPtr)
977
TkMainInfo *mainPtr; /* Record that identifies a particular
979
TkDisplay *dispPtr; /* Display whose focus information is
982
DisplayFocusInfo *displayFocusPtr;
984
for (displayFocusPtr = mainPtr->displayFocusPtr;
985
displayFocusPtr != NULL;
986
displayFocusPtr = displayFocusPtr->nextPtr) {
987
if (displayFocusPtr->dispPtr == dispPtr) {
988
return displayFocusPtr;
993
* The record doesn't exist yet. Make a new one.
996
displayFocusPtr = (DisplayFocusInfo *) ckalloc(sizeof(DisplayFocusInfo));
997
displayFocusPtr->dispPtr = dispPtr;
998
displayFocusPtr->focusWinPtr = NULL;
999
displayFocusPtr->focusOnMapPtr = NULL;
1000
displayFocusPtr->forceFocus = 0;
1001
displayFocusPtr->focusSerial = 0;
1002
displayFocusPtr->nextPtr = mainPtr->displayFocusPtr;
1003
mainPtr->displayFocusPtr = displayFocusPtr;
1004
return displayFocusPtr;