/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfocus.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfocus.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25