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

Diff of /projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkgrab.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   * tkGrab.c --   * tkGrab.c --
5   *   *
6   *      This file provides procedures that implement grabs for Tk.   *      This file provides procedures that implement grabs for Tk.
7   *   *
8   * Copyright (c) 1992-1994 The Regents of the University of California.   * Copyright (c) 1992-1994 The Regents of the University of California.
9   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10   *   *
11   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
12   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13   *   *
14   * RCS: @(#) $Id: tkgrab.c,v 1.1.1.1 2001/06/13 05:01:40 dtashley Exp $   * RCS: @(#) $Id: tkgrab.c,v 1.1.1.1 2001/06/13 05:01:40 dtashley Exp $
15   */   */
16    
17  #include "tkPort.h"  #include "tkPort.h"
18  #include "tkInt.h"  #include "tkInt.h"
19    
20  #if !defined(__WIN32__) && !defined(MAC_TCL)  #if !defined(__WIN32__) && !defined(MAC_TCL)
21  #include "tkUnixInt.h"  #include "tkUnixInt.h"
22  #endif  #endif
23    
24  /*  /*
25   * The grab state machine has four states: ungrabbed, button pressed,   * The grab state machine has four states: ungrabbed, button pressed,
26   * grabbed, and button pressed while grabbed.  In addition, there are   * grabbed, and button pressed while grabbed.  In addition, there are
27   * three pieces of grab state information: the current grab window,   * three pieces of grab state information: the current grab window,
28   * the current restrict window, and whether the mouse is captured.   * the current restrict window, and whether the mouse is captured.
29   *   *
30   * The current grab window specifies the point in the Tk window   * The current grab window specifies the point in the Tk window
31   * heirarchy above which pointer events will not be reported.  Any   * heirarchy above which pointer events will not be reported.  Any
32   * window within the subtree below the grab window will continue to   * window within the subtree below the grab window will continue to
33   * receive events as normal.  Events outside of the grab tree will be   * receive events as normal.  Events outside of the grab tree will be
34   * reported to the grab window.   * reported to the grab window.
35   *   *
36   * If the current restrict window is set, then all pointer events will   * If the current restrict window is set, then all pointer events will
37   * be reported only to the restrict window.  The restrict window is   * be reported only to the restrict window.  The restrict window is
38   * normally set during an automatic button grab.   * normally set during an automatic button grab.
39   *   *
40   * The mouse capture state specifies whether the window system will   * The mouse capture state specifies whether the window system will
41   * report mouse events outside of any Tk toplevels.  This is set   * report mouse events outside of any Tk toplevels.  This is set
42   * during a global grab or an automatic button grab.   * during a global grab or an automatic button grab.
43   *   *
44   * The transitions between different states is given in the following   * The transitions between different states is given in the following
45   * table:   * table:
46   *   *
47   * Event\State  U       B       G       GB   * Event\State  U       B       G       GB
48   * -----------  --      --      --      --   * -----------  --      --      --      --
49   * FirstPress   B       B       GB      GB   * FirstPress   B       B       GB      GB
50   * Press        B       B       G       GB   * Press        B       B       G       GB
51   * Release      U       B       G       GB   * Release      U       B       G       GB
52   * LastRelease  U       U       G       G   * LastRelease  U       U       G       G
53   * Grab         G       G       G       G   * Grab         G       G       G       G
54   * Ungrab       U       B       U       U   * Ungrab       U       B       U       U
55   *   *
56   * Note: U=Ungrabbed, B=Button, G=Grabbed, GB=Grab and Button   * Note: U=Ungrabbed, B=Button, G=Grabbed, GB=Grab and Button
57   *   *
58   * In addition, the following conditions are always true:   * In addition, the following conditions are always true:
59   *   *
60   * State\Variable       Grab         Restrict        Capture   * State\Variable       Grab         Restrict        Capture
61   * --------------       ----         --------        -------   * --------------       ----         --------        -------
62   * Ungrabbed             0              0               0   * Ungrabbed             0              0               0
63   * Button                0              1               1   * Button                0              1               1
64   * Grabbed               1              0               b/g   * Grabbed               1              0               b/g
65   * Grab and Button       1              1               1   * Grab and Button       1              1               1
66   *   *
67   * Note: 0 means variable is set to NULL, 1 means variable is set to   * Note: 0 means variable is set to NULL, 1 means variable is set to
68   * some window, b/g means the variable is set to a window if a button   * some window, b/g means the variable is set to a window if a button
69   * is currently down or a global grab is in effect.   * is currently down or a global grab is in effect.
70   *   *
71   * The final complication to all of this is enter and leave events.   * The final complication to all of this is enter and leave events.
72   * In order to correctly handle all of the various cases, Tk cannot   * In order to correctly handle all of the various cases, Tk cannot
73   * rely on X enter/leave events in all situations.  The following   * rely on X enter/leave events in all situations.  The following
74   * describes the correct sequence of enter and leave events that   * describes the correct sequence of enter and leave events that
75   * should be observed by Tk scripts:   * should be observed by Tk scripts:
76   *   *
77   * Event(state)         Enter/Leave From -> To   * Event(state)         Enter/Leave From -> To
78   * ------------         ----------------------   * ------------         ----------------------
79   * LastRelease(B | GB): restrict window -> anc(grab window, event window)   * LastRelease(B | GB): restrict window -> anc(grab window, event window)
80   * Grab(U | B):         event window -> anc(grab window, event window)   * Grab(U | B):         event window -> anc(grab window, event window)
81   * Grab(G):             anc(old grab window, event window) ->   * Grab(G):             anc(old grab window, event window) ->
82   *                              anc(new grab window, event window)   *                              anc(new grab window, event window)
83   * Grab(GB):            restrict window -> anc(new grab window, event window)   * Grab(GB):            restrict window -> anc(new grab window, event window)
84   * Ungrab(G):           anc(grab window, event window) -> event window   * Ungrab(G):           anc(grab window, event window) -> event window
85   * Ungrab(GB):          restrict window -> event window   * Ungrab(GB):          restrict window -> event window
86   *   *
87   * Note: anc(x,y) returns the least ancestor of y that is in the tree   * Note: anc(x,y) returns the least ancestor of y that is in the tree
88   * of x, terminating at toplevels.   * of x, terminating at toplevels.
89   */   */
90    
91  /*  /*
92   * The following structure is used to pass information to   * The following structure is used to pass information to
93   * GrabRestrictProc from EatGrabEvents.   * GrabRestrictProc from EatGrabEvents.
94   */   */
95    
96  typedef struct {  typedef struct {
97      Display *display;           /* Display from which to discard events. */      Display *display;           /* Display from which to discard events. */
98      unsigned int serial;        /* Serial number with which to compare. */      unsigned int serial;        /* Serial number with which to compare. */
99  } GrabInfo;  } GrabInfo;
100    
101  /*  /*
102   * Bit definitions for grabFlags field of TkDisplay structures:   * Bit definitions for grabFlags field of TkDisplay structures:
103   *   *
104   * GRAB_GLOBAL                  1 means this is a global grab (we grabbed via   * GRAB_GLOBAL                  1 means this is a global grab (we grabbed via
105   *                              the server so all applications are locked out).   *                              the server so all applications are locked out).
106   *                              0 means this is a local grab that affects   *                              0 means this is a local grab that affects
107   *                              only this application.   *                              only this application.
108   * GRAB_TEMP_GLOBAL             1 means we've temporarily grabbed via the   * GRAB_TEMP_GLOBAL             1 means we've temporarily grabbed via the
109   *                              server because a button is down and we want   *                              server because a button is down and we want
110   *                              to make sure that we get the button-up   *                              to make sure that we get the button-up
111   *                              event.  The grab will be released when the   *                              event.  The grab will be released when the
112   *                              last mouse button goes up.   *                              last mouse button goes up.
113   */   */
114    
115  #define GRAB_GLOBAL             1  #define GRAB_GLOBAL             1
116  #define GRAB_TEMP_GLOBAL        4  #define GRAB_TEMP_GLOBAL        4
117    
118  /*  /*
119   * The following structure is a Tcl_Event that triggers a change in   * The following structure is a Tcl_Event that triggers a change in
120   * the grabWinPtr field of a display.  This event guarantees that   * the grabWinPtr field of a display.  This event guarantees that
121   * the change occurs in the proper order relative to enter and leave   * the change occurs in the proper order relative to enter and leave
122   * events.   * events.
123   */   */
124    
125  typedef struct NewGrabWinEvent {  typedef struct NewGrabWinEvent {
126      Tcl_Event header;           /* Standard information for all Tcl events. */      Tcl_Event header;           /* Standard information for all Tcl events. */
127      TkDisplay *dispPtr;         /* Display whose grab window is to change. */      TkDisplay *dispPtr;         /* Display whose grab window is to change. */
128      Window grabWindow;          /* New grab window for display.  This is      Window grabWindow;          /* New grab window for display.  This is
129                                   * recorded instead of a (TkWindow *) because                                   * recorded instead of a (TkWindow *) because
130                                   * it will allow us to detect cases where                                   * it will allow us to detect cases where
131                                   * the window is destroyed before this event                                   * the window is destroyed before this event
132                                   * is processed. */                                   * is processed. */
133  } NewGrabWinEvent;  } NewGrabWinEvent;
134    
135  /*  /*
136   * The following magic value is stored in the "send_event" field of   * The following magic value is stored in the "send_event" field of
137   * EnterNotify and LeaveNotify events that are generated in this   * EnterNotify and LeaveNotify events that are generated in this
138   * file.  This allows us to separate "real" events coming from the   * file.  This allows us to separate "real" events coming from the
139   * server from those that we generated.   * server from those that we generated.
140   */   */
141    
142  #define GENERATED_EVENT_MAGIC ((Bool) 0x147321ac)  #define GENERATED_EVENT_MAGIC ((Bool) 0x147321ac)
143    
144  /*  /*
145   * Mask that selects any of the state bits corresponding to buttons,   * Mask that selects any of the state bits corresponding to buttons,
146   * plus masks that select individual buttons' bits:   * plus masks that select individual buttons' bits:
147   */   */
148    
149  #define ALL_BUTTONS \  #define ALL_BUTTONS \
150          (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)          (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
151  static unsigned int buttonStates[] = {  static unsigned int buttonStates[] = {
152      Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask      Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
153  };  };
154    
155  /*  /*
156   * Forward declarations for procedures declared later in this file:   * Forward declarations for procedures declared later in this file:
157   */   */
158    
159  static void             EatGrabEvents _ANSI_ARGS_((TkDisplay *dispPtr,  static void             EatGrabEvents _ANSI_ARGS_((TkDisplay *dispPtr,
160                              unsigned int serial));                              unsigned int serial));
161  static TkWindow *       FindCommonAncestor _ANSI_ARGS_((TkWindow *winPtr1,  static TkWindow *       FindCommonAncestor _ANSI_ARGS_((TkWindow *winPtr1,
162                              TkWindow *winPtr2, int *countPtr1,                              TkWindow *winPtr2, int *countPtr1,
163                              int *countPtr2));                              int *countPtr2));
164  static Tk_RestrictAction GrabRestrictProc _ANSI_ARGS_((ClientData arg,  static Tk_RestrictAction GrabRestrictProc _ANSI_ARGS_((ClientData arg,
165                              XEvent *eventPtr));                              XEvent *eventPtr));
166  static int              GrabWinEventProc _ANSI_ARGS_((Tcl_Event *evPtr,  static int              GrabWinEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
167                              int flags));                              int flags));
168  static void             MovePointer2 _ANSI_ARGS_((TkWindow *sourcePtr,  static void             MovePointer2 _ANSI_ARGS_((TkWindow *sourcePtr,
169                              TkWindow *destPtr, int mode, int leaveEvents,                              TkWindow *destPtr, int mode, int leaveEvents,
170                              int EnterEvents));                              int EnterEvents));
171  static void             QueueGrabWindowChange _ANSI_ARGS_((TkDisplay *dispPtr,  static void             QueueGrabWindowChange _ANSI_ARGS_((TkDisplay *dispPtr,
172                              TkWindow *grabWinPtr));                              TkWindow *grabWinPtr));
173  static void             ReleaseButtonGrab _ANSI_ARGS_((TkDisplay *dispPtr));  static void             ReleaseButtonGrab _ANSI_ARGS_((TkDisplay *dispPtr));
174    
175  /*  /*
176   *----------------------------------------------------------------------   *----------------------------------------------------------------------
177   *   *
178   * Tk_GrabCmd --   * Tk_GrabCmd --
179   *   *
180   *      This procedure is invoked to process the "grab" Tcl command.   *      This procedure is invoked to process the "grab" Tcl command.
181   *      See the user documentation for details on what it does.   *      See the user documentation for details on what it does.
182   *   *
183   * Results:   * Results:
184   *      A standard Tcl result.   *      A standard Tcl result.
185   *   *
186   * Side effects:   * Side effects:
187   *      See the user documentation.   *      See the user documentation.
188   *   *
189   *----------------------------------------------------------------------   *----------------------------------------------------------------------
190   */   */
191    
192          /* ARGSUSED */          /* ARGSUSED */
193  int  int
194  Tk_GrabCmd(clientData, interp, argc, argv)  Tk_GrabCmd(clientData, interp, argc, argv)
195      ClientData clientData;      /* Main window associated with      ClientData clientData;      /* Main window associated with
196                                   * interpreter. */                                   * interpreter. */
197      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
198      int argc;                   /* Number of arguments. */      int argc;                   /* Number of arguments. */
199      char **argv;                /* Argument strings. */      char **argv;                /* Argument strings. */
200  {  {
201      int globalGrab, c;      int globalGrab, c;
202      Tk_Window tkwin;      Tk_Window tkwin;
203      TkDisplay *dispPtr;      TkDisplay *dispPtr;
204      size_t length;      size_t length;
205    
206      if (argc < 2) {      if (argc < 2) {
207          badArgs:          badArgs:
208          Tcl_AppendResult(interp, "wrong # args: should be \"",          Tcl_AppendResult(interp, "wrong # args: should be \"",
209                  argv[0], " ?-global? window\" or \"", argv[0],                  argv[0], " ?-global? window\" or \"", argv[0],
210                  " option ?arg arg ...?\"", (char *) NULL);                  " option ?arg arg ...?\"", (char *) NULL);
211          return TCL_ERROR;          return TCL_ERROR;
212      }      }
213      c = argv[1][0];      c = argv[1][0];
214      length = strlen(argv[1]);      length = strlen(argv[1]);
215      if (c == '.') {      if (c == '.') {
216          if (argc != 2) {          if (argc != 2) {
217              goto badArgs;              goto badArgs;
218          }          }
219          tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);          tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);
220          if (tkwin == NULL) {          if (tkwin == NULL) {
221              return TCL_ERROR;              return TCL_ERROR;
222          }          }
223          return Tk_Grab(interp, tkwin, 0);          return Tk_Grab(interp, tkwin, 0);
224      } else if ((c == '-') && (strncmp(argv[1], "-global", length) == 0)      } else if ((c == '-') && (strncmp(argv[1], "-global", length) == 0)
225              && (length >= 2)) {              && (length >= 2)) {
226          if (argc != 3) {          if (argc != 3) {
227              goto badArgs;              goto badArgs;
228          }          }
229          tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);          tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
230          if (tkwin == NULL) {          if (tkwin == NULL) {
231              return TCL_ERROR;              return TCL_ERROR;
232          }          }
233          return Tk_Grab(interp, tkwin, 1);          return Tk_Grab(interp, tkwin, 1);
234      } else if ((c == 'c') && (strncmp(argv[1], "current", length) == 0)) {      } else if ((c == 'c') && (strncmp(argv[1], "current", length) == 0)) {
235          if (argc > 3) {          if (argc > 3) {
236              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
237                      argv[0], " current ?window?\"", (char *) NULL);                      argv[0], " current ?window?\"", (char *) NULL);
238              return TCL_ERROR;              return TCL_ERROR;
239          }          }
240          if (argc == 3) {          if (argc == 3) {
241              tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);              tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
242              if (tkwin == NULL) {              if (tkwin == NULL) {
243                  return TCL_ERROR;                  return TCL_ERROR;
244              }              }
245              dispPtr = ((TkWindow *) tkwin)->dispPtr;              dispPtr = ((TkWindow *) tkwin)->dispPtr;
246              if (dispPtr->eventualGrabWinPtr != NULL) {              if (dispPtr->eventualGrabWinPtr != NULL) {
247                  Tcl_SetResult(interp, dispPtr->eventualGrabWinPtr->pathName,                  Tcl_SetResult(interp, dispPtr->eventualGrabWinPtr->pathName,
248                          TCL_STATIC);                          TCL_STATIC);
249              }              }
250          } else {          } else {
251              for (dispPtr = TkGetDisplayList(); dispPtr != NULL;              for (dispPtr = TkGetDisplayList(); dispPtr != NULL;
252                      dispPtr = dispPtr->nextPtr) {                      dispPtr = dispPtr->nextPtr) {
253                  if (dispPtr->eventualGrabWinPtr != NULL) {                  if (dispPtr->eventualGrabWinPtr != NULL) {
254                      Tcl_AppendElement(interp,                      Tcl_AppendElement(interp,
255                              dispPtr->eventualGrabWinPtr->pathName);                              dispPtr->eventualGrabWinPtr->pathName);
256                  }                  }
257              }              }
258          }          }
259          return TCL_OK;          return TCL_OK;
260      } else if ((c == 'r') && (strncmp(argv[1], "release", length) == 0)) {      } else if ((c == 'r') && (strncmp(argv[1], "release", length) == 0)) {
261          if (argc != 3) {          if (argc != 3) {
262              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
263                      argv[0], " release window\"", (char *) NULL);                      argv[0], " release window\"", (char *) NULL);
264              return TCL_ERROR;              return TCL_ERROR;
265          }          }
266          tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);          tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
267          if (tkwin == NULL) {          if (tkwin == NULL) {
268              Tcl_ResetResult(interp);              Tcl_ResetResult(interp);
269          } else {          } else {
270              Tk_Ungrab(tkwin);              Tk_Ungrab(tkwin);
271          }          }
272      } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)      } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)
273              && (length >= 2)) {              && (length >= 2)) {
274          if ((argc != 3) && (argc != 4)) {          if ((argc != 3) && (argc != 4)) {
275              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
276                      argv[0], " set ?-global? window\"", (char *) NULL);                      argv[0], " set ?-global? window\"", (char *) NULL);
277              return TCL_ERROR;              return TCL_ERROR;
278          }          }
279          if (argc == 3) {          if (argc == 3) {
280              globalGrab = 0;              globalGrab = 0;
281              tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);              tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
282          } else {          } else {
283              globalGrab = 1;              globalGrab = 1;
284              length = strlen(argv[2]);              length = strlen(argv[2]);
285              if ((strncmp(argv[2], "-global", length) != 0) || (length < 2)) {              if ((strncmp(argv[2], "-global", length) != 0) || (length < 2)) {
286                  Tcl_AppendResult(interp, "bad argument \"", argv[2],                  Tcl_AppendResult(interp, "bad argument \"", argv[2],
287                          "\": must be \"", argv[0], " set ?-global? window\"",                          "\": must be \"", argv[0], " set ?-global? window\"",
288                          (char *) NULL);                          (char *) NULL);
289                  return TCL_ERROR;                  return TCL_ERROR;
290              }              }
291              tkwin = Tk_NameToWindow(interp, argv[3], (Tk_Window) clientData);              tkwin = Tk_NameToWindow(interp, argv[3], (Tk_Window) clientData);
292          }          }
293          if (tkwin == NULL) {          if (tkwin == NULL) {
294              return TCL_ERROR;              return TCL_ERROR;
295          }          }
296          return Tk_Grab(interp, tkwin, globalGrab);          return Tk_Grab(interp, tkwin, globalGrab);
297      } else if ((c == 's') && (strncmp(argv[1], "status", length) == 0)      } else if ((c == 's') && (strncmp(argv[1], "status", length) == 0)
298              && (length >= 2)) {              && (length >= 2)) {
299          TkWindow *winPtr;          TkWindow *winPtr;
300    
301          if (argc != 3) {          if (argc != 3) {
302              Tcl_AppendResult(interp, "wrong # args: should be \"",              Tcl_AppendResult(interp, "wrong # args: should be \"",
303                      argv[0], " status window\"", (char *) NULL);                      argv[0], " status window\"", (char *) NULL);
304              return TCL_ERROR;              return TCL_ERROR;
305          }          }
306          winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2],          winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2],
307                  (Tk_Window) clientData);                  (Tk_Window) clientData);
308          if (winPtr == NULL) {          if (winPtr == NULL) {
309              return TCL_ERROR;              return TCL_ERROR;
310          }          }
311          dispPtr = winPtr->dispPtr;          dispPtr = winPtr->dispPtr;
312          if (dispPtr->eventualGrabWinPtr != winPtr) {          if (dispPtr->eventualGrabWinPtr != winPtr) {
313              Tcl_SetResult(interp, "none", TCL_STATIC);              Tcl_SetResult(interp, "none", TCL_STATIC);
314          } else if (dispPtr->grabFlags & GRAB_GLOBAL) {          } else if (dispPtr->grabFlags & GRAB_GLOBAL) {
315              Tcl_SetResult(interp, "global", TCL_STATIC);              Tcl_SetResult(interp, "global", TCL_STATIC);
316          } else {          } else {
317              Tcl_SetResult(interp, "local", TCL_STATIC);              Tcl_SetResult(interp, "local", TCL_STATIC);
318          }          }
319      } else {      } else {
320          Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],          Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
321                  "\": must be current, release, set, or status",                  "\": must be current, release, set, or status",
322                  (char *) NULL);                  (char *) NULL);
323          return TCL_ERROR;          return TCL_ERROR;
324      }      }
325      return TCL_OK;      return TCL_OK;
326  }  }
327    
328  /*  /*
329   *----------------------------------------------------------------------   *----------------------------------------------------------------------
330   *   *
331   * Tk_Grab --   * Tk_Grab --
332   *   *
333   *      Grabs the pointer and keyboard, so that mouse-related events are   *      Grabs the pointer and keyboard, so that mouse-related events are
334   *      only reported relative to a given window and its descendants.   *      only reported relative to a given window and its descendants.
335   *   *
336   * Results:   * Results:
337   *      A standard Tcl result is returned.  TCL_OK is the normal return   *      A standard Tcl result is returned.  TCL_OK is the normal return
338   *      value;  if the grab could not be set then TCL_ERROR is returned   *      value;  if the grab could not be set then TCL_ERROR is returned
339   *      and the interp's result will hold an error message.   *      and the interp's result will hold an error message.
340   *   *
341   * Side effects:   * Side effects:
342   *      Once this call completes successfully, no window outside the   *      Once this call completes successfully, no window outside the
343   *      tree rooted at tkwin will receive pointer- or keyboard-related   *      tree rooted at tkwin will receive pointer- or keyboard-related
344   *      events until the next call to Tk_Ungrab.  If a previous grab was   *      events until the next call to Tk_Ungrab.  If a previous grab was
345   *      in effect within this application, then it is replaced with a new   *      in effect within this application, then it is replaced with a new
346   *      one.   *      one.
347   *   *
348   *----------------------------------------------------------------------   *----------------------------------------------------------------------
349   */   */
350    
351  int  int
352  Tk_Grab(interp, tkwin, grabGlobal)  Tk_Grab(interp, tkwin, grabGlobal)
353      Tcl_Interp *interp;                 /* Used for error reporting. */      Tcl_Interp *interp;                 /* Used for error reporting. */
354      Tk_Window tkwin;                    /* Window on whose behalf the pointer      Tk_Window tkwin;                    /* Window on whose behalf the pointer
355                                           * is to be grabbed. */                                           * is to be grabbed. */
356      int grabGlobal;                     /* Non-zero means issue a grab to the      int grabGlobal;                     /* Non-zero means issue a grab to the
357                                           * server so that no other application                                           * server so that no other application
358                                           * gets mouse or keyboard events.                                           * gets mouse or keyboard events.
359                                           * Zero means the grab only applies                                           * Zero means the grab only applies
360                                           * within this application. */                                           * within this application. */
361  {  {
362      int grabResult, numTries;      int grabResult, numTries;
363      TkWindow *winPtr = (TkWindow *) tkwin;      TkWindow *winPtr = (TkWindow *) tkwin;
364      TkDisplay *dispPtr = winPtr->dispPtr;      TkDisplay *dispPtr = winPtr->dispPtr;
365      TkWindow *winPtr2;      TkWindow *winPtr2;
366      unsigned int serial;      unsigned int serial;
367    
368      ReleaseButtonGrab(dispPtr);      ReleaseButtonGrab(dispPtr);
369      if (dispPtr->eventualGrabWinPtr != NULL) {      if (dispPtr->eventualGrabWinPtr != NULL) {
370          if ((dispPtr->eventualGrabWinPtr == winPtr)          if ((dispPtr->eventualGrabWinPtr == winPtr)
371                  && (grabGlobal == ((dispPtr->grabFlags & GRAB_GLOBAL) != 0))) {                  && (grabGlobal == ((dispPtr->grabFlags & GRAB_GLOBAL) != 0))) {
372              return TCL_OK;              return TCL_OK;
373          }          }
374          if (dispPtr->eventualGrabWinPtr->mainPtr != winPtr->mainPtr) {          if (dispPtr->eventualGrabWinPtr->mainPtr != winPtr->mainPtr) {
375              alreadyGrabbed:              alreadyGrabbed:
376              Tcl_SetResult(interp, "grab failed: another application has grab",              Tcl_SetResult(interp, "grab failed: another application has grab",
377                      TCL_STATIC);                      TCL_STATIC);
378              return TCL_ERROR;              return TCL_ERROR;
379          }          }
380          Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr);          Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr);
381      }      }
382    
383      Tk_MakeWindowExist(tkwin);      Tk_MakeWindowExist(tkwin);
384      if (!grabGlobal) {      if (!grabGlobal) {
385          Window dummy1, dummy2;          Window dummy1, dummy2;
386          int dummy3, dummy4, dummy5, dummy6;          int dummy3, dummy4, dummy5, dummy6;
387          unsigned int state;          unsigned int state;
388    
389          /*          /*
390           * Local grab.  However, if any mouse buttons are down, turn           * Local grab.  However, if any mouse buttons are down, turn
391           * it into a global grab temporarily, until the last button           * it into a global grab temporarily, until the last button
392           * goes up.  This does two things: (a) it makes sure that we           * goes up.  This does two things: (a) it makes sure that we
393           * see the button-up event;  and (b) it allows us to track mouse           * see the button-up event;  and (b) it allows us to track mouse
394           * motion among all of the windows of this application.           * motion among all of the windows of this application.
395           */           */
396    
397          dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL);          dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL);
398          XQueryPointer(dispPtr->display, winPtr->window, &dummy1,          XQueryPointer(dispPtr->display, winPtr->window, &dummy1,
399                  &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &state);                  &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &state);
400          if ((state & ALL_BUTTONS) != 0) {          if ((state & ALL_BUTTONS) != 0) {
401              dispPtr->grabFlags |= GRAB_TEMP_GLOBAL;              dispPtr->grabFlags |= GRAB_TEMP_GLOBAL;
402              goto setGlobalGrab;              goto setGlobalGrab;
403          }          }
404      } else {      } else {
405          dispPtr->grabFlags |= GRAB_GLOBAL;          dispPtr->grabFlags |= GRAB_GLOBAL;
406          setGlobalGrab:          setGlobalGrab:
407    
408          /*          /*
409           * Tricky point: must ungrab before grabbing.  This is needed           * Tricky point: must ungrab before grabbing.  This is needed
410           * in case there is a button auto-grab already in effect.  If           * in case there is a button auto-grab already in effect.  If
411           * there is, and the mouse has moved to a different window, X           * there is, and the mouse has moved to a different window, X
412           * won't generate enter and leave events to move the mouse if           * won't generate enter and leave events to move the mouse if
413           * we grab without ungrabbing.           * we grab without ungrabbing.
414           */           */
415    
416          XUngrabPointer(dispPtr->display, CurrentTime);          XUngrabPointer(dispPtr->display, CurrentTime);
417          serial = NextRequest(dispPtr->display);          serial = NextRequest(dispPtr->display);
418    
419          /*          /*
420           * Another tricky point: there are races with some window           * Another tricky point: there are races with some window
421           * managers that can cause grabs to fail because the window           * managers that can cause grabs to fail because the window
422           * manager hasn't released its grab quickly enough.  To work           * manager hasn't released its grab quickly enough.  To work
423           * around this problem, retry a few times after AlreadyGrabbed           * around this problem, retry a few times after AlreadyGrabbed
424           * errors to give the grab release enough time to register with           * errors to give the grab release enough time to register with
425           * the server.           * the server.
426           */           */
427    
428          grabResult = 0;                 /* Needed only to prevent gcc          grabResult = 0;                 /* Needed only to prevent gcc
429                                           * compiler warnings. */                                           * compiler warnings. */
430          for (numTries = 0; numTries < 10; numTries++) {          for (numTries = 0; numTries < 10; numTries++) {
431              grabResult = XGrabPointer(dispPtr->display, winPtr->window,              grabResult = XGrabPointer(dispPtr->display, winPtr->window,
432                      True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask                      True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask
433                      |PointerMotionMask, GrabModeAsync, GrabModeAsync, None,                      |PointerMotionMask, GrabModeAsync, GrabModeAsync, None,
434                      None, CurrentTime);                      None, CurrentTime);
435              if (grabResult != AlreadyGrabbed) {              if (grabResult != AlreadyGrabbed) {
436                  break;                  break;
437              }              }
438              Tcl_Sleep(100);              Tcl_Sleep(100);
439          }          }
440          if (grabResult != 0) {          if (grabResult != 0) {
441              grabError:              grabError:
442              if (grabResult == GrabNotViewable) {              if (grabResult == GrabNotViewable) {
443                  Tcl_SetResult(interp, "grab failed: window not viewable",                  Tcl_SetResult(interp, "grab failed: window not viewable",
444                          TCL_STATIC);                          TCL_STATIC);
445              } else if (grabResult == AlreadyGrabbed) {              } else if (grabResult == AlreadyGrabbed) {
446                  goto alreadyGrabbed;                  goto alreadyGrabbed;
447              } else if (grabResult == GrabFrozen) {              } else if (grabResult == GrabFrozen) {
448                  Tcl_SetResult(interp,                  Tcl_SetResult(interp,
449                          "grab failed: keyboard or pointer frozen", TCL_STATIC);                          "grab failed: keyboard or pointer frozen", TCL_STATIC);
450              } else if (grabResult == GrabInvalidTime) {              } else if (grabResult == GrabInvalidTime) {
451                  Tcl_SetResult(interp, "grab failed: invalid time",                  Tcl_SetResult(interp, "grab failed: invalid time",
452                          TCL_STATIC);                          TCL_STATIC);
453              } else {              } else {
454                  char msg[64 + TCL_INTEGER_SPACE];                  char msg[64 + TCL_INTEGER_SPACE];
455                    
456                  sprintf(msg, "grab failed for unknown reason (code %d)",                  sprintf(msg, "grab failed for unknown reason (code %d)",
457                          grabResult);                          grabResult);
458                  Tcl_AppendResult(interp, msg, (char *) NULL);                  Tcl_AppendResult(interp, msg, (char *) NULL);
459              }              }
460              return TCL_ERROR;              return TCL_ERROR;
461          }          }
462          grabResult = XGrabKeyboard(dispPtr->display, Tk_WindowId(tkwin),          grabResult = XGrabKeyboard(dispPtr->display, Tk_WindowId(tkwin),
463                  False, GrabModeAsync, GrabModeAsync, CurrentTime);                  False, GrabModeAsync, GrabModeAsync, CurrentTime);
464          if (grabResult != 0) {          if (grabResult != 0) {
465              XUngrabPointer(dispPtr->display, CurrentTime);              XUngrabPointer(dispPtr->display, CurrentTime);
466              goto grabError;              goto grabError;
467          }          }
468    
469          /*          /*
470           * Eat up any grab-related events generated by the server for the           * Eat up any grab-related events generated by the server for the
471           * grab.  There are several reasons for doing this:           * grab.  There are several reasons for doing this:
472           *           *
473           * 1. We have to synthesize the events for local grabs anyway, since           * 1. We have to synthesize the events for local grabs anyway, since
474           *    the server doesn't participate in them.           *    the server doesn't participate in them.
475           * 2. The server doesn't always generate the right events for global           * 2. The server doesn't always generate the right events for global
476           *    grabs (e.g. it generates events even if the current window is           *    grabs (e.g. it generates events even if the current window is
477           *    in the grab tree, which we don't want).           *    in the grab tree, which we don't want).
478           * 3. We want all the grab-related events to be processed immediately           * 3. We want all the grab-related events to be processed immediately
479           *    (before other events that are already queued); events coming           *    (before other events that are already queued); events coming
480           *    from the server will be in the wrong place, but events we           *    from the server will be in the wrong place, but events we
481           *    synthesize here will go to the front of the queue.           *    synthesize here will go to the front of the queue.
482           */           */
483    
484          EatGrabEvents(dispPtr, serial);          EatGrabEvents(dispPtr, serial);
485      }      }
486    
487      /*      /*
488       * Synthesize leave events to move the pointer from its current window       * Synthesize leave events to move the pointer from its current window
489       * up to the lowest ancestor that it has in common with the grab window.       * up to the lowest ancestor that it has in common with the grab window.
490       * However, only do this if the pointer is outside the grab window's       * However, only do this if the pointer is outside the grab window's
491       * subtree but inside the grab window's application.       * subtree but inside the grab window's application.
492       */       */
493    
494      if ((dispPtr->serverWinPtr != NULL)      if ((dispPtr->serverWinPtr != NULL)
495              && (dispPtr->serverWinPtr->mainPtr == winPtr->mainPtr)) {              && (dispPtr->serverWinPtr->mainPtr == winPtr->mainPtr)) {
496          for (winPtr2 = dispPtr->serverWinPtr; ; winPtr2 = winPtr2->parentPtr) {          for (winPtr2 = dispPtr->serverWinPtr; ; winPtr2 = winPtr2->parentPtr) {
497              if (winPtr2 == winPtr) {              if (winPtr2 == winPtr) {
498                  break;                  break;
499              }              }
500              if (winPtr2 == NULL) {              if (winPtr2 == NULL) {
501                  MovePointer2(dispPtr->serverWinPtr, winPtr, NotifyGrab, 1, 0);                  MovePointer2(dispPtr->serverWinPtr, winPtr, NotifyGrab, 1, 0);
502                  break;                  break;
503              }              }
504          }          }
505      }      }
506      QueueGrabWindowChange(dispPtr, winPtr);      QueueGrabWindowChange(dispPtr, winPtr);
507      return TCL_OK;      return TCL_OK;
508  }  }
509    
510  /*  /*
511   *----------------------------------------------------------------------   *----------------------------------------------------------------------
512   *   *
513   * Tk_Ungrab --   * Tk_Ungrab --
514   *   *
515   *      Releases a grab on the mouse pointer and keyboard, if there   *      Releases a grab on the mouse pointer and keyboard, if there
516   *      is one set on the specified window.   *      is one set on the specified window.
517   *   *
518   * Results:   * Results:
519   *      None.   *      None.
520   *   *
521   * Side effects:   * Side effects:
522   *      Pointer and keyboard events will start being delivered to other   *      Pointer and keyboard events will start being delivered to other
523   *      windows again.   *      windows again.
524   *   *
525   *----------------------------------------------------------------------   *----------------------------------------------------------------------
526   */   */
527    
528  void  void
529  Tk_Ungrab(tkwin)  Tk_Ungrab(tkwin)
530      Tk_Window tkwin;                    /* Window whose grab should be      Tk_Window tkwin;                    /* Window whose grab should be
531                                           * released. */                                           * released. */
532  {  {
533      TkDisplay *dispPtr;      TkDisplay *dispPtr;
534      TkWindow *grabWinPtr, *winPtr;      TkWindow *grabWinPtr, *winPtr;
535      unsigned int serial;      unsigned int serial;
536    
537      grabWinPtr = (TkWindow *) tkwin;      grabWinPtr = (TkWindow *) tkwin;
538      dispPtr = grabWinPtr->dispPtr;      dispPtr = grabWinPtr->dispPtr;
539      if (grabWinPtr != dispPtr->eventualGrabWinPtr) {      if (grabWinPtr != dispPtr->eventualGrabWinPtr) {
540          return;          return;
541      }      }
542      ReleaseButtonGrab(dispPtr);      ReleaseButtonGrab(dispPtr);
543      QueueGrabWindowChange(dispPtr, (TkWindow *) NULL);      QueueGrabWindowChange(dispPtr, (TkWindow *) NULL);
544      if (dispPtr->grabFlags & (GRAB_GLOBAL|GRAB_TEMP_GLOBAL)) {      if (dispPtr->grabFlags & (GRAB_GLOBAL|GRAB_TEMP_GLOBAL)) {
545          dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL);          dispPtr->grabFlags &= ~(GRAB_GLOBAL|GRAB_TEMP_GLOBAL);
546          serial = NextRequest(dispPtr->display);          serial = NextRequest(dispPtr->display);
547          XUngrabPointer(dispPtr->display, CurrentTime);          XUngrabPointer(dispPtr->display, CurrentTime);
548          XUngrabKeyboard(dispPtr->display, CurrentTime);          XUngrabKeyboard(dispPtr->display, CurrentTime);
549          EatGrabEvents(dispPtr, serial);          EatGrabEvents(dispPtr, serial);
550      }      }
551    
552      /*      /*
553       * Generate events to move the pointer back to the window where it       * Generate events to move the pointer back to the window where it
554       * really is.  Some notes:       * really is.  Some notes:
555       * 1. As with grabs, only do this if the "real" window is not a       * 1. As with grabs, only do this if the "real" window is not a
556       *    descendant of the grab window, since in this case the pointer       *    descendant of the grab window, since in this case the pointer
557       *    is already where it's supposed to be.       *    is already where it's supposed to be.
558       * 2. If the "real" window is in some other application then don't       * 2. If the "real" window is in some other application then don't
559       *    generate any events at all, since everything's already been       *    generate any events at all, since everything's already been
560       *    reported correctly.       *    reported correctly.
561       * 3. Only generate enter events.  Don't generate leave events,       * 3. Only generate enter events.  Don't generate leave events,
562       *    because we never told the lower-level windows that they       *    because we never told the lower-level windows that they
563       *    had the pointer in the first place.       *    had the pointer in the first place.
564       */       */
565    
566      for (winPtr = dispPtr->serverWinPtr; ; winPtr = winPtr->parentPtr) {      for (winPtr = dispPtr->serverWinPtr; ; winPtr = winPtr->parentPtr) {
567          if (winPtr == grabWinPtr) {          if (winPtr == grabWinPtr) {
568              break;              break;
569          }          }
570          if (winPtr == NULL) {          if (winPtr == NULL) {
571              if ((dispPtr->serverWinPtr == NULL) ||              if ((dispPtr->serverWinPtr == NULL) ||
572                      (dispPtr->serverWinPtr->mainPtr == grabWinPtr->mainPtr)) {                      (dispPtr->serverWinPtr->mainPtr == grabWinPtr->mainPtr)) {
573                  MovePointer2(grabWinPtr, dispPtr->serverWinPtr,                  MovePointer2(grabWinPtr, dispPtr->serverWinPtr,
574                          NotifyUngrab, 0, 1);                          NotifyUngrab, 0, 1);
575              }              }
576              break;              break;
577          }          }
578      }      }
579  }  }
580    
581  /*  /*
582   *----------------------------------------------------------------------   *----------------------------------------------------------------------
583   *   *
584   * ReleaseButtonGrab --   * ReleaseButtonGrab --
585   *   *
586   *      This procedure is called to release a simulated button grab, if   *      This procedure is called to release a simulated button grab, if
587   *      there is one in effect.  A button grab is present whenever   *      there is one in effect.  A button grab is present whenever
588   *      dispPtr->buttonWinPtr is non-NULL or when the GRAB_TEMP_GLOBAL   *      dispPtr->buttonWinPtr is non-NULL or when the GRAB_TEMP_GLOBAL
589   *      flag is set.   *      flag is set.
590   *   *
591   * Results:   * Results:
592   *      None.   *      None.
593   *   *
594   * Side effects:   * Side effects:
595   *      DispPtr->buttonWinPtr is reset to NULL, and enter and leave   *      DispPtr->buttonWinPtr is reset to NULL, and enter and leave
596   *      events are generated if necessary to move the pointer from   *      events are generated if necessary to move the pointer from
597   *      the button grab window to its current window.   *      the button grab window to its current window.
598   *   *
599   *----------------------------------------------------------------------   *----------------------------------------------------------------------
600   */   */
601    
602  static void  static void
603  ReleaseButtonGrab(dispPtr)  ReleaseButtonGrab(dispPtr)
604      register TkDisplay *dispPtr;        /* Display whose button grab is to be      register TkDisplay *dispPtr;        /* Display whose button grab is to be
605                                           * released. */                                           * released. */
606  {  {
607      unsigned int serial;      unsigned int serial;
608    
609      if (dispPtr->buttonWinPtr != NULL) {      if (dispPtr->buttonWinPtr != NULL) {
610          if (dispPtr->buttonWinPtr != dispPtr->serverWinPtr) {          if (dispPtr->buttonWinPtr != dispPtr->serverWinPtr) {
611              MovePointer2(dispPtr->buttonWinPtr, dispPtr->serverWinPtr,              MovePointer2(dispPtr->buttonWinPtr, dispPtr->serverWinPtr,
612                      NotifyUngrab, 1, 1);                      NotifyUngrab, 1, 1);
613          }          }
614          dispPtr->buttonWinPtr = NULL;          dispPtr->buttonWinPtr = NULL;
615      }      }
616      if (dispPtr->grabFlags & GRAB_TEMP_GLOBAL) {      if (dispPtr->grabFlags & GRAB_TEMP_GLOBAL) {
617          dispPtr->grabFlags &= ~GRAB_TEMP_GLOBAL;          dispPtr->grabFlags &= ~GRAB_TEMP_GLOBAL;
618          serial = NextRequest(dispPtr->display);          serial = NextRequest(dispPtr->display);
619          XUngrabPointer(dispPtr->display, CurrentTime);          XUngrabPointer(dispPtr->display, CurrentTime);
620          XUngrabKeyboard(dispPtr->display, CurrentTime);          XUngrabKeyboard(dispPtr->display, CurrentTime);
621          EatGrabEvents(dispPtr, serial);          EatGrabEvents(dispPtr, serial);
622      }      }
623  }  }
624    
625  /*  /*
626   *----------------------------------------------------------------------   *----------------------------------------------------------------------
627   *   *
628   * TkPointerEvent --   * TkPointerEvent --
629   *   *
630   *      This procedure is called for each pointer-related event, before   *      This procedure is called for each pointer-related event, before
631   *      the event has been processed.  It does various things to make   *      the event has been processed.  It does various things to make
632   *      grabs work correctly.   *      grabs work correctly.
633   *   *
634   * Results:   * Results:
635   *      If the return value is 1 it means the event should be processed   *      If the return value is 1 it means the event should be processed
636   *      (event handlers should be invoked).  If the return value is 0   *      (event handlers should be invoked).  If the return value is 0
637   *      it means the event should be ignored in order to make grabs   *      it means the event should be ignored in order to make grabs
638   *      work correctly.  In some cases this procedure modifies the event.   *      work correctly.  In some cases this procedure modifies the event.
639   *   *
640   * Side effects:   * Side effects:
641   *      Grab state information may be updated.  New events may also be   *      Grab state information may be updated.  New events may also be
642   *      pushed back onto the event queue to replace or augment the   *      pushed back onto the event queue to replace or augment the
643   *      one passed in here.   *      one passed in here.
644   *   *
645   *----------------------------------------------------------------------   *----------------------------------------------------------------------
646   */   */
647    
648  int  int
649  TkPointerEvent(eventPtr, winPtr)  TkPointerEvent(eventPtr, winPtr)
650      register XEvent *eventPtr;          /* Pointer to the event. */      register XEvent *eventPtr;          /* Pointer to the event. */
651      TkWindow *winPtr;                   /* Tk's information for window      TkWindow *winPtr;                   /* Tk's information for window
652                                           * where event was reported. */                                           * where event was reported. */
653  {  {
654      register TkWindow *winPtr2;      register TkWindow *winPtr2;
655      TkDisplay *dispPtr = winPtr->dispPtr;      TkDisplay *dispPtr = winPtr->dispPtr;
656      unsigned int serial;      unsigned int serial;
657      int outsideGrabTree = 0;      int outsideGrabTree = 0;
658      int ancestorOfGrab = 0;      int ancestorOfGrab = 0;
659      int appGrabbed = 0;                 /* Non-zero means event is being      int appGrabbed = 0;                 /* Non-zero means event is being
660                                           * reported to an application that is                                           * reported to an application that is
661                                           * affected by the grab. */                                           * affected by the grab. */
662    
663      /*      /*
664       * Collect information about the grab (if any).       * Collect information about the grab (if any).
665       */       */
666    
667      switch (TkGrabState(winPtr)) {      switch (TkGrabState(winPtr)) {
668          case TK_GRAB_IN_TREE:          case TK_GRAB_IN_TREE:
669              appGrabbed = 1;              appGrabbed = 1;
670              break;              break;
671          case TK_GRAB_ANCESTOR:          case TK_GRAB_ANCESTOR:
672              appGrabbed = 1;              appGrabbed = 1;
673              outsideGrabTree = 1;              outsideGrabTree = 1;
674              ancestorOfGrab = 1;              ancestorOfGrab = 1;
675              break;              break;
676          case TK_GRAB_EXCLUDED:          case TK_GRAB_EXCLUDED:
677              appGrabbed = 1;              appGrabbed = 1;
678              outsideGrabTree = 1;              outsideGrabTree = 1;
679              break;              break;
680      }      }
681    
682      if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) {      if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) {
683          /*          /*
684           * Keep track of what window the mouse is *really* over.           * Keep track of what window the mouse is *really* over.
685           * Any events that we generate have a special send_event value,           * Any events that we generate have a special send_event value,
686           * which is detected below and used to ignore the event for           * which is detected below and used to ignore the event for
687           * purposes of setting serverWinPtr.           * purposes of setting serverWinPtr.
688           */           */
689    
690          if (eventPtr->xcrossing.send_event != GENERATED_EVENT_MAGIC) {          if (eventPtr->xcrossing.send_event != GENERATED_EVENT_MAGIC) {
691              if ((eventPtr->type == LeaveNotify) &&              if ((eventPtr->type == LeaveNotify) &&
692                      (winPtr->flags & TK_TOP_LEVEL)) {                      (winPtr->flags & TK_TOP_LEVEL)) {
693                  dispPtr->serverWinPtr = NULL;                  dispPtr->serverWinPtr = NULL;
694              } else {              } else {
695                  dispPtr->serverWinPtr = winPtr;                  dispPtr->serverWinPtr = winPtr;
696              }              }
697          }          }
698    
699          /*          /*
700           * When a grab is active, X continues to report enter and leave           * When a grab is active, X continues to report enter and leave
701           * events for windows outside the tree of the grab window:           * events for windows outside the tree of the grab window:
702           * 1. Detect these events and ignore them except for           * 1. Detect these events and ignore them except for
703           *    windows above the grab window.           *    windows above the grab window.
704           * 2. Allow Enter and Leave events to pass through the           * 2. Allow Enter and Leave events to pass through the
705           *    windows above the grab window, but never let them           *    windows above the grab window, but never let them
706           *    end up with the pointer *in* one of those windows.           *    end up with the pointer *in* one of those windows.
707           */           */
708    
709          if (dispPtr->grabWinPtr != NULL) {          if (dispPtr->grabWinPtr != NULL) {
710              if (outsideGrabTree && appGrabbed) {              if (outsideGrabTree && appGrabbed) {
711                  if (!ancestorOfGrab) {                  if (!ancestorOfGrab) {
712                      return 0;                      return 0;
713                  }                  }
714                  switch (eventPtr->xcrossing.detail) {                  switch (eventPtr->xcrossing.detail) {
715                      case NotifyInferior:                      case NotifyInferior:
716                          return 0;                          return 0;
717                      case NotifyAncestor:                      case NotifyAncestor:
718                          eventPtr->xcrossing.detail = NotifyVirtual;                          eventPtr->xcrossing.detail = NotifyVirtual;
719                          break;                          break;
720                      case NotifyNonlinear:                      case NotifyNonlinear:
721                          eventPtr->xcrossing.detail = NotifyNonlinearVirtual;                          eventPtr->xcrossing.detail = NotifyNonlinearVirtual;
722                          break;                          break;
723                  }                  }
724              }              }
725    
726              /*              /*
727               * Make buttons have the same grab-like behavior inside a grab               * Make buttons have the same grab-like behavior inside a grab
728               * as they do outside a grab:  do this by ignoring enter and               * as they do outside a grab:  do this by ignoring enter and
729               * leave events except for the window in which the button was               * leave events except for the window in which the button was
730               * pressed.               * pressed.
731               */               */
732    
733              if ((dispPtr->buttonWinPtr != NULL)              if ((dispPtr->buttonWinPtr != NULL)
734                      && (winPtr != dispPtr->buttonWinPtr)) {                      && (winPtr != dispPtr->buttonWinPtr)) {
735                  return 0;                  return 0;
736              }              }
737          }          }
738          return 1;          return 1;
739      }      }
740    
741      if (!appGrabbed) {      if (!appGrabbed) {
742          return 1;          return 1;
743      }      }
744    
745      if (eventPtr->type == MotionNotify) {      if (eventPtr->type == MotionNotify) {
746          /*          /*
747           * When grabs are active, X reports motion events relative to the           * When grabs are active, X reports motion events relative to the
748           * window under the pointer.  Instead, it should report the events           * window under the pointer.  Instead, it should report the events
749           * relative to the window the button went down in, if there is a           * relative to the window the button went down in, if there is a
750           * button down.  Otherwise, if the pointer window is outside the           * button down.  Otherwise, if the pointer window is outside the
751           * subtree of the grab window, the events should be reported           * subtree of the grab window, the events should be reported
752           * relative to the grab window.  Otherwise, the event should be           * relative to the grab window.  Otherwise, the event should be
753           * reported to the pointer window.           * reported to the pointer window.
754           */           */
755    
756          winPtr2 = winPtr;          winPtr2 = winPtr;
757          if (dispPtr->buttonWinPtr != NULL) {          if (dispPtr->buttonWinPtr != NULL) {
758              winPtr2 = dispPtr->buttonWinPtr;              winPtr2 = dispPtr->buttonWinPtr;
759          } else if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) {          } else if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) {
760              winPtr2 = dispPtr->grabWinPtr;              winPtr2 = dispPtr->grabWinPtr;
761          }          }
762          if (winPtr2 != winPtr) {          if (winPtr2 != winPtr) {
763              TkChangeEventWindow(eventPtr, winPtr2);              TkChangeEventWindow(eventPtr, winPtr2);
764              Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);              Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);
765              return 0;              return 0;
766          }          }
767          return 1;          return 1;
768      }      }
769    
770      /*      /*
771       * Process ButtonPress and ButtonRelease events:       * Process ButtonPress and ButtonRelease events:
772       * 1. Keep track of whether a button is down and what window it       * 1. Keep track of whether a button is down and what window it
773       *    went down in.       *    went down in.
774       * 2. If the first button goes down outside the grab tree, pretend       * 2. If the first button goes down outside the grab tree, pretend
775       *    it went down in the grab window.  Note: it's important to       *    it went down in the grab window.  Note: it's important to
776       *    redirect events to the grab window like this in order to make       *    redirect events to the grab window like this in order to make
777       *    things like menus work, where button presses outside the       *    things like menus work, where button presses outside the
778       *    grabbed menu need to be seen.  An application can always       *    grabbed menu need to be seen.  An application can always
779       *    ignore the events if they occur outside its window.       *    ignore the events if they occur outside its window.
780       * 3. If a button press or release occurs outside the window where       * 3. If a button press or release occurs outside the window where
781       *    the first button was pressed, retarget the event so it's reported       *    the first button was pressed, retarget the event so it's reported
782       *    to the window where the first button was pressed.       *    to the window where the first button was pressed.
783       * 4. If the last button is released in a window different than where       * 4. If the last button is released in a window different than where
784       *    the first button was pressed, generate Enter/Leave events to       *    the first button was pressed, generate Enter/Leave events to
785       *    move the mouse from the button window to its current window.       *    move the mouse from the button window to its current window.
786       * 5. If the grab is set at a time when a button is already down, or       * 5. If the grab is set at a time when a button is already down, or
787       *    if the window where the button was pressed was deleted, then       *    if the window where the button was pressed was deleted, then
788       *    dispPtr->buttonWinPtr will stay NULL.  Just forget about the       *    dispPtr->buttonWinPtr will stay NULL.  Just forget about the
789       *    auto-grab for the button press;  events will go to whatever       *    auto-grab for the button press;  events will go to whatever
790       *    window contains the pointer.  If this window isn't in the grab       *    window contains the pointer.  If this window isn't in the grab
791       *    tree then redirect events to the grab window.       *    tree then redirect events to the grab window.
792       * 6. When a button is pressed during a local grab, the X server sets       * 6. When a button is pressed during a local grab, the X server sets
793       *    a grab of its own, since it doesn't even know about our local       *    a grab of its own, since it doesn't even know about our local
794       *    grab.  This causes enter and leave events no longer to be       *    grab.  This causes enter and leave events no longer to be
795       *    generated in the same way as for global grabs.  To eliminate this       *    generated in the same way as for global grabs.  To eliminate this
796       *    problem, set a temporary global grab when the first button goes       *    problem, set a temporary global grab when the first button goes
797       *    down and release it when the last button comes up.       *    down and release it when the last button comes up.
798       */       */
799    
800      if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {      if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
801          winPtr2 = dispPtr->buttonWinPtr;          winPtr2 = dispPtr->buttonWinPtr;
802          if (winPtr2 == NULL) {          if (winPtr2 == NULL) {
803              if (outsideGrabTree) {              if (outsideGrabTree) {
804                  winPtr2 = dispPtr->grabWinPtr;                  /* Note 5. */                  winPtr2 = dispPtr->grabWinPtr;                  /* Note 5. */
805              } else {              } else {
806                  winPtr2 = winPtr;                               /* Note 5. */                  winPtr2 = winPtr;                               /* Note 5. */
807              }              }
808          }          }
809          if (eventPtr->type == ButtonPress) {          if (eventPtr->type == ButtonPress) {
810              if ((eventPtr->xbutton.state & ALL_BUTTONS) == 0) {              if ((eventPtr->xbutton.state & ALL_BUTTONS) == 0) {
811                  if (outsideGrabTree) {                  if (outsideGrabTree) {
812                      TkChangeEventWindow(eventPtr, dispPtr->grabWinPtr);                      TkChangeEventWindow(eventPtr, dispPtr->grabWinPtr);
813                      Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);                      Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);
814                      return 0;                                   /* Note 2. */                      return 0;                                   /* Note 2. */
815                  }                  }
816                  if (!(dispPtr->grabFlags & GRAB_GLOBAL)) {      /* Note 6. */                  if (!(dispPtr->grabFlags & GRAB_GLOBAL)) {      /* Note 6. */
817                      serial = NextRequest(dispPtr->display);                      serial = NextRequest(dispPtr->display);
818                      if (XGrabPointer(dispPtr->display,                      if (XGrabPointer(dispPtr->display,
819                              dispPtr->grabWinPtr->window, True,                              dispPtr->grabWinPtr->window, True,
820                              ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,                              ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
821                              GrabModeAsync, GrabModeAsync, None, None,                              GrabModeAsync, GrabModeAsync, None, None,
822                              CurrentTime) == 0) {                              CurrentTime) == 0) {
823                          EatGrabEvents(dispPtr, serial);                          EatGrabEvents(dispPtr, serial);
824                          if (XGrabKeyboard(dispPtr->display, winPtr->window,                          if (XGrabKeyboard(dispPtr->display, winPtr->window,
825                                  False, GrabModeAsync, GrabModeAsync,                                  False, GrabModeAsync, GrabModeAsync,
826                                  CurrentTime) == 0) {                                  CurrentTime) == 0) {
827                              dispPtr->grabFlags |= GRAB_TEMP_GLOBAL;                              dispPtr->grabFlags |= GRAB_TEMP_GLOBAL;
828                          } else {                          } else {
829                              XUngrabPointer(dispPtr->display, CurrentTime);                              XUngrabPointer(dispPtr->display, CurrentTime);
830                          }                          }
831                      }                      }
832                  }                  }
833                  dispPtr->buttonWinPtr = winPtr;                  dispPtr->buttonWinPtr = winPtr;
834                  return 1;                  return 1;
835              }              }
836          } else {          } else {
837              if ((eventPtr->xbutton.state & ALL_BUTTONS)              if ((eventPtr->xbutton.state & ALL_BUTTONS)
838                      == buttonStates[eventPtr->xbutton.button - Button1]) {                      == buttonStates[eventPtr->xbutton.button - Button1]) {
839                  ReleaseButtonGrab(dispPtr);                     /* Note 4. */                  ReleaseButtonGrab(dispPtr);                     /* Note 4. */
840              }              }
841          }          }
842          if (winPtr2 != winPtr) {          if (winPtr2 != winPtr) {
843              TkChangeEventWindow(eventPtr, winPtr2);              TkChangeEventWindow(eventPtr, winPtr2);
844              Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);              Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_HEAD);
845              return 0;                                           /* Note 3. */              return 0;                                           /* Note 3. */
846          }          }
847      }      }
848    
849      return 1;      return 1;
850  }  }
851    
852  /*  /*
853   *----------------------------------------------------------------------   *----------------------------------------------------------------------
854   *   *
855   * TkChangeEventWindow --   * TkChangeEventWindow --
856   *   *
857   *      Given an event and a new window to which the event should be   *      Given an event and a new window to which the event should be
858   *      retargeted, modify fields of the event so that the event is   *      retargeted, modify fields of the event so that the event is
859   *      properly retargeted to the new window.   *      properly retargeted to the new window.
860   *   *
861   * Results:   * Results:
862   *      The following fields of eventPtr are modified:  window,   *      The following fields of eventPtr are modified:  window,
863   *      subwindow, x, y, same_screen.   *      subwindow, x, y, same_screen.
864   *   *
865   * Side effects:   * Side effects:
866   *      None.   *      None.
867   *   *
868   *----------------------------------------------------------------------   *----------------------------------------------------------------------
869   */   */
870    
871  void  void
872  TkChangeEventWindow(eventPtr, winPtr)  TkChangeEventWindow(eventPtr, winPtr)
873      register XEvent *eventPtr;  /* Event to retarget.  Must have      register XEvent *eventPtr;  /* Event to retarget.  Must have
874                                   * type ButtonPress, ButtonRelease, KeyPress,                                   * type ButtonPress, ButtonRelease, KeyPress,
875                                   * KeyRelease, MotionNotify, EnterNotify,                                   * KeyRelease, MotionNotify, EnterNotify,
876                                   * or LeaveNotify. */                                   * or LeaveNotify. */
877      TkWindow *winPtr;           /* New target window for event. */      TkWindow *winPtr;           /* New target window for event. */
878  {  {
879      int x, y, sameScreen, bd;      int x, y, sameScreen, bd;
880      register TkWindow *childPtr;      register TkWindow *childPtr;
881    
882      eventPtr->xmotion.window = Tk_WindowId(winPtr);      eventPtr->xmotion.window = Tk_WindowId(winPtr);
883      if (eventPtr->xmotion.root ==      if (eventPtr->xmotion.root ==
884              RootWindow(winPtr->display, winPtr->screenNum)) {              RootWindow(winPtr->display, winPtr->screenNum)) {
885          Tk_GetRootCoords((Tk_Window) winPtr, &x, &y);          Tk_GetRootCoords((Tk_Window) winPtr, &x, &y);
886          eventPtr->xmotion.x = eventPtr->xmotion.x_root - x;          eventPtr->xmotion.x = eventPtr->xmotion.x_root - x;
887          eventPtr->xmotion.y = eventPtr->xmotion.y_root - y;          eventPtr->xmotion.y = eventPtr->xmotion.y_root - y;
888          eventPtr->xmotion.subwindow = None;          eventPtr->xmotion.subwindow = None;
889          for (childPtr = winPtr->childList; childPtr != NULL;          for (childPtr = winPtr->childList; childPtr != NULL;
890                  childPtr = childPtr->nextPtr) {                  childPtr = childPtr->nextPtr) {
891              if (childPtr->flags & TK_TOP_LEVEL) {              if (childPtr->flags & TK_TOP_LEVEL) {
892                  continue;                  continue;
893              }              }
894              x = eventPtr->xmotion.x - childPtr->changes.x;              x = eventPtr->xmotion.x - childPtr->changes.x;
895              y = eventPtr->xmotion.y - childPtr->changes.y;              y = eventPtr->xmotion.y - childPtr->changes.y;
896              bd = childPtr->changes.border_width;              bd = childPtr->changes.border_width;
897              if ((x >= -bd) && (y >= -bd)              if ((x >= -bd) && (y >= -bd)
898                      && (x < (childPtr->changes.width + bd))                      && (x < (childPtr->changes.width + bd))
899                      && (y < (childPtr->changes.height + bd))) {                      && (y < (childPtr->changes.height + bd))) {
900                  eventPtr->xmotion.subwindow = childPtr->window;                  eventPtr->xmotion.subwindow = childPtr->window;
901              }              }
902          }          }
903          sameScreen = 1;          sameScreen = 1;
904      } else {      } else {
905          eventPtr->xmotion.x = 0;          eventPtr->xmotion.x = 0;
906          eventPtr->xmotion.y = 0;          eventPtr->xmotion.y = 0;
907          eventPtr->xmotion.subwindow = None;          eventPtr->xmotion.subwindow = None;
908          sameScreen = 0;          sameScreen = 0;
909      }      }
910      if (eventPtr->type == MotionNotify) {      if (eventPtr->type == MotionNotify) {
911          eventPtr->xmotion.same_screen = sameScreen;          eventPtr->xmotion.same_screen = sameScreen;
912      } else {      } else {
913          eventPtr->xbutton.same_screen = sameScreen;          eventPtr->xbutton.same_screen = sameScreen;
914      }      }
915  }  }
916    
917  /*  /*
918   *----------------------------------------------------------------------   *----------------------------------------------------------------------
919   *   *
920   * TkInOutEvents --   * TkInOutEvents --
921   *   *
922   *      This procedure synthesizes EnterNotify and LeaveNotify events   *      This procedure synthesizes EnterNotify and LeaveNotify events
923   *      to correctly transfer the pointer from one window to another.   *      to correctly transfer the pointer from one window to another.
924   *      It can also be used to generate FocusIn and FocusOut events   *      It can also be used to generate FocusIn and FocusOut events
925   *      to move the input focus.   *      to move the input focus.
926   *   *
927   * Results:   * Results:
928   *      None.   *      None.
929   *   *
930   * Side effects:   * Side effects:
931   *      Synthesized events may be pushed back onto the event queue.   *      Synthesized events may be pushed back onto the event queue.
932   *      The event pointed to by eventPtr is modified.   *      The event pointed to by eventPtr is modified.
933   *   *
934   *----------------------------------------------------------------------   *----------------------------------------------------------------------
935   */   */
936    
937  void  void
938  TkInOutEvents(eventPtr, sourcePtr, destPtr, leaveType, enterType, position)  TkInOutEvents(eventPtr, sourcePtr, destPtr, leaveType, enterType, position)
939      XEvent *eventPtr;           /* A template X event.  Must have all fields      XEvent *eventPtr;           /* A template X event.  Must have all fields
940                                   * properly set except for type, window,                                   * properly set except for type, window,
941                                   * subwindow, x, y, detail, and same_screen                                   * subwindow, x, y, detail, and same_screen
942                                   * (Not all of these fields are valid for                                   * (Not all of these fields are valid for
943                                   * FocusIn/FocusOut events;  x_root and y_root                                   * FocusIn/FocusOut events;  x_root and y_root
944                                   * must be valid for Enter/Leave events, even                                   * must be valid for Enter/Leave events, even
945                                   * though x and y needn't be valid). */                                   * though x and y needn't be valid). */
946      TkWindow *sourcePtr;        /* Window that used to have the pointer or      TkWindow *sourcePtr;        /* Window that used to have the pointer or
947                                   * focus (NULL means it was not in a window                                   * focus (NULL means it was not in a window
948                                   * managed by this process). */                                   * managed by this process). */
949      TkWindow *destPtr;          /* Window that is to end up with the pointer      TkWindow *destPtr;          /* Window that is to end up with the pointer
950                                   * or focus (NULL means it's not one managed                                   * or focus (NULL means it's not one managed
951                                   * by this process). */                                   * by this process). */
952      int leaveType;              /* Type of events to generate for windows      int leaveType;              /* Type of events to generate for windows
953                                   * being left (LeaveNotify or FocusOut).  0                                   * being left (LeaveNotify or FocusOut).  0
954                                   * means don't generate leave events. */                                   * means don't generate leave events. */
955      int enterType;              /* Type of events to generate for windows      int enterType;              /* Type of events to generate for windows
956                                   * being entered (EnterNotify or FocusIn).  0                                   * being entered (EnterNotify or FocusIn).  0
957                                   * means don't generate enter events. */                                   * means don't generate enter events. */
958      Tcl_QueuePosition position; /* Position at which events are added to      Tcl_QueuePosition position; /* Position at which events are added to
959                                   * the system event queue. */                                   * the system event queue. */
960  {  {
961      register TkWindow *winPtr;      register TkWindow *winPtr;
962      int upLevels, downLevels, i, j, focus;      int upLevels, downLevels, i, j, focus;
963    
964      /*      /*
965       * There are four possible cases to deal with:       * There are four possible cases to deal with:
966       *       *
967       * 1. SourcePtr and destPtr are the same.  There's nothing to do in       * 1. SourcePtr and destPtr are the same.  There's nothing to do in
968       *    this case.       *    this case.
969       * 2. SourcePtr is an ancestor of destPtr in the same top-level       * 2. SourcePtr is an ancestor of destPtr in the same top-level
970       *    window.  Must generate events down the window tree from source       *    window.  Must generate events down the window tree from source
971       *    to dest.       *    to dest.
972       * 3. DestPtr is an ancestor of sourcePtr in the same top-level       * 3. DestPtr is an ancestor of sourcePtr in the same top-level
973       *    window.  Must generate events up the window tree from sourcePtr       *    window.  Must generate events up the window tree from sourcePtr
974       *    to destPtr.       *    to destPtr.
975       * 4. All other cases.  Must first generate events up the window tree       * 4. All other cases.  Must first generate events up the window tree
976       *    from sourcePtr to its top-level, then down from destPtr's       *    from sourcePtr to its top-level, then down from destPtr's
977       *    top-level to destPtr. This form is called "non-linear."       *    top-level to destPtr. This form is called "non-linear."
978       *       *
979       * The call to FindCommonAncestor separates these four cases and decides       * The call to FindCommonAncestor separates these four cases and decides
980       * how many levels up and down events have to be generated for.       * how many levels up and down events have to be generated for.
981       */       */
982    
983      if (sourcePtr == destPtr) {      if (sourcePtr == destPtr) {
984          return;          return;
985      }      }
986      if ((leaveType == FocusOut) || (enterType == FocusIn)) {      if ((leaveType == FocusOut) || (enterType == FocusIn)) {
987          focus = 1;          focus = 1;
988      } else {      } else {
989          focus = 0;          focus = 0;
990      }      }
991      FindCommonAncestor(sourcePtr, destPtr, &upLevels, &downLevels);      FindCommonAncestor(sourcePtr, destPtr, &upLevels, &downLevels);
992    
993      /*      /*
994       * Generate enter/leave events and add them to the grab event queue.       * Generate enter/leave events and add them to the grab event queue.
995       */       */
996    
997    
998  #define QUEUE(w, t, d)                                  \  #define QUEUE(w, t, d)                                  \
999      if (w->window != None) {                            \      if (w->window != None) {                            \
1000          eventPtr->type = t;                             \          eventPtr->type = t;                             \
1001          if (focus) {                                    \          if (focus) {                                    \
1002              eventPtr->xfocus.window = w->window;        \              eventPtr->xfocus.window = w->window;        \
1003              eventPtr->xfocus.detail = d;                \              eventPtr->xfocus.detail = d;                \
1004          } else {                                        \          } else {                                        \
1005              eventPtr->xcrossing.detail = d;             \              eventPtr->xcrossing.detail = d;             \
1006              TkChangeEventWindow(eventPtr, w);           \              TkChangeEventWindow(eventPtr, w);           \
1007          }                                               \          }                                               \
1008          Tk_QueueWindowEvent(eventPtr, position);        \          Tk_QueueWindowEvent(eventPtr, position);        \
1009      }      }
1010    
1011      if (downLevels == 0) {      if (downLevels == 0) {
1012            
1013          /*          /*
1014           * SourcePtr is an inferior of destPtr.           * SourcePtr is an inferior of destPtr.
1015           */           */
1016    
1017          if (leaveType != 0) {          if (leaveType != 0) {
1018              QUEUE(sourcePtr, leaveType, NotifyAncestor);              QUEUE(sourcePtr, leaveType, NotifyAncestor);
1019              for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0;              for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0;
1020                      winPtr = winPtr->parentPtr, i--) {                      winPtr = winPtr->parentPtr, i--) {
1021                  QUEUE(winPtr, leaveType, NotifyVirtual);                  QUEUE(winPtr, leaveType, NotifyVirtual);
1022              }              }
1023          }          }
1024          if ((enterType != 0) && (destPtr != NULL)) {          if ((enterType != 0) && (destPtr != NULL)) {
1025              QUEUE(destPtr, enterType, NotifyInferior);              QUEUE(destPtr, enterType, NotifyInferior);
1026          }          }
1027      } else if (upLevels == 0) {      } else if (upLevels == 0) {
1028    
1029          /*          /*
1030           * DestPtr is an inferior of sourcePtr.           * DestPtr is an inferior of sourcePtr.
1031           */           */
1032    
1033          if ((leaveType != 0) && (sourcePtr != NULL)) {          if ((leaveType != 0) && (sourcePtr != NULL)) {
1034              QUEUE(sourcePtr, leaveType, NotifyInferior);              QUEUE(sourcePtr, leaveType, NotifyInferior);
1035          }          }
1036          if (enterType != 0) {          if (enterType != 0) {
1037              for (i = downLevels-1; i > 0; i--) {              for (i = downLevels-1; i > 0; i--) {
1038                  for (winPtr = destPtr->parentPtr, j = 1; j < i;                  for (winPtr = destPtr->parentPtr, j = 1; j < i;
1039                          winPtr = winPtr->parentPtr, j++) {                          winPtr = winPtr->parentPtr, j++) {
1040                  }                  }
1041                  QUEUE(winPtr, enterType, NotifyVirtual);                  QUEUE(winPtr, enterType, NotifyVirtual);
1042              }              }
1043              if (destPtr != NULL) {              if (destPtr != NULL) {
1044                  QUEUE(destPtr, enterType, NotifyAncestor);                  QUEUE(destPtr, enterType, NotifyAncestor);
1045              }              }
1046          }          }
1047      } else {      } else {
1048    
1049          /*          /*
1050           * Non-linear:  neither window is an inferior of the other.           * Non-linear:  neither window is an inferior of the other.
1051           */           */
1052    
1053          if (leaveType != 0) {          if (leaveType != 0) {
1054              QUEUE(sourcePtr, leaveType, NotifyNonlinear);              QUEUE(sourcePtr, leaveType, NotifyNonlinear);
1055              for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0;              for (winPtr = sourcePtr->parentPtr, i = upLevels-1; i > 0;
1056                      winPtr = winPtr->parentPtr, i--) {                      winPtr = winPtr->parentPtr, i--) {
1057                  QUEUE(winPtr, leaveType, NotifyNonlinearVirtual);                  QUEUE(winPtr, leaveType, NotifyNonlinearVirtual);
1058              }              }
1059          }          }
1060          if (enterType != 0) {          if (enterType != 0) {
1061              for (i = downLevels-1; i > 0; i--) {              for (i = downLevels-1; i > 0; i--) {
1062                  for (winPtr = destPtr->parentPtr, j = 1; j < i;                  for (winPtr = destPtr->parentPtr, j = 1; j < i;
1063                          winPtr = winPtr->parentPtr, j++) {                          winPtr = winPtr->parentPtr, j++) {
1064                  }                  }
1065                  QUEUE(winPtr, enterType, NotifyNonlinearVirtual);                  QUEUE(winPtr, enterType, NotifyNonlinearVirtual);
1066              }              }
1067              if (destPtr != NULL) {              if (destPtr != NULL) {
1068                  QUEUE(destPtr, enterType, NotifyNonlinear);                  QUEUE(destPtr, enterType, NotifyNonlinear);
1069              }              }
1070          }          }
1071      }      }
1072  }  }
1073    
1074  /*  /*
1075   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1076   *   *
1077   * MovePointer2 --   * MovePointer2 --
1078   *   *
1079   *      This procedure synthesizes  EnterNotify and LeaveNotify events   *      This procedure synthesizes  EnterNotify and LeaveNotify events
1080   *      to correctly transfer the pointer from one window to another.   *      to correctly transfer the pointer from one window to another.
1081   *      It is different from TkInOutEvents in that no template X event   *      It is different from TkInOutEvents in that no template X event
1082   *      needs to be supplied;  this procedure generates the template   *      needs to be supplied;  this procedure generates the template
1083   *      event and calls TkInOutEvents.   *      event and calls TkInOutEvents.
1084   *   *
1085   * Results:   * Results:
1086   *      None.   *      None.
1087   *   *
1088   * Side effects:   * Side effects:
1089   *      Synthesized events may be pushed back onto the event queue.   *      Synthesized events may be pushed back onto the event queue.
1090   *   *
1091   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1092   */   */
1093    
1094  static void  static void
1095  MovePointer2(sourcePtr, destPtr, mode, leaveEvents, enterEvents)  MovePointer2(sourcePtr, destPtr, mode, leaveEvents, enterEvents)
1096      TkWindow *sourcePtr;        /* Window currently containing pointer (NULL      TkWindow *sourcePtr;        /* Window currently containing pointer (NULL
1097                                   * means it's not one managed by this                                   * means it's not one managed by this
1098                                   * process). */                                   * process). */
1099      TkWindow *destPtr;          /* Window that is to end up containing the      TkWindow *destPtr;          /* Window that is to end up containing the
1100                                   * pointer (NULL means it's not one managed                                   * pointer (NULL means it's not one managed
1101                                   * by this process). */                                   * by this process). */
1102      int mode;                   /* Mode for enter/leave events, such as      int mode;                   /* Mode for enter/leave events, such as
1103                                   * NotifyNormal or NotifyUngrab. */                                   * NotifyNormal or NotifyUngrab. */
1104      int leaveEvents;            /* Non-zero means generate leave events for the      int leaveEvents;            /* Non-zero means generate leave events for the
1105                                   * windows being left.  Zero means don't                                   * windows being left.  Zero means don't
1106                                   * generate leave events. */                                   * generate leave events. */
1107      int enterEvents;            /* Non-zero means generate enter events for the      int enterEvents;            /* Non-zero means generate enter events for the
1108                                   * windows being entered.  Zero means don't                                   * windows being entered.  Zero means don't
1109                                   * generate enter events. */                                   * generate enter events. */
1110  {  {
1111      XEvent event;      XEvent event;
1112      Window dummy1, dummy2;      Window dummy1, dummy2;
1113      int dummy3, dummy4;      int dummy3, dummy4;
1114      TkWindow *winPtr;      TkWindow *winPtr;
1115    
1116      winPtr = sourcePtr;      winPtr = sourcePtr;
1117      if ((winPtr == NULL) || (winPtr->window == None)) {      if ((winPtr == NULL) || (winPtr->window == None)) {
1118          winPtr = destPtr;          winPtr = destPtr;
1119          if ((winPtr == NULL) || (winPtr->window == None)) {          if ((winPtr == NULL) || (winPtr->window == None)) {
1120              return;              return;
1121          }          }
1122      }      }
1123    
1124      event.xcrossing.serial = LastKnownRequestProcessed(      event.xcrossing.serial = LastKnownRequestProcessed(
1125          winPtr->display);          winPtr->display);
1126      event.xcrossing.send_event = GENERATED_EVENT_MAGIC;      event.xcrossing.send_event = GENERATED_EVENT_MAGIC;
1127      event.xcrossing.display = winPtr->display;      event.xcrossing.display = winPtr->display;
1128      event.xcrossing.root = RootWindow(winPtr->display,      event.xcrossing.root = RootWindow(winPtr->display,
1129              winPtr->screenNum);              winPtr->screenNum);
1130      event.xcrossing.time = TkCurrentTime(winPtr->dispPtr);      event.xcrossing.time = TkCurrentTime(winPtr->dispPtr);
1131      XQueryPointer(winPtr->display, winPtr->window, &dummy1, &dummy2,      XQueryPointer(winPtr->display, winPtr->window, &dummy1, &dummy2,
1132              &event.xcrossing.x_root, &event.xcrossing.y_root,              &event.xcrossing.x_root, &event.xcrossing.y_root,
1133              &dummy3, &dummy4, &event.xcrossing.state);              &dummy3, &dummy4, &event.xcrossing.state);
1134      event.xcrossing.mode = mode;      event.xcrossing.mode = mode;
1135      event.xcrossing.focus = False;      event.xcrossing.focus = False;
1136      TkInOutEvents(&event, sourcePtr, destPtr, (leaveEvents) ? LeaveNotify : 0,      TkInOutEvents(&event, sourcePtr, destPtr, (leaveEvents) ? LeaveNotify : 0,
1137              (enterEvents) ? EnterNotify : 0, TCL_QUEUE_MARK);              (enterEvents) ? EnterNotify : 0, TCL_QUEUE_MARK);
1138  }  }
1139    
1140  /*  /*
1141   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1142   *   *
1143   * TkGrabDeadWindow --   * TkGrabDeadWindow --
1144   *   *
1145   *      This procedure is invoked whenever a window is deleted, so that   *      This procedure is invoked whenever a window is deleted, so that
1146   *      grab-related cleanup can be performed.   *      grab-related cleanup can be performed.
1147   *   *
1148   * Results:   * Results:
1149   *      None.   *      None.
1150   *   *
1151   * Side effects:   * Side effects:
1152   *      Various cleanups happen, such as generating events to move the   *      Various cleanups happen, such as generating events to move the
1153   *      pointer back to its "natural" window as if an ungrab had been   *      pointer back to its "natural" window as if an ungrab had been
1154   *      done.  See the code.   *      done.  See the code.
1155   *   *
1156   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1157   */   */
1158    
1159  void  void
1160  TkGrabDeadWindow(winPtr)  TkGrabDeadWindow(winPtr)
1161      register TkWindow *winPtr;          /* Window that is in the process      register TkWindow *winPtr;          /* Window that is in the process
1162                                           * of being deleted. */                                           * of being deleted. */
1163  {  {
1164      TkDisplay *dispPtr = winPtr->dispPtr;      TkDisplay *dispPtr = winPtr->dispPtr;
1165    
1166      if (dispPtr->eventualGrabWinPtr == winPtr) {      if (dispPtr->eventualGrabWinPtr == winPtr) {
1167          /*          /*
1168           * Grab window was deleted.  Release the grab.           * Grab window was deleted.  Release the grab.
1169           */           */
1170    
1171          Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr);          Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr);
1172      } else if (dispPtr->buttonWinPtr == winPtr) {      } else if (dispPtr->buttonWinPtr == winPtr) {
1173          ReleaseButtonGrab(dispPtr);          ReleaseButtonGrab(dispPtr);
1174      }      }
1175      if (dispPtr->serverWinPtr == winPtr) {      if (dispPtr->serverWinPtr == winPtr) {
1176          if (winPtr->flags & TK_TOP_LEVEL) {          if (winPtr->flags & TK_TOP_LEVEL) {
1177              dispPtr->serverWinPtr = NULL;              dispPtr->serverWinPtr = NULL;
1178          } else {          } else {
1179              dispPtr->serverWinPtr = winPtr->parentPtr;              dispPtr->serverWinPtr = winPtr->parentPtr;
1180          }          }
1181      }      }
1182      if (dispPtr->grabWinPtr == winPtr) {      if (dispPtr->grabWinPtr == winPtr) {
1183          dispPtr->grabWinPtr = NULL;          dispPtr->grabWinPtr = NULL;
1184      }      }
1185  }  }
1186    
1187  /*  /*
1188   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1189   *   *
1190   * EatGrabEvents --   * EatGrabEvents --
1191   *   *
1192   *      This procedure is called to eliminate any Enter, Leave,   *      This procedure is called to eliminate any Enter, Leave,
1193   *      FocusIn, or FocusOut events in the event queue for a   *      FocusIn, or FocusOut events in the event queue for a
1194   *      display that have mode NotifyGrab or NotifyUngrab and   *      display that have mode NotifyGrab or NotifyUngrab and
1195   *      have a serial number no less than a given value and are not   *      have a serial number no less than a given value and are not
1196   *      generated by the grab module.   *      generated by the grab module.
1197   *   *
1198   * Results:   * Results:
1199   *      None.   *      None.
1200   *   *
1201   * Side effects:   * Side effects:
1202   *      DispPtr's display gets sync-ed, and some of the events get   *      DispPtr's display gets sync-ed, and some of the events get
1203   *      removed from the Tk event queue.   *      removed from the Tk event queue.
1204   *   *
1205   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1206   */   */
1207    
1208  static void  static void
1209  EatGrabEvents(dispPtr, serial)  EatGrabEvents(dispPtr, serial)
1210      TkDisplay *dispPtr;         /* Display from which to consume events. */      TkDisplay *dispPtr;         /* Display from which to consume events. */
1211      unsigned int serial;        /* Only discard events that have a serial      unsigned int serial;        /* Only discard events that have a serial
1212                                   * number at least this great. */                                   * number at least this great. */
1213  {  {
1214      Tk_RestrictProc *oldProc;      Tk_RestrictProc *oldProc;
1215      GrabInfo info;      GrabInfo info;
1216      ClientData oldArg, dummy;      ClientData oldArg, dummy;
1217    
1218      info.display = dispPtr->display;      info.display = dispPtr->display;
1219      info.serial = serial;      info.serial = serial;
1220      TkpSync(info.display);      TkpSync(info.display);
1221      oldProc = Tk_RestrictEvents(GrabRestrictProc, (ClientData)&info, &oldArg);      oldProc = Tk_RestrictEvents(GrabRestrictProc, (ClientData)&info, &oldArg);
1222      while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {      while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {
1223      }      }
1224      Tk_RestrictEvents(oldProc, oldArg, &dummy);      Tk_RestrictEvents(oldProc, oldArg, &dummy);
1225  }  }
1226    
1227  /*  /*
1228   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1229   *   *
1230   * GrabRestrictProc --   * GrabRestrictProc --
1231   *   *
1232   *      A Tk_RestrictProc used by EatGrabEvents to eliminate any   *      A Tk_RestrictProc used by EatGrabEvents to eliminate any
1233   *      Enter, Leave, FocusIn, or FocusOut events in the event queue   *      Enter, Leave, FocusIn, or FocusOut events in the event queue
1234   *      for a display that has mode NotifyGrab or NotifyUngrab and   *      for a display that has mode NotifyGrab or NotifyUngrab and
1235   *      have a serial number no less than a given value.   *      have a serial number no less than a given value.
1236   *   *
1237   * Results:   * Results:
1238   *      Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT.   *      Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT.
1239   *   *
1240   * Side effects:   * Side effects:
1241   *      None.   *      None.
1242   *   *
1243   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1244   */   */
1245    
1246  static Tk_RestrictAction  static Tk_RestrictAction
1247  GrabRestrictProc(arg, eventPtr)  GrabRestrictProc(arg, eventPtr)
1248      ClientData arg;      ClientData arg;
1249      XEvent *eventPtr;      XEvent *eventPtr;
1250  {  {
1251      GrabInfo *info = (GrabInfo *) arg;      GrabInfo *info = (GrabInfo *) arg;
1252      int mode, diff;      int mode, diff;
1253    
1254      /*      /*
1255       * The diff caculation is trickier than it may seem.  Don't forget       * The diff caculation is trickier than it may seem.  Don't forget
1256       * that serial numbers can wrap around, so can't compare the two       * that serial numbers can wrap around, so can't compare the two
1257       * serial numbers directly.       * serial numbers directly.
1258       */       */
1259    
1260      diff = eventPtr->xany.serial - info->serial;      diff = eventPtr->xany.serial - info->serial;
1261      if ((eventPtr->type == EnterNotify)      if ((eventPtr->type == EnterNotify)
1262              || (eventPtr->type == LeaveNotify)) {              || (eventPtr->type == LeaveNotify)) {
1263          mode = eventPtr->xcrossing.mode;          mode = eventPtr->xcrossing.mode;
1264      } else if ((eventPtr->type == FocusIn)      } else if ((eventPtr->type == FocusIn)
1265              || (eventPtr->type == FocusOut)) {              || (eventPtr->type == FocusOut)) {
1266          mode = eventPtr->xfocus.mode;          mode = eventPtr->xfocus.mode;
1267      } else {      } else {
1268          mode = NotifyNormal;          mode = NotifyNormal;
1269      }      }
1270      if ((info->display != eventPtr->xany.display) || (mode == NotifyNormal)      if ((info->display != eventPtr->xany.display) || (mode == NotifyNormal)
1271              || (diff < 0)) {              || (diff < 0)) {
1272          return TK_DEFER_EVENT;          return TK_DEFER_EVENT;
1273      } else {      } else {
1274          return TK_DISCARD_EVENT;          return TK_DISCARD_EVENT;
1275      }      }
1276  }  }
1277    
1278  /*  /*
1279   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1280   *   *
1281   * QueueGrabWindowChange --   * QueueGrabWindowChange --
1282   *   *
1283   *      This procedure queues a special event in the Tcl event queue,   *      This procedure queues a special event in the Tcl event queue,
1284   *      which will cause the "grabWinPtr" field for the display to get   *      which will cause the "grabWinPtr" field for the display to get
1285   *      modified when the event is processed.  This is needed to make   *      modified when the event is processed.  This is needed to make
1286   *      sure that the grab window changes at the proper time relative   *      sure that the grab window changes at the proper time relative
1287   *      to grab-related enter and leave events that are also in the   *      to grab-related enter and leave events that are also in the
1288   *      queue.  In particular, this approach works even when multiple   *      queue.  In particular, this approach works even when multiple
1289   *      grabs and ungrabs happen back-to-back.   *      grabs and ungrabs happen back-to-back.
1290   *   *
1291   * Results:   * Results:
1292   *      None.   *      None.
1293   *   *
1294   * Side effects:   * Side effects:
1295   *      DispPtr->grabWinPtr will be modified later (by GrabWinEventProc)   *      DispPtr->grabWinPtr will be modified later (by GrabWinEventProc)
1296   *      when the event is removed from the grab event queue.   *      when the event is removed from the grab event queue.
1297   *   *
1298   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1299   */   */
1300    
1301  static void  static void
1302  QueueGrabWindowChange(dispPtr, grabWinPtr)  QueueGrabWindowChange(dispPtr, grabWinPtr)
1303      TkDisplay *dispPtr;         /* Display on which to change the grab      TkDisplay *dispPtr;         /* Display on which to change the grab
1304                                   * window. */                                   * window. */
1305      TkWindow *grabWinPtr;       /* Window that is to become the new grab      TkWindow *grabWinPtr;       /* Window that is to become the new grab
1306                                   * window (may be NULL). */                                   * window (may be NULL). */
1307  {  {
1308      NewGrabWinEvent *grabEvPtr;      NewGrabWinEvent *grabEvPtr;
1309    
1310      grabEvPtr = (NewGrabWinEvent *) ckalloc(sizeof(NewGrabWinEvent));      grabEvPtr = (NewGrabWinEvent *) ckalloc(sizeof(NewGrabWinEvent));
1311      grabEvPtr->header.proc = GrabWinEventProc;      grabEvPtr->header.proc = GrabWinEventProc;
1312      grabEvPtr->dispPtr = dispPtr;      grabEvPtr->dispPtr = dispPtr;
1313      if (grabWinPtr == NULL) {      if (grabWinPtr == NULL) {
1314          grabEvPtr->grabWindow = None;          grabEvPtr->grabWindow = None;
1315      } else {      } else {
1316          grabEvPtr->grabWindow = grabWinPtr->window;          grabEvPtr->grabWindow = grabWinPtr->window;
1317      }      }
1318      Tcl_QueueEvent(&grabEvPtr->header, TCL_QUEUE_MARK);      Tcl_QueueEvent(&grabEvPtr->header, TCL_QUEUE_MARK);
1319      dispPtr->eventualGrabWinPtr = grabWinPtr;      dispPtr->eventualGrabWinPtr = grabWinPtr;
1320  }  }
1321    
1322  /*  /*
1323   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1324   *   *
1325   * GrabWinEventProc --   * GrabWinEventProc --
1326   *   *
1327   *      This procedure is invoked as a handler for Tcl_Events of type   *      This procedure is invoked as a handler for Tcl_Events of type
1328   *      NewGrabWinEvent.  It updates the current grab window field in   *      NewGrabWinEvent.  It updates the current grab window field in
1329   *      a display.   *      a display.
1330   *   *
1331   * Results:   * Results:
1332   *      Returns 1 if the event was processed, 0 if it should be deferred   *      Returns 1 if the event was processed, 0 if it should be deferred
1333   *      for processing later.   *      for processing later.
1334   *   *
1335   * Side effects:   * Side effects:
1336   *      The grabWinPtr field is modified in the display associated with   *      The grabWinPtr field is modified in the display associated with
1337   *      the event.   *      the event.
1338   *   *
1339   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1340   */   */
1341    
1342  static int  static int
1343  GrabWinEventProc(evPtr, flags)  GrabWinEventProc(evPtr, flags)
1344      Tcl_Event *evPtr;           /* Event of type NewGrabWinEvent. */      Tcl_Event *evPtr;           /* Event of type NewGrabWinEvent. */
1345      int flags;                  /* Flags argument to Tk_DoOneEvent: indicates      int flags;                  /* Flags argument to Tk_DoOneEvent: indicates
1346                                   * what kinds of events are being processed                                   * what kinds of events are being processed
1347                                   * right now. */                                   * right now. */
1348  {  {
1349      NewGrabWinEvent *grabEvPtr = (NewGrabWinEvent *) evPtr;      NewGrabWinEvent *grabEvPtr = (NewGrabWinEvent *) evPtr;
1350    
1351      grabEvPtr->dispPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(      grabEvPtr->dispPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(
1352              grabEvPtr->dispPtr->display, grabEvPtr->grabWindow);              grabEvPtr->dispPtr->display, grabEvPtr->grabWindow);
1353      return 1;      return 1;
1354  }  }
1355    
1356  /*  /*
1357   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1358   *   *
1359   * FindCommonAncestor --   * FindCommonAncestor --
1360   *   *
1361   *      Given two windows, this procedure finds their least common   *      Given two windows, this procedure finds their least common
1362   *      ancestor and also computes how many levels up this ancestor   *      ancestor and also computes how many levels up this ancestor
1363   *      is from each of the original windows.   *      is from each of the original windows.
1364   *   *
1365   * Results:   * Results:
1366   *      If the windows are in different applications or top-level   *      If the windows are in different applications or top-level
1367   *      windows, then NULL is returned and *countPtr1 and *countPtr2   *      windows, then NULL is returned and *countPtr1 and *countPtr2
1368   *      are set to the depths of the two windows in their respective   *      are set to the depths of the two windows in their respective
1369   *      top-level windows (1 means the window is a top-level, 2 means   *      top-level windows (1 means the window is a top-level, 2 means
1370   *      its parent is a top-level, and so on).  Otherwise, the return   *      its parent is a top-level, and so on).  Otherwise, the return
1371   *      value is a pointer to the common ancestor and the counts are   *      value is a pointer to the common ancestor and the counts are
1372   *      set to the distance of winPtr1 and winPtr2 from this ancestor   *      set to the distance of winPtr1 and winPtr2 from this ancestor
1373   *      (1 means they're children, 2 means grand-children, etc.).   *      (1 means they're children, 2 means grand-children, etc.).
1374   *   *
1375   * Side effects:   * Side effects:
1376   *      None.   *      None.
1377   *   *
1378   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1379   */   */
1380    
1381  static TkWindow *  static TkWindow *
1382  FindCommonAncestor(winPtr1, winPtr2, countPtr1, countPtr2)  FindCommonAncestor(winPtr1, winPtr2, countPtr1, countPtr2)
1383      TkWindow *winPtr1;          /* First window.   May be NULL. */      TkWindow *winPtr1;          /* First window.   May be NULL. */
1384      TkWindow *winPtr2;          /* Second window.  May be NULL. */      TkWindow *winPtr2;          /* Second window.  May be NULL. */
1385      int *countPtr1;             /* Store nesting level of winPtr1 within      int *countPtr1;             /* Store nesting level of winPtr1 within
1386                                   * common ancestor here. */                                   * common ancestor here. */
1387      int *countPtr2;             /* Store nesting level of winPtr2 within      int *countPtr2;             /* Store nesting level of winPtr2 within
1388                                   * common ancestor here. */                                   * common ancestor here. */
1389  {  {
1390      register TkWindow *winPtr;      register TkWindow *winPtr;
1391      TkWindow *ancestorPtr;      TkWindow *ancestorPtr;
1392      int count1, count2, i;      int count1, count2, i;
1393    
1394      /*      /*
1395       * Mark winPtr1 and all of its ancestors with a special flag bit.       * Mark winPtr1 and all of its ancestors with a special flag bit.
1396       */       */
1397    
1398      if (winPtr1 != NULL) {      if (winPtr1 != NULL) {
1399          for (winPtr = winPtr1; winPtr != NULL; winPtr = winPtr->parentPtr) {          for (winPtr = winPtr1; winPtr != NULL; winPtr = winPtr->parentPtr) {
1400              winPtr->flags |= TK_GRAB_FLAG;              winPtr->flags |= TK_GRAB_FLAG;
1401              if (winPtr->flags & TK_TOP_LEVEL) {              if (winPtr->flags & TK_TOP_LEVEL) {
1402                  break;                  break;
1403              }              }
1404          }          }
1405      }      }
1406    
1407      /*      /*
1408       * Search upwards from winPtr2 until an ancestor of winPtr1 is       * Search upwards from winPtr2 until an ancestor of winPtr1 is
1409       * found or a top-level window is reached.       * found or a top-level window is reached.
1410       */       */
1411    
1412      winPtr = winPtr2;      winPtr = winPtr2;
1413      count2 = 0;      count2 = 0;
1414      ancestorPtr = NULL;      ancestorPtr = NULL;
1415      if (winPtr2 != NULL) {      if (winPtr2 != NULL) {
1416          for (; winPtr != NULL; count2++, winPtr = winPtr->parentPtr) {          for (; winPtr != NULL; count2++, winPtr = winPtr->parentPtr) {
1417              if (winPtr->flags & TK_GRAB_FLAG) {              if (winPtr->flags & TK_GRAB_FLAG) {
1418                  ancestorPtr = winPtr;                  ancestorPtr = winPtr;
1419                  break;                  break;
1420              }              }
1421              if (winPtr->flags & TK_TOP_LEVEL)  {              if (winPtr->flags & TK_TOP_LEVEL)  {
1422                  count2++;                  count2++;
1423                  break;                  break;
1424              }              }
1425          }          }
1426      }      }
1427    
1428      /*      /*
1429       * Search upwards from winPtr1 again, clearing the flag bits and       * Search upwards from winPtr1 again, clearing the flag bits and
1430       * remembering how many levels up we had to go.       * remembering how many levels up we had to go.
1431       */       */
1432    
1433      if (winPtr1 == NULL) {      if (winPtr1 == NULL) {
1434          count1 = 0;          count1 = 0;
1435      } else {      } else {
1436          count1 = -1;          count1 = -1;
1437          for (i = 0, winPtr = winPtr1; winPtr != NULL;          for (i = 0, winPtr = winPtr1; winPtr != NULL;
1438                  i++, winPtr = winPtr->parentPtr) {                  i++, winPtr = winPtr->parentPtr) {
1439              winPtr->flags &= ~TK_GRAB_FLAG;              winPtr->flags &= ~TK_GRAB_FLAG;
1440              if (winPtr == ancestorPtr) {              if (winPtr == ancestorPtr) {
1441                  count1 = i;                  count1 = i;
1442              }              }
1443              if (winPtr->flags & TK_TOP_LEVEL) {              if (winPtr->flags & TK_TOP_LEVEL) {
1444                  if (count1 == -1) {                  if (count1 == -1) {
1445                      count1 = i+1;                      count1 = i+1;
1446                  }                  }
1447                  break;                  break;
1448              }              }
1449          }          }
1450      }      }
1451    
1452      *countPtr1 = count1;      *countPtr1 = count1;
1453      *countPtr2 = count2;      *countPtr2 = count2;
1454      return ancestorPtr;      return ancestorPtr;
1455  }  }
1456    
1457  /*  /*
1458   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1459   *   *
1460   * TkPositionInTree --   * TkPositionInTree --
1461   *   *
1462   *      Compute where the given window is relative to a particular   *      Compute where the given window is relative to a particular
1463   *      subtree of the window hierarchy.   *      subtree of the window hierarchy.
1464   *   *
1465   * Results:   * Results:
1466   *   *
1467   *      Returns TK_GRAB_IN_TREE if the window is contained in the   *      Returns TK_GRAB_IN_TREE if the window is contained in the
1468   *      subtree.  Returns TK_GRAB_ANCESTOR if the window is an   *      subtree.  Returns TK_GRAB_ANCESTOR if the window is an
1469   *      ancestor of the subtree, in the same toplevel.  Otherwise   *      ancestor of the subtree, in the same toplevel.  Otherwise
1470   *      it returns TK_GRAB_EXCLUDED.   *      it returns TK_GRAB_EXCLUDED.
1471   *   *
1472   * Side effects:   * Side effects:
1473   *      None.   *      None.
1474   *   *
1475   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1476   */   */
1477    
1478  int  int
1479  TkPositionInTree(winPtr, treePtr)  TkPositionInTree(winPtr, treePtr)
1480      TkWindow *winPtr;           /* Window to be checked. */      TkWindow *winPtr;           /* Window to be checked. */
1481      TkWindow *treePtr;          /* Root of tree to compare against. */      TkWindow *treePtr;          /* Root of tree to compare against. */
1482  {  {
1483      TkWindow *winPtr2;      TkWindow *winPtr2;
1484    
1485      for (winPtr2 = winPtr; winPtr2 != treePtr;      for (winPtr2 = winPtr; winPtr2 != treePtr;
1486             winPtr2 = winPtr2->parentPtr) {             winPtr2 = winPtr2->parentPtr) {
1487          if (winPtr2 == NULL) {          if (winPtr2 == NULL) {
1488              for (winPtr2 = treePtr; winPtr2 != NULL;              for (winPtr2 = treePtr; winPtr2 != NULL;
1489                      winPtr2 = winPtr2->parentPtr) {                      winPtr2 = winPtr2->parentPtr) {
1490                  if (winPtr2 == winPtr) {                  if (winPtr2 == winPtr) {
1491                      return TK_GRAB_ANCESTOR;                      return TK_GRAB_ANCESTOR;
1492                  }                  }
1493                  if (winPtr2->flags & TK_TOP_LEVEL) {                  if (winPtr2->flags & TK_TOP_LEVEL) {
1494                      break;                      break;
1495                  }                  }
1496              }              }
1497              return TK_GRAB_EXCLUDED;              return TK_GRAB_EXCLUDED;
1498          }          }
1499      }      }
1500      return TK_GRAB_IN_TREE;      return TK_GRAB_IN_TREE;
1501  }  }
1502    
1503  /*  /*
1504   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1505   *   *
1506   * TkGrabState --   * TkGrabState --
1507   *   *
1508   *      Given a window, this procedure returns a value that indicates   *      Given a window, this procedure returns a value that indicates
1509   *      the grab state of the application relative to the window.   *      the grab state of the application relative to the window.
1510   *   *
1511   * Results:   * Results:
1512   *      The return value is one of three things:   *      The return value is one of three things:
1513   *          TK_GRAB_NONE -      no grab is in effect.   *          TK_GRAB_NONE -      no grab is in effect.
1514   *          TK_GRAB_IN_TREE -   there is a grab in effect, and winPtr   *          TK_GRAB_IN_TREE -   there is a grab in effect, and winPtr
1515   *                              is in the grabbed subtree.   *                              is in the grabbed subtree.
1516   *          TK_GRAB_ANCESTOR -  there is a grab in effect;  winPtr is   *          TK_GRAB_ANCESTOR -  there is a grab in effect;  winPtr is
1517   *                              an ancestor of the grabbed window, in   *                              an ancestor of the grabbed window, in
1518   *                              the same toplevel.   *                              the same toplevel.
1519   *          TK_GRAB_EXCLUDED -  there is a grab in effect; winPtr is   *          TK_GRAB_EXCLUDED -  there is a grab in effect; winPtr is
1520   *                              outside the tree of the grab and is not   *                              outside the tree of the grab and is not
1521   *                              an ancestor of the grabbed window in the   *                              an ancestor of the grabbed window in the
1522   *                              same toplevel.   *                              same toplevel.
1523   *   *
1524   * Side effects:   * Side effects:
1525   *      None.   *      None.
1526   *   *
1527   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1528   */   */
1529    
1530  int  int
1531  TkGrabState(winPtr)  TkGrabState(winPtr)
1532      TkWindow *winPtr;           /* Window for which grab information is      TkWindow *winPtr;           /* Window for which grab information is
1533                                   * needed. */                                   * needed. */
1534  {  {
1535      TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr;      TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr;
1536    
1537      if (grabWinPtr == NULL) {      if (grabWinPtr == NULL) {
1538          return TK_GRAB_NONE;          return TK_GRAB_NONE;
1539      }      }
1540      if ((winPtr->mainPtr != grabWinPtr->mainPtr)      if ((winPtr->mainPtr != grabWinPtr->mainPtr)
1541              && !(winPtr->dispPtr->grabFlags & GRAB_GLOBAL)) {              && !(winPtr->dispPtr->grabFlags & GRAB_GLOBAL)) {
1542          return TK_GRAB_NONE;          return TK_GRAB_NONE;
1543      }      }
1544    
1545      return TkPositionInTree(winPtr, grabWinPtr);      return TkPositionInTree(winPtr, grabWinPtr);
1546  }  }
1547    
1548  /* End of tkgrab.c */  /* End of tkgrab.c */

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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25