enterleave.c revision 4202a189
14642e01fSmrg/* 24642e01fSmrg * Copyright © 2008 Red Hat, Inc. 34642e01fSmrg * 44642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 54642e01fSmrg * copy of this software and associated documentation files (the "Software"), 64642e01fSmrg * to deal in the Software without restriction, including without limitation 74642e01fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 84642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the 94642e01fSmrg * Software is furnished to do so, subject to the following conditions: 104642e01fSmrg * 114642e01fSmrg * The above copyright notice and this permission notice (including the next 124642e01fSmrg * paragraph) shall be included in all copies or substantial portions of the 134642e01fSmrg * Software. 144642e01fSmrg * 154642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 164642e01fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 174642e01fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 184642e01fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 194642e01fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 204642e01fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 214642e01fSmrg * DEALINGS IN THE SOFTWARE. 224642e01fSmrg * 234642e01fSmrg * Authors: Peter Hutterer 244642e01fSmrg * 254642e01fSmrg */ 264642e01fSmrg 274642e01fSmrg#ifdef HAVE_DIX_CONFIG_H 284642e01fSmrg#include <dix-config.h> 294642e01fSmrg#endif 304642e01fSmrg 314642e01fSmrg#include <X11/X.h> 324202a189Smrg#include <X11/extensions/XI2.h> 334202a189Smrg#include "inputstr.h" 344642e01fSmrg#include "windowstr.h" 354642e01fSmrg#include "scrnintstr.h" 364642e01fSmrg#include "exglobals.h" 374642e01fSmrg#include "enterleave.h" 384642e01fSmrg 394202a189Smrg/** 404202a189Smrg * @file 414202a189Smrg * This file describes the model for sending core enter/leave events and 424202a189Smrg * focus in/out in the case of multiple pointers/keyboard foci. 434202a189Smrg * 444642e01fSmrg * Since we can't send more than one Enter or Leave/Focus in or out event per 454642e01fSmrg * window to a core client without confusing it, this is a rather complicated 464642e01fSmrg * approach. 474642e01fSmrg * 484642e01fSmrg * For a full description of the enter/leave model from a window's 494642e01fSmrg * perspective, see 504642e01fSmrg * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html 514642e01fSmrg * 524642e01fSmrg * For a full description of the focus in/out model from a window's 534642e01fSmrg * perspective, see 544642e01fSmrg * http://lists.freedesktop.org/archives/xorg/2008-December/041740.html 554642e01fSmrg * 564642e01fSmrg * Additional notes: 574202a189Smrg * - The core protocol spec says that "In a LeaveNotify event, if a child of the 584642e01fSmrg * event window contains the initial position of the pointer, then the child 594642e01fSmrg * component is set to that child. Otherwise, it is None. For an EnterNotify 604642e01fSmrg * event, if a child of the event window contains the final pointer position, 614642e01fSmrg * then the child component is set to that child. Otherwise, it is None." 624642e01fSmrg * 634642e01fSmrg * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual 644642e01fSmrg * events may have a subwindow set to other than None. 654642e01fSmrg * 664202a189Smrg * - NotifyPointer events may be sent if the focus changes from window A to 674642e01fSmrg * B. The assumption used in this model is that NotifyPointer events are only 684642e01fSmrg * sent for the pointer paired with the keyboard that is involved in the focus 694642e01fSmrg * events. For example, if F(W) changes because of keyboard 2, then 704642e01fSmrg * NotifyPointer events are only sent for pointer 2. 714642e01fSmrg */ 724642e01fSmrg 734642e01fSmrgstatic WindowPtr PointerWindows[MAXDEVICES]; 744642e01fSmrgstatic WindowPtr FocusWindows[MAXDEVICES]; 754642e01fSmrg 764642e01fSmrg/** 774202a189Smrg * Return TRUE if 'win' has a pointer within its boundaries, excluding child 784642e01fSmrg * window. 794642e01fSmrg */ 804642e01fSmrgstatic BOOL 814202a189SmrgHasPointer(DeviceIntPtr dev, WindowPtr win) 824642e01fSmrg{ 834642e01fSmrg int i; 844642e01fSmrg 854202a189Smrg /* FIXME: The enter/leave model does not cater for grabbed devices. For 864202a189Smrg * now, a quickfix: if the device about to send an enter/leave event to 874202a189Smrg * a window is grabbed, assume there is no pointer in that window. 884202a189Smrg * Fixes fdo 27804. 894202a189Smrg * There isn't enough beer in my fridge to fix this properly. 904202a189Smrg */ 914202a189Smrg if (dev->deviceGrab.grab) 924202a189Smrg return FALSE; 934202a189Smrg 944642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 954642e01fSmrg if (PointerWindows[i] == win) 964642e01fSmrg return TRUE; 974642e01fSmrg 984642e01fSmrg return FALSE; 994642e01fSmrg} 1004642e01fSmrg 1014642e01fSmrg/** 1024202a189Smrg * Return TRUE if at least one keyboard focus is set to 'win' (excluding 1034642e01fSmrg * descendants of win). 1044642e01fSmrg */ 1054642e01fSmrgstatic BOOL 1064642e01fSmrgHasFocus(WindowPtr win) 1074642e01fSmrg{ 1084642e01fSmrg int i; 1094642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 1104642e01fSmrg if (FocusWindows[i] == win) 1114642e01fSmrg return TRUE; 1124642e01fSmrg 1134642e01fSmrg return FALSE; 1144642e01fSmrg} 1154642e01fSmrg 1164642e01fSmrg/** 1174202a189Smrg * Return the window the device dev is currently on. 1184642e01fSmrg */ 1194642e01fSmrgstatic WindowPtr 1204642e01fSmrgPointerWin(DeviceIntPtr dev) 1214642e01fSmrg{ 1224642e01fSmrg return PointerWindows[dev->id]; 1234642e01fSmrg} 1244642e01fSmrg 1254642e01fSmrg/** 1264202a189Smrg * Search for the first window below 'win' that has a pointer directly within 1274642e01fSmrg * it's boundaries (excluding boundaries of its own descendants). 1284642e01fSmrg * 1294642e01fSmrg * @return The child window that has the pointer within its boundaries or 1304642e01fSmrg * NULL. 1314642e01fSmrg */ 1324642e01fSmrgstatic WindowPtr 1334642e01fSmrgFirstPointerChild(WindowPtr win) 1344642e01fSmrg{ 1354642e01fSmrg int i; 1364642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 1374642e01fSmrg { 1384642e01fSmrg if (PointerWindows[i] && IsParent(win, PointerWindows[i])) 1394642e01fSmrg return PointerWindows[i]; 1404642e01fSmrg } 1414642e01fSmrg 1424642e01fSmrg return NULL; 1434642e01fSmrg} 1444642e01fSmrg 1454642e01fSmrg/** 1464202a189Smrg * Search for the first window below 'win' that has a focus directly within 1474642e01fSmrg * it's boundaries (excluding boundaries of its own descendants). 1484642e01fSmrg * 1494642e01fSmrg * @return The child window that has the pointer within its boundaries or 1504642e01fSmrg * NULL. 1514642e01fSmrg */ 1524642e01fSmrgstatic WindowPtr 1534642e01fSmrgFirstFocusChild(WindowPtr win) 1544642e01fSmrg{ 1554642e01fSmrg int i; 1564642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 1574642e01fSmrg { 1584642e01fSmrg if (FocusWindows[i] && FocusWindows[i] != PointerRootWin && 1594642e01fSmrg IsParent(win, FocusWindows[i])) 1604642e01fSmrg return FocusWindows[i]; 1614642e01fSmrg } 1624642e01fSmrg 1634642e01fSmrg return NULL; 1644642e01fSmrg} 1654642e01fSmrg 1664642e01fSmrg/** 1674202a189Smrg * Set the presence flag for dev to mark that it is now in 'win'. 1684642e01fSmrg */ 1694642e01fSmrgvoid 1704642e01fSmrgEnterWindow(DeviceIntPtr dev, WindowPtr win, int mode) 1714642e01fSmrg{ 1724642e01fSmrg PointerWindows[dev->id] = win; 1734642e01fSmrg} 1744642e01fSmrg 1754642e01fSmrg/** 1764202a189Smrg * Unset the presence flag for dev to mark that it is not in 'win' anymore. 1774642e01fSmrg */ 1784202a189Smrgvoid 1794202a189SmrgLeaveWindow(DeviceIntPtr dev) 1804642e01fSmrg{ 1814642e01fSmrg PointerWindows[dev->id] = NULL; 1824642e01fSmrg} 1834642e01fSmrg 1844642e01fSmrg/** 1854202a189Smrg * Set the presence flag for dev to mark that it is now in 'win'. 1864642e01fSmrg */ 1874642e01fSmrgvoid 1884642e01fSmrgSetFocusIn(DeviceIntPtr dev, WindowPtr win) 1894642e01fSmrg{ 1904642e01fSmrg FocusWindows[dev->id] = win; 1914642e01fSmrg} 1924642e01fSmrg 1934642e01fSmrg/** 1944202a189Smrg * Unset the presence flag for dev to mark that it is not in 'win' anymore. 1954642e01fSmrg */ 1964642e01fSmrgvoid 1974202a189SmrgSetFocusOut(DeviceIntPtr dev) 1984642e01fSmrg{ 1994642e01fSmrg FocusWindows[dev->id] = NULL; 2004642e01fSmrg} 2014642e01fSmrg 2024642e01fSmrg 2034642e01fSmrg 2044642e01fSmrg 2054642e01fSmrg/** 2064202a189Smrg * Return the common ancestor of 'a' and 'b' (if one exists). 2074202a189Smrg * @param a A window with the same ancestor as b. 2084202a189Smrg * @param b A window with the same ancestor as a. 2094202a189Smrg * @return The window that is the first ancestor of both 'a' and 'b', or the 2104202a189Smrg * NullWindow if they do not have a common ancestor. 2114642e01fSmrg */ 2124642e01fSmrgWindowPtr 2134642e01fSmrgCommonAncestor( 2144642e01fSmrg WindowPtr a, 2154642e01fSmrg WindowPtr b) 2164642e01fSmrg{ 2174642e01fSmrg for (b = b->parent; b; b = b->parent) 2184642e01fSmrg if (IsParent(b, a)) return b; 2194642e01fSmrg return NullWindow; 2204642e01fSmrg} 2214642e01fSmrg 2224642e01fSmrg 2234642e01fSmrg/** 2244202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 2254642e01fSmrg * both). Events are sent running up the window hierarchy. This function 2264642e01fSmrg * recurses. 2274642e01fSmrg */ 2284642e01fSmrgstatic void 2294642e01fSmrgDeviceEnterNotifies(DeviceIntPtr dev, 2304202a189Smrg int sourceid, 2314642e01fSmrg WindowPtr ancestor, 2324642e01fSmrg WindowPtr child, 2334642e01fSmrg int mode, 2344642e01fSmrg int detail) 2354642e01fSmrg{ 2364642e01fSmrg WindowPtr parent = child->parent; 2374642e01fSmrg 2384642e01fSmrg if (ancestor == parent) 2394642e01fSmrg return; 2404202a189Smrg DeviceEnterNotifies(dev, sourceid, ancestor, parent, mode, detail); 2414202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, detail, parent, 2424642e01fSmrg child->drawable.id); 2434642e01fSmrg} 2444642e01fSmrg 2454642e01fSmrg/** 2464202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 2474642e01fSmrg * both). Events are sent running down the window hierarchy. This function 2484642e01fSmrg * recurses. 2494642e01fSmrg */ 2504642e01fSmrgstatic void 2514642e01fSmrgCoreEnterNotifies(DeviceIntPtr dev, 2524642e01fSmrg WindowPtr ancestor, 2534642e01fSmrg WindowPtr child, 2544642e01fSmrg int mode, 2554642e01fSmrg int detail) 2564642e01fSmrg{ 2574642e01fSmrg WindowPtr parent = child->parent; 2584642e01fSmrg if (ancestor == parent) 2594642e01fSmrg return; 2604642e01fSmrg CoreEnterNotifies(dev, ancestor, parent, mode, detail); 2614642e01fSmrg 2624642e01fSmrg 2634642e01fSmrg /* Case 3: 2644642e01fSmrg A is above W, B is a descendant 2654642e01fSmrg 2664642e01fSmrg Classically: The move generates an EnterNotify on W with a detail of 2674642e01fSmrg Virtual or NonlinearVirtual 2684642e01fSmrg 2694642e01fSmrg MPX: 2704642e01fSmrg Case 3A: There is at least one other pointer on W itself 2714642e01fSmrg P(W) doesn't change, so the event should be suppressed 2724642e01fSmrg Case 3B: Otherwise, if there is at least one other pointer in a 2734642e01fSmrg descendant 2744642e01fSmrg P(W) stays on the same descendant, or changes to a different 2754642e01fSmrg descendant. The event should be suppressed. 2764642e01fSmrg Case 3C: Otherwise: 2774642e01fSmrg P(W) moves from a window above W to a descendant. The subwindow 2784642e01fSmrg field is set to the child containing the descendant. The detail 2794642e01fSmrg may need to be changed from Virtual to NonlinearVirtual depending 2804642e01fSmrg on the previous P(W). */ 2814642e01fSmrg 2824202a189Smrg if (!HasPointer(dev, parent) && !FirstPointerChild(parent)) 2834642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent, 2844642e01fSmrg child->drawable.id); 2854642e01fSmrg} 2864642e01fSmrg 2874642e01fSmrgstatic void 2884642e01fSmrgCoreLeaveNotifies(DeviceIntPtr dev, 2894642e01fSmrg WindowPtr child, 2904642e01fSmrg WindowPtr ancestor, 2914642e01fSmrg int mode, 2924642e01fSmrg int detail) 2934642e01fSmrg{ 2944642e01fSmrg WindowPtr win; 2954642e01fSmrg 2964642e01fSmrg if (ancestor == child) 2974642e01fSmrg return; 2984642e01fSmrg 2994642e01fSmrg for (win = child->parent; win != ancestor; win = win->parent) 3004642e01fSmrg { 3014642e01fSmrg /*Case 7: 3024642e01fSmrg A is a descendant of W, B is above W 3034642e01fSmrg 3044642e01fSmrg Classically: A LeaveNotify is generated on W with a detail of Virtual 3054642e01fSmrg or NonlinearVirtual. 3064642e01fSmrg 3074642e01fSmrg MPX: 3084642e01fSmrg Case 3A: There is at least one other pointer on W itself 3094642e01fSmrg P(W) doesn't change, the event should be suppressed. 3104642e01fSmrg Case 3B: Otherwise, if there is at least one other pointer in a 3114642e01fSmrg descendant 3124642e01fSmrg P(W) stays on the same descendant, or changes to a different 3134642e01fSmrg descendant. The event should be suppressed. 3144642e01fSmrg Case 3C: Otherwise: 3154642e01fSmrg P(W) changes from the descendant of W to a window above W. 3164642e01fSmrg The detail may need to be changed from Virtual to NonlinearVirtual 3174642e01fSmrg or vice-versa depending on the new P(W).*/ 3184642e01fSmrg 3194642e01fSmrg /* If one window has a pointer or a child with a pointer, skip some 3204642e01fSmrg * work and exit. */ 3214202a189Smrg if (HasPointer(dev, win) || FirstPointerChild(win)) 3224642e01fSmrg return; 3234642e01fSmrg 3244642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win, child->drawable.id); 3254642e01fSmrg 3264642e01fSmrg child = win; 3274642e01fSmrg } 3284642e01fSmrg} 3294642e01fSmrg 3304642e01fSmrg/** 3314202a189Smrg * Send leave notifies to all windows between 'child' and 'ancestor'. 3324642e01fSmrg * Events are sent running up the hierarchy. 3334642e01fSmrg */ 3344642e01fSmrgstatic void 3354642e01fSmrgDeviceLeaveNotifies(DeviceIntPtr dev, 3364202a189Smrg int sourceid, 3374642e01fSmrg WindowPtr child, 3384642e01fSmrg WindowPtr ancestor, 3394642e01fSmrg int mode, 3404642e01fSmrg int detail) 3414642e01fSmrg{ 3424642e01fSmrg WindowPtr win; 3434642e01fSmrg 3444642e01fSmrg if (ancestor == child) 3454642e01fSmrg return; 3464642e01fSmrg for (win = child->parent; win != ancestor; win = win->parent) 3474642e01fSmrg { 3484202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, detail, win, 3494642e01fSmrg child->drawable.id); 3504642e01fSmrg child = win; 3514642e01fSmrg } 3524642e01fSmrg} 3534642e01fSmrg 3544642e01fSmrg/** 3554202a189Smrg * Pointer dev moves from A to B and A neither a descendant of B nor is 3564202a189Smrg * B a descendant of A. 3574642e01fSmrg */ 3584642e01fSmrgstatic void 3594642e01fSmrgCoreEnterLeaveNonLinear(DeviceIntPtr dev, 3604642e01fSmrg WindowPtr A, 3614642e01fSmrg WindowPtr B, 3624642e01fSmrg int mode) 3634642e01fSmrg{ 3644642e01fSmrg WindowPtr X = CommonAncestor(A, B); 3654642e01fSmrg /* Case 4: 3664642e01fSmrg A is W, B is above W 3674642e01fSmrg 3684642e01fSmrg Classically: The move generates a LeaveNotify on W with a detail of 3694642e01fSmrg Ancestor or Nonlinear 3704642e01fSmrg 3714642e01fSmrg MPX: 3724642e01fSmrg Case 3A: There is at least one other pointer on W itself 3734642e01fSmrg P(W) doesn't change, the event should be suppressed 3744642e01fSmrg Case 3B: Otherwise, if there is at least one other pointer in a 3754642e01fSmrg descendant of W 3764642e01fSmrg P(W) changes from W to a descendant of W. The subwindow field 3774642e01fSmrg is set to the child containing the new P(W), the detail field 3784642e01fSmrg is set to Inferior 3794642e01fSmrg Case 3C: Otherwise: 3804642e01fSmrg The pointer window moves from W to a window above W. 3814642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear or 3824642e01fSmrg vice versa depending on the the new P(W) 3834642e01fSmrg */ 3844642e01fSmrg 3854202a189Smrg if (!HasPointer(dev, A)) 3864642e01fSmrg { 3874642e01fSmrg WindowPtr child = FirstPointerChild(A); 3884642e01fSmrg if (child) 3894642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None); 3904642e01fSmrg else 3914642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyNonlinear, A, None); 3924642e01fSmrg } 3934642e01fSmrg 3944642e01fSmrg 3954642e01fSmrg CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual); 3964642e01fSmrg 3974642e01fSmrg /* 3984642e01fSmrg Case 9: 3994642e01fSmrg A is a descendant of W, B is a descendant of W 4004642e01fSmrg 4014642e01fSmrg Classically: No events are generated on W 4024642e01fSmrg MPX: The pointer window stays the same or moves to a different 4034642e01fSmrg descendant of W. No events should be generated on W. 4044642e01fSmrg 4054642e01fSmrg 4064642e01fSmrg Therefore, no event to X. 4074642e01fSmrg */ 4084642e01fSmrg 4094642e01fSmrg CoreEnterNotifies(dev, X, B, mode, NotifyNonlinearVirtual); 4104642e01fSmrg 4114642e01fSmrg /* Case 2: 4124642e01fSmrg A is above W, B=W 4134642e01fSmrg 4144642e01fSmrg Classically: The move generates an EnterNotify on W with a detail of 4154642e01fSmrg Ancestor or Nonlinear 4164642e01fSmrg 4174642e01fSmrg MPX: 4184642e01fSmrg Case 2A: There is at least one other pointer on W itself 4194642e01fSmrg P(W) doesn't change, so the event should be suppressed 4204642e01fSmrg Case 2B: Otherwise, if there is at least one other pointer in a 4214642e01fSmrg descendant 4224642e01fSmrg P(W) moves from a descendant to W. detail is changed to Inferior, 4234642e01fSmrg subwindow is set to the child containing the previous P(W) 4244642e01fSmrg Case 2C: Otherwise: 4254642e01fSmrg P(W) changes from a window above W to W itself. 4264642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear 4274642e01fSmrg or vice-versa depending on the previous P(W). */ 4284642e01fSmrg 4294202a189Smrg if (!HasPointer(dev, B)) 4304642e01fSmrg { 4314642e01fSmrg WindowPtr child = FirstPointerChild(B); 4324642e01fSmrg if (child) 4334642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None); 4344642e01fSmrg else 4354642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyNonlinear, B, None); 4364642e01fSmrg } 4374642e01fSmrg} 4384642e01fSmrg 4394642e01fSmrg/** 4404202a189Smrg * Pointer dev moves from A to B and A is a descendant of B. 4414642e01fSmrg */ 4424642e01fSmrgstatic void 4434642e01fSmrgCoreEnterLeaveToAncestor(DeviceIntPtr dev, 4444642e01fSmrg WindowPtr A, 4454642e01fSmrg WindowPtr B, 4464642e01fSmrg int mode) 4474642e01fSmrg{ 4484642e01fSmrg /* Case 4: 4494642e01fSmrg A is W, B is above W 4504642e01fSmrg 4514642e01fSmrg Classically: The move generates a LeaveNotify on W with a detail of 4524642e01fSmrg Ancestor or Nonlinear 4534642e01fSmrg 4544642e01fSmrg MPX: 4554642e01fSmrg Case 3A: There is at least one other pointer on W itself 4564642e01fSmrg P(W) doesn't change, the event should be suppressed 4574642e01fSmrg Case 3B: Otherwise, if there is at least one other pointer in a 4584642e01fSmrg descendant of W 4594642e01fSmrg P(W) changes from W to a descendant of W. The subwindow field 4604642e01fSmrg is set to the child containing the new P(W), the detail field 4614642e01fSmrg is set to Inferior 4624642e01fSmrg Case 3C: Otherwise: 4634642e01fSmrg The pointer window moves from W to a window above W. 4644642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear or 4654642e01fSmrg vice versa depending on the the new P(W) 4664642e01fSmrg */ 4674202a189Smrg if (!HasPointer(dev, A)) 4684642e01fSmrg { 4694642e01fSmrg WindowPtr child = FirstPointerChild(A); 4704642e01fSmrg if (child) 4714642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None); 4724642e01fSmrg else 4734642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyAncestor, A, None); 4744642e01fSmrg } 4754642e01fSmrg 4764642e01fSmrg CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual); 4774642e01fSmrg 4784642e01fSmrg /* Case 8: 4794642e01fSmrg A is a descendant of W, B is W 4804642e01fSmrg 4814642e01fSmrg Classically: A EnterNotify is generated on W with a detail of 4824642e01fSmrg NotifyInferior 4834642e01fSmrg 4844642e01fSmrg MPX: 4854642e01fSmrg Case 3A: There is at least one other pointer on W itself 4864642e01fSmrg P(W) doesn't change, the event should be suppressed 4874642e01fSmrg Case 3B: Otherwise: 4884642e01fSmrg P(W) changes from a descendant to W itself. The subwindow 4894642e01fSmrg field should be set to the child containing the old P(W) <<< WRONG */ 4904642e01fSmrg 4914202a189Smrg if (!HasPointer(dev, B)) 4924642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None); 4934642e01fSmrg 4944642e01fSmrg} 4954642e01fSmrg 4964642e01fSmrg 4974642e01fSmrg/** 4984202a189Smrg * Pointer dev moves from A to B and B is a descendant of A. 4994642e01fSmrg */ 5004642e01fSmrgstatic void 5014642e01fSmrgCoreEnterLeaveToDescendant(DeviceIntPtr dev, 5024642e01fSmrg WindowPtr A, 5034642e01fSmrg WindowPtr B, 5044642e01fSmrg int mode) 5054642e01fSmrg{ 5064642e01fSmrg /* Case 6: 5074642e01fSmrg A is W, B is a descendant of W 5084642e01fSmrg 5094642e01fSmrg Classically: A LeaveNotify is generated on W with a detail of 5104642e01fSmrg NotifyInferior 5114642e01fSmrg 5124642e01fSmrg MPX: 5134642e01fSmrg Case 3A: There is at least one other pointer on W itself 5144642e01fSmrg P(W) doesn't change, the event should be suppressed 5154642e01fSmrg Case 3B: Otherwise: 5164642e01fSmrg P(W) changes from W to a descendant of W. The subwindow field 5174642e01fSmrg is set to the child containing the new P(W) <<< THIS IS WRONG */ 5184642e01fSmrg 5194202a189Smrg if (!HasPointer(dev, A)) 5204642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None); 5214642e01fSmrg 5224642e01fSmrg 5234642e01fSmrg CoreEnterNotifies(dev, A, B, mode, NotifyVirtual); 5244642e01fSmrg 5254642e01fSmrg /* Case 2: 5264642e01fSmrg A is above W, B=W 5274642e01fSmrg 5284642e01fSmrg Classically: The move generates an EnterNotify on W with a detail of 5294642e01fSmrg Ancestor or Nonlinear 5304642e01fSmrg 5314642e01fSmrg MPX: 5324642e01fSmrg Case 2A: There is at least one other pointer on W itself 5334642e01fSmrg P(W) doesn't change, so the event should be suppressed 5344642e01fSmrg Case 2B: Otherwise, if there is at least one other pointer in a 5354642e01fSmrg descendant 5364642e01fSmrg P(W) moves from a descendant to W. detail is changed to Inferior, 5374642e01fSmrg subwindow is set to the child containing the previous P(W) 5384642e01fSmrg Case 2C: Otherwise: 5394642e01fSmrg P(W) changes from a window above W to W itself. 5404642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear 5414642e01fSmrg or vice-versa depending on the previous P(W). */ 5424642e01fSmrg 5434202a189Smrg if (!HasPointer(dev, B)) 5444642e01fSmrg { 5454642e01fSmrg WindowPtr child = FirstPointerChild(B); 5464642e01fSmrg if (child) 5474642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None); 5484642e01fSmrg else 5494642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyAncestor, B, None); 5504642e01fSmrg } 5514642e01fSmrg} 5524642e01fSmrg 5534642e01fSmrgstatic void 5544642e01fSmrgCoreEnterLeaveEvents(DeviceIntPtr dev, 5554642e01fSmrg WindowPtr from, 5564642e01fSmrg WindowPtr to, 5574642e01fSmrg int mode) 5584642e01fSmrg{ 5594202a189Smrg if (!IsMaster(dev)) 5604642e01fSmrg return; 5614642e01fSmrg 5624202a189Smrg LeaveWindow(dev); 5634642e01fSmrg 5644642e01fSmrg if (IsParent(from, to)) 5654642e01fSmrg CoreEnterLeaveToDescendant(dev, from, to, mode); 5664642e01fSmrg else if (IsParent(to, from)) 5674642e01fSmrg CoreEnterLeaveToAncestor(dev, from, to, mode); 5684642e01fSmrg else 5694642e01fSmrg CoreEnterLeaveNonLinear(dev, from, to, mode); 5704642e01fSmrg 5714642e01fSmrg EnterWindow(dev, to, mode); 5724642e01fSmrg} 5734642e01fSmrg 5744642e01fSmrgstatic void 5754642e01fSmrgDeviceEnterLeaveEvents(DeviceIntPtr dev, 5764202a189Smrg int sourceid, 5774642e01fSmrg WindowPtr from, 5784642e01fSmrg WindowPtr to, 5794642e01fSmrg int mode) 5804642e01fSmrg{ 5814642e01fSmrg if (IsParent(from, to)) 5824642e01fSmrg { 5834202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyInferior, from, None); 5844202a189Smrg DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 5854202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyAncestor, to, None); 5864642e01fSmrg } 5874642e01fSmrg else if (IsParent(to, from)) 5884642e01fSmrg { 5894202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyAncestor, from, None); 5904202a189Smrg DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 5914202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyInferior, to, None); 5924642e01fSmrg } 5934642e01fSmrg else 5944642e01fSmrg { /* neither from nor to is descendent of the other */ 5954642e01fSmrg WindowPtr common = CommonAncestor(to, from); 5964642e01fSmrg /* common == NullWindow ==> different screens */ 5974202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyNonlinear, from, None); 5984202a189Smrg DeviceLeaveNotifies(dev, sourceid, from, common, mode, NotifyNonlinearVirtual); 5994202a189Smrg DeviceEnterNotifies(dev, sourceid, common, to, mode, NotifyNonlinearVirtual); 6004202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyNonlinear, to, None); 6014642e01fSmrg } 6024642e01fSmrg} 6034642e01fSmrg 6044642e01fSmrg/** 6054642e01fSmrg * Figure out if enter/leave events are necessary and send them to the 6064642e01fSmrg * appropriate windows. 6074642e01fSmrg * 6084642e01fSmrg * @param fromWin Window the sprite moved out of. 6094642e01fSmrg * @param toWin Window the sprite moved into. 6104642e01fSmrg */ 6114642e01fSmrgvoid 6124642e01fSmrgDoEnterLeaveEvents(DeviceIntPtr pDev, 6134202a189Smrg int sourceid, 6144642e01fSmrg WindowPtr fromWin, 6154642e01fSmrg WindowPtr toWin, 6164642e01fSmrg int mode) 6174642e01fSmrg{ 6184642e01fSmrg if (!IsPointerDevice(pDev)) 6194642e01fSmrg return; 6204642e01fSmrg 6214642e01fSmrg if (fromWin == toWin) 6224642e01fSmrg return; 6234642e01fSmrg 6244202a189Smrg if (mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab) 6254202a189Smrg CoreEnterLeaveEvents(pDev, fromWin, toWin, mode); 6264202a189Smrg DeviceEnterLeaveEvents(pDev, sourceid, fromWin, toWin, mode); 6274642e01fSmrg} 6284642e01fSmrg 6294642e01fSmrg/** 6304202a189Smrg * Send focus out events to all windows between 'child' and 'ancestor'. 6314642e01fSmrg * Events are sent running up the hierarchy. 6324642e01fSmrg */ 6334642e01fSmrgstatic void 6344642e01fSmrgDeviceFocusOutEvents(DeviceIntPtr dev, 6354642e01fSmrg WindowPtr child, 6364642e01fSmrg WindowPtr ancestor, 6374642e01fSmrg int mode, 6384642e01fSmrg int detail) 6394642e01fSmrg{ 6404642e01fSmrg WindowPtr win; 6414642e01fSmrg 6424642e01fSmrg if (ancestor == child) 6434642e01fSmrg return; 6444642e01fSmrg for (win = child->parent; win != ancestor; win = win->parent) 6454202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, detail, win); 6464642e01fSmrg} 6474642e01fSmrg 6484642e01fSmrg 6494642e01fSmrg/** 6504202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 6514642e01fSmrg * both). Events are sent running up the window hierarchy. This function 6524642e01fSmrg * recurses. 6534642e01fSmrg */ 6544642e01fSmrgstatic void 6554642e01fSmrgDeviceFocusInEvents(DeviceIntPtr dev, 6564642e01fSmrg WindowPtr ancestor, 6574642e01fSmrg WindowPtr child, 6584642e01fSmrg int mode, 6594642e01fSmrg int detail) 6604642e01fSmrg{ 6614642e01fSmrg WindowPtr parent = child->parent; 6624642e01fSmrg 6634642e01fSmrg if (ancestor == parent || !parent) 6644642e01fSmrg return; 6654642e01fSmrg DeviceFocusInEvents(dev, ancestor, parent, mode, detail); 6664202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, detail, parent); 6674642e01fSmrg} 6684642e01fSmrg 6694642e01fSmrg/** 6704202a189Smrg * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding 6714642e01fSmrg * both). Events are sent running down the window hierarchy. This function 6724642e01fSmrg * recurses. 6734642e01fSmrg */ 6744642e01fSmrgstatic void 6754642e01fSmrgCoreFocusInEvents(DeviceIntPtr dev, 6764642e01fSmrg WindowPtr ancestor, 6774642e01fSmrg WindowPtr child, 6784642e01fSmrg int mode, 6794642e01fSmrg int detail) 6804642e01fSmrg{ 6814642e01fSmrg WindowPtr parent = child->parent; 6824642e01fSmrg if (ancestor == parent) 6834642e01fSmrg return; 6844642e01fSmrg CoreFocusInEvents(dev, ancestor, parent, mode, detail); 6854642e01fSmrg 6864642e01fSmrg 6874642e01fSmrg /* Case 3: 6884642e01fSmrg A is above W, B is a descendant 6894642e01fSmrg 6904642e01fSmrg Classically: The move generates an FocusIn on W with a detail of 6914642e01fSmrg Virtual or NonlinearVirtual 6924642e01fSmrg 6934642e01fSmrg MPX: 6944642e01fSmrg Case 3A: There is at least one other focus on W itself 6954642e01fSmrg F(W) doesn't change, so the event should be suppressed 6964642e01fSmrg Case 3B: Otherwise, if there is at least one other focus in a 6974642e01fSmrg descendant 6984642e01fSmrg F(W) stays on the same descendant, or changes to a different 6994642e01fSmrg descendant. The event should be suppressed. 7004642e01fSmrg Case 3C: Otherwise: 7014642e01fSmrg F(W) moves from a window above W to a descendant. The detail may 7024642e01fSmrg need to be changed from Virtual to NonlinearVirtual depending 7034642e01fSmrg on the previous F(W). */ 7044642e01fSmrg 7054642e01fSmrg if (!HasFocus(parent) && !FirstFocusChild(parent)) 7064642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, detail, parent); 7074642e01fSmrg} 7084642e01fSmrg 7094642e01fSmrgstatic void 7104642e01fSmrgCoreFocusOutEvents(DeviceIntPtr dev, 7114642e01fSmrg WindowPtr child, 7124642e01fSmrg WindowPtr ancestor, 7134642e01fSmrg int mode, 7144642e01fSmrg int detail) 7154642e01fSmrg{ 7164642e01fSmrg WindowPtr win; 7174642e01fSmrg 7184642e01fSmrg if (ancestor == child) 7194642e01fSmrg return; 7204642e01fSmrg 7214642e01fSmrg for (win = child->parent; win != ancestor; win = win->parent) 7224642e01fSmrg { 7234642e01fSmrg /*Case 7: 7244642e01fSmrg A is a descendant of W, B is above W 7254642e01fSmrg 7264642e01fSmrg Classically: A FocusOut is generated on W with a detail of Virtual 7274642e01fSmrg or NonlinearVirtual. 7284642e01fSmrg 7294642e01fSmrg MPX: 7304642e01fSmrg Case 3A: There is at least one other focus on W itself 7314642e01fSmrg F(W) doesn't change, the event should be suppressed. 7324642e01fSmrg Case 3B: Otherwise, if there is at least one other focus in a 7334642e01fSmrg descendant 7344642e01fSmrg F(W) stays on the same descendant, or changes to a different 7354642e01fSmrg descendant. The event should be suppressed. 7364642e01fSmrg Case 3C: Otherwise: 7374642e01fSmrg F(W) changes from the descendant of W to a window above W. 7384642e01fSmrg The detail may need to be changed from Virtual to NonlinearVirtual 7394642e01fSmrg or vice-versa depending on the new P(W).*/ 7404642e01fSmrg 7414642e01fSmrg /* If one window has a focus or a child with a focuspointer, skip some 7424642e01fSmrg * work and exit. */ 7434642e01fSmrg if (HasFocus(win) || FirstFocusChild(win)) 7444642e01fSmrg return; 7454642e01fSmrg 7464642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, detail, win); 7474642e01fSmrg } 7484642e01fSmrg} 7494642e01fSmrg 7504642e01fSmrg/** 7514642e01fSmrg * Send FocusOut(NotifyPointer) events from the current pointer window (which 7524202a189Smrg * is a descendant of pwin_parent) up to (excluding) pwin_parent. 7534642e01fSmrg * 7544202a189Smrg * NotifyPointer events are only sent for the device paired with dev. 7554642e01fSmrg * 7564202a189Smrg * If the current pointer window is a descendant of 'exclude' or an ancestor of 7574202a189Smrg * 'exclude', no events are sent. If the current pointer IS 'exclude', events 7584202a189Smrg * are sent! 7594642e01fSmrg */ 7604642e01fSmrgstatic void 7614642e01fSmrgCoreFocusOutNotifyPointerEvents(DeviceIntPtr dev, 7624642e01fSmrg WindowPtr pwin_parent, 7634642e01fSmrg WindowPtr exclude, 7644642e01fSmrg int mode, 7654642e01fSmrg int inclusive) 7664642e01fSmrg{ 7674642e01fSmrg WindowPtr P, stopAt; 7684642e01fSmrg 7694642e01fSmrg P = PointerWin(GetPairedDevice(dev)); 7704642e01fSmrg 7714642e01fSmrg if (!P) 7724642e01fSmrg return; 7734642e01fSmrg if (!IsParent(pwin_parent, P)) 7744642e01fSmrg if (!(pwin_parent == P && inclusive)) 7754642e01fSmrg return; 7764642e01fSmrg 7774642e01fSmrg if (exclude != None && exclude != PointerRootWin && 7784642e01fSmrg (IsParent(exclude, P) || IsParent(P, exclude))) 7794642e01fSmrg return; 7804642e01fSmrg 7814642e01fSmrg stopAt = (inclusive) ? pwin_parent->parent : pwin_parent; 7824642e01fSmrg 7834642e01fSmrg for (; P && P != stopAt; P = P->parent) 7844642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyPointer, P); 7854642e01fSmrg} 7864642e01fSmrg 7874642e01fSmrg/** 7884642e01fSmrg * DO NOT CALL DIRECTLY. 7894642e01fSmrg * Recursion helper for CoreFocusInNotifyPointerEvents. 7904642e01fSmrg */ 7914642e01fSmrgstatic void 7924642e01fSmrgCoreFocusInRecurse(DeviceIntPtr dev, 7934642e01fSmrg WindowPtr win, 7944642e01fSmrg WindowPtr stopAt, 7954642e01fSmrg int mode, 7964642e01fSmrg int inclusive) 7974642e01fSmrg{ 7984642e01fSmrg if ((!inclusive && win == stopAt) || !win) 7994642e01fSmrg return; 8004642e01fSmrg 8014642e01fSmrg CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive); 8024642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyPointer, win); 8034642e01fSmrg} 8044642e01fSmrg 8054642e01fSmrg 8064642e01fSmrg/** 8074202a189Smrg * Send FocusIn(NotifyPointer) events from pwin_parent down to 8084202a189Smrg * including the current pointer window (which is a descendant of pwin_parent). 8094642e01fSmrg * 8104202a189Smrg * @param pwin The pointer window. 8114202a189Smrg * @param exclude If the pointer window is a child of 'exclude', no events are 8124202a189Smrg * sent. 8134202a189Smrg * @param inclusive If TRUE, pwin_parent will receive the event too. 8144642e01fSmrg */ 8154642e01fSmrgstatic void 8164642e01fSmrgCoreFocusInNotifyPointerEvents(DeviceIntPtr dev, 8174642e01fSmrg WindowPtr pwin_parent, 8184642e01fSmrg WindowPtr exclude, 8194642e01fSmrg int mode, 8204642e01fSmrg int inclusive) 8214642e01fSmrg{ 8224642e01fSmrg WindowPtr P; 8234642e01fSmrg 8244642e01fSmrg P = PointerWin(GetPairedDevice(dev)); 8254642e01fSmrg 8264642e01fSmrg if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P))) 8274642e01fSmrg return; 8284642e01fSmrg 8294642e01fSmrg if (exclude != None && (IsParent(exclude, P) || IsParent(P, exclude))) 8304642e01fSmrg return; 8314642e01fSmrg 8324642e01fSmrg CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive); 8334642e01fSmrg} 8344642e01fSmrg 8354642e01fSmrg 8364642e01fSmrg/** 8374202a189Smrg * Focus of dev moves from A to B and A neither a descendant of B nor is 8384202a189Smrg * B a descendant of A. 8394642e01fSmrg */ 8404642e01fSmrgstatic void 8414642e01fSmrgCoreFocusNonLinear(DeviceIntPtr dev, 8424642e01fSmrg WindowPtr A, 8434642e01fSmrg WindowPtr B, 8444642e01fSmrg int mode) 8454642e01fSmrg{ 8464642e01fSmrg WindowPtr X = CommonAncestor(A, B); 8474642e01fSmrg 8484642e01fSmrg /* Case 4: 8494642e01fSmrg A is W, B is above W 8504642e01fSmrg 8514642e01fSmrg Classically: The change generates a FocusOut on W with a detail of 8524642e01fSmrg Ancestor or Nonlinear 8534642e01fSmrg 8544642e01fSmrg MPX: 8554642e01fSmrg Case 3A: There is at least one other focus on W itself 8564642e01fSmrg F(W) doesn't change, the event should be suppressed 8574642e01fSmrg Case 3B: Otherwise, if there is at least one other focus in a 8584642e01fSmrg descendant of W 8594642e01fSmrg F(W) changes from W to a descendant of W. The detail field 8604642e01fSmrg is set to Inferior 8614642e01fSmrg Case 3C: Otherwise: 8624642e01fSmrg The focus window moves from W to a window above W. 8634642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear or 8644642e01fSmrg vice versa depending on the the new F(W) 8654642e01fSmrg */ 8664642e01fSmrg 8674642e01fSmrg if (!HasFocus(A)) 8684642e01fSmrg { 8694642e01fSmrg WindowPtr child = FirstFocusChild(A); 8704642e01fSmrg if (child) 8714642e01fSmrg { 8724642e01fSmrg /* NotifyPointer P-A unless P is child or below*/ 8734642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 8744642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 8754642e01fSmrg } else 8764642e01fSmrg { 8774642e01fSmrg /* NotifyPointer P-A */ 8784642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 8794642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 8804642e01fSmrg } 8814642e01fSmrg } 8824642e01fSmrg 8834642e01fSmrg 8844642e01fSmrg CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual); 8854642e01fSmrg 8864642e01fSmrg /* 8874642e01fSmrg Case 9: 8884642e01fSmrg A is a descendant of W, B is a descendant of W 8894642e01fSmrg 8904642e01fSmrg Classically: No events are generated on W 8914642e01fSmrg MPX: The focus window stays the same or moves to a different 8924642e01fSmrg descendant of W. No events should be generated on W. 8934642e01fSmrg 8944642e01fSmrg 8954642e01fSmrg Therefore, no event to X. 8964642e01fSmrg */ 8974642e01fSmrg 8984642e01fSmrg CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual); 8994642e01fSmrg 9004642e01fSmrg /* Case 2: 9014642e01fSmrg A is above W, B=W 9024642e01fSmrg 9034642e01fSmrg Classically: The move generates an EnterNotify on W with a detail of 9044642e01fSmrg Ancestor or Nonlinear 9054642e01fSmrg 9064642e01fSmrg MPX: 9074642e01fSmrg Case 2A: There is at least one other focus on W itself 9084642e01fSmrg F(W) doesn't change, so the event should be suppressed 9094642e01fSmrg Case 2B: Otherwise, if there is at least one other focus in a 9104642e01fSmrg descendant 9114642e01fSmrg F(W) moves from a descendant to W. detail is changed to Inferior. 9124642e01fSmrg Case 2C: Otherwise: 9134642e01fSmrg F(W) changes from a window above W to W itself. 9144642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear 9154642e01fSmrg or vice-versa depending on the previous F(W). */ 9164642e01fSmrg 9174642e01fSmrg if (!HasFocus(B)) 9184642e01fSmrg { 9194642e01fSmrg WindowPtr child = FirstFocusChild(B); 9204642e01fSmrg if (child) 9214642e01fSmrg { 9224642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 9234642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 9244642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 9254642e01fSmrg } else { 9264642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 9274642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 9284642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 9294642e01fSmrg } 9304642e01fSmrg } 9314642e01fSmrg} 9324642e01fSmrg 9334642e01fSmrg 9344642e01fSmrg/** 9354202a189Smrg * Focus of dev moves from A to B and A is a descendant of B. 9364642e01fSmrg */ 9374642e01fSmrgstatic void 9384642e01fSmrgCoreFocusToAncestor(DeviceIntPtr dev, 9394642e01fSmrg WindowPtr A, 9404642e01fSmrg WindowPtr B, 9414642e01fSmrg int mode) 9424642e01fSmrg{ 9434642e01fSmrg /* Case 4: 9444642e01fSmrg A is W, B is above W 9454642e01fSmrg 9464642e01fSmrg Classically: The change generates a FocusOut on W with a detail of 9474642e01fSmrg Ancestor or Nonlinear 9484642e01fSmrg 9494642e01fSmrg MPX: 9504642e01fSmrg Case 3A: There is at least one other focus on W itself 9514642e01fSmrg F(W) doesn't change, the event should be suppressed 9524642e01fSmrg Case 3B: Otherwise, if there is at least one other focus in a 9534642e01fSmrg descendant of W 9544642e01fSmrg F(W) changes from W to a descendant of W. The detail field 9554642e01fSmrg is set to Inferior 9564642e01fSmrg Case 3C: Otherwise: 9574642e01fSmrg The focus window moves from W to a window above W. 9584642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear or 9594642e01fSmrg vice versa depending on the the new F(W) 9604642e01fSmrg */ 9614642e01fSmrg if (!HasFocus(A)) 9624642e01fSmrg { 9634642e01fSmrg WindowPtr child = FirstFocusChild(A); 9644642e01fSmrg if (child) 9654642e01fSmrg { 9664642e01fSmrg /* NotifyPointer P-A unless P is child or below*/ 9674642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 9684642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 9694642e01fSmrg } else 9704642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyAncestor, A); 9714642e01fSmrg } 9724642e01fSmrg 9734642e01fSmrg CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual); 9744642e01fSmrg 9754642e01fSmrg /* Case 8: 9764642e01fSmrg A is a descendant of W, B is W 9774642e01fSmrg 9784642e01fSmrg Classically: A FocusOut is generated on W with a detail of 9794642e01fSmrg NotifyInferior 9804642e01fSmrg 9814642e01fSmrg MPX: 9824642e01fSmrg Case 3A: There is at least one other focus on W itself 9834642e01fSmrg F(W) doesn't change, the event should be suppressed 9844642e01fSmrg Case 3B: Otherwise: 9854642e01fSmrg F(W) changes from a descendant to W itself. */ 9864642e01fSmrg 9874642e01fSmrg if (!HasFocus(B)) 9884642e01fSmrg { 9894642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 9904642e01fSmrg /* NotifyPointer B-P unless P is A or below. */ 9914642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE); 9924642e01fSmrg } 9934642e01fSmrg} 9944642e01fSmrg 9954642e01fSmrg/** 9964202a189Smrg * Focus of dev moves from A to B and B is a descendant of A. 9974642e01fSmrg */ 9984642e01fSmrgstatic void 9994642e01fSmrgCoreFocusToDescendant(DeviceIntPtr dev, 10004642e01fSmrg WindowPtr A, 10014642e01fSmrg WindowPtr B, 10024642e01fSmrg int mode) 10034642e01fSmrg{ 10044642e01fSmrg /* Case 6: 10054642e01fSmrg A is W, B is a descendant of W 10064642e01fSmrg 10074642e01fSmrg Classically: A FocusOut is generated on W with a detail of 10084642e01fSmrg NotifyInferior 10094642e01fSmrg 10104642e01fSmrg MPX: 10114642e01fSmrg Case 3A: There is at least one other focus on W itself 10124642e01fSmrg F(W) doesn't change, the event should be suppressed 10134642e01fSmrg Case 3B: Otherwise: 10144642e01fSmrg F(W) changes from W to a descendant of W. */ 10154642e01fSmrg 10164642e01fSmrg if (!HasFocus(A)) 10174642e01fSmrg { 10184642e01fSmrg /* NotifyPointer P-A unless P is B or below*/ 10194642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 10204642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 10214642e01fSmrg } 10224642e01fSmrg 10234642e01fSmrg 10244642e01fSmrg CoreFocusInEvents(dev, A, B, mode, NotifyVirtual); 10254642e01fSmrg 10264642e01fSmrg /* Case 2: 10274642e01fSmrg A is above W, B=W 10284642e01fSmrg 10294642e01fSmrg Classically: The move generates an FocusIn on W with a detail of 10304642e01fSmrg Ancestor or Nonlinear 10314642e01fSmrg 10324642e01fSmrg MPX: 10334642e01fSmrg Case 2A: There is at least one other focus on W itself 10344642e01fSmrg F(W) doesn't change, so the event should be suppressed 10354642e01fSmrg Case 2B: Otherwise, if there is at least one other focus in a 10364642e01fSmrg descendant 10374642e01fSmrg F(W) moves from a descendant to W. detail is changed to Inferior. 10384642e01fSmrg Case 2C: Otherwise: 10394642e01fSmrg F(W) changes from a window above W to W itself. 10404642e01fSmrg The detail may need to be changed from Ancestor to Nonlinear 10414642e01fSmrg or vice-versa depending on the previous F(W). */ 10424642e01fSmrg 10434642e01fSmrg if (!HasFocus(B)) 10444642e01fSmrg { 10454642e01fSmrg WindowPtr child = FirstFocusChild(B); 10464642e01fSmrg if (child) 10474642e01fSmrg { 10484642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 10494642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 10504642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 10514642e01fSmrg } else 10524642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyAncestor, B); 10534642e01fSmrg } 10544642e01fSmrg} 10554642e01fSmrg 10564642e01fSmrgstatic BOOL 10574642e01fSmrgHasOtherPointer(WindowPtr win, DeviceIntPtr exclude) 10584642e01fSmrg{ 10594642e01fSmrg int i; 10604642e01fSmrg 10614642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 10624642e01fSmrg if (i != exclude->id && PointerWindows[i] == win) 10634642e01fSmrg return TRUE; 10644642e01fSmrg 10654642e01fSmrg return FALSE; 10664642e01fSmrg} 10674642e01fSmrg 10684642e01fSmrg/** 10694642e01fSmrg * Focus moves from PointerRoot to None or from None to PointerRoot. 10704642e01fSmrg * Assumption: Neither A nor B are valid windows. 10714642e01fSmrg */ 10724642e01fSmrgstatic void 10734642e01fSmrgCoreFocusPointerRootNoneSwitch(DeviceIntPtr dev, 10744642e01fSmrg WindowPtr A, /* PointerRootWin or NoneWin */ 10754642e01fSmrg WindowPtr B, /* NoneWin or PointerRootWin */ 10764642e01fSmrg int mode) 10774642e01fSmrg{ 10784642e01fSmrg WindowPtr root; 10794642e01fSmrg int i; 10804642e01fSmrg int nscreens = screenInfo.numScreens; 10814642e01fSmrg 10824642e01fSmrg#ifdef PANORAMIX 10834642e01fSmrg if (!noPanoramiXExtension) 10844642e01fSmrg nscreens = 1; 10854642e01fSmrg#endif 10864642e01fSmrg 10874642e01fSmrg for (i = 0; i < nscreens; i++) 10884642e01fSmrg { 10894202a189Smrg root = screenInfo.screens[i]->root; 10904642e01fSmrg if (!HasOtherPointer(root, GetPairedDevice(dev)) && !FirstFocusChild(root)) 10914642e01fSmrg { 10924642e01fSmrg /* If pointer was on PointerRootWin and changes to NoneWin, and 10934202a189Smrg * the pointer paired with dev is below the current root window, 10944642e01fSmrg * do a NotifyPointer run. */ 10954642e01fSmrg if (dev->focus && dev->focus->win == PointerRootWin && 10964642e01fSmrg B != PointerRootWin) 10974642e01fSmrg { 10984642e01fSmrg WindowPtr ptrwin = PointerWin(GetPairedDevice(dev)); 10994642e01fSmrg if (ptrwin && IsParent(root, ptrwin)) 11004642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, root, None, mode, TRUE); 11014642e01fSmrg } 1102eb61724eSmrg CoreFocusEvent(dev, FocusOut, mode, ((unsigned long)A) ? NotifyPointerRoot : NotifyDetailNone, root); 1103eb61724eSmrg CoreFocusEvent(dev, FocusIn, mode, ((unsigned long)B) ? NotifyPointerRoot : NotifyDetailNone, root); 11044642e01fSmrg if (B == PointerRootWin) 11054642e01fSmrg CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 11064642e01fSmrg } 11074642e01fSmrg 11084642e01fSmrg } 11094642e01fSmrg} 11104642e01fSmrg 11114642e01fSmrg/** 11124202a189Smrg * Focus moves from window A to PointerRoot or to None. 11134202a189Smrg * Assumption: A is a valid window and not PointerRoot or None. 11144642e01fSmrg */ 11154642e01fSmrgstatic void 11164642e01fSmrgCoreFocusToPointerRootOrNone(DeviceIntPtr dev, 11174642e01fSmrg WindowPtr A, 11184642e01fSmrg WindowPtr B, /* PointerRootWin or NoneWin */ 11194642e01fSmrg int mode) 11204642e01fSmrg{ 11214642e01fSmrg WindowPtr root; 11224642e01fSmrg int i; 11234642e01fSmrg int nscreens = screenInfo.numScreens; 11244642e01fSmrg 11254642e01fSmrg#ifdef PANORAMIX 11264642e01fSmrg if (!noPanoramiXExtension) 11274642e01fSmrg nscreens = 1; 11284642e01fSmrg#endif 11294642e01fSmrg 11304642e01fSmrg if (!HasFocus(A)) 11314642e01fSmrg { 11324642e01fSmrg WindowPtr child = FirstFocusChild(A); 11334642e01fSmrg if (child) 11344642e01fSmrg { 11354642e01fSmrg /* NotifyPointer P-A unless P is B or below*/ 11364642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 11374642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 11384642e01fSmrg } else { 11394642e01fSmrg /* NotifyPointer P-A */ 11404642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 11414642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 11424642e01fSmrg } 11434642e01fSmrg } 11444642e01fSmrg 11454642e01fSmrg /* NullWindow means we include the root window */ 11464642e01fSmrg CoreFocusOutEvents(dev, A, NullWindow, mode, NotifyNonlinearVirtual); 11474642e01fSmrg 11484642e01fSmrg for (i = 0; i < nscreens; i++) 11494642e01fSmrg { 11504202a189Smrg root = screenInfo.screens[i]->root; 11514642e01fSmrg if (!HasFocus(root) && !FirstFocusChild(root)) 11524642e01fSmrg { 1153eb61724eSmrg CoreFocusEvent(dev, FocusIn, mode, ((unsigned long)B) ? NotifyPointerRoot : NotifyDetailNone, root); 11544642e01fSmrg if (B == PointerRootWin) 11554642e01fSmrg CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 11564642e01fSmrg } 11574642e01fSmrg } 11584642e01fSmrg} 11594642e01fSmrg 11604642e01fSmrg/** 11614202a189Smrg * Focus moves from PointerRoot or None to a window B. 11624202a189Smrg * Assumption: B is a valid window and not PointerRoot or None. 11634642e01fSmrg */ 11644642e01fSmrgstatic void 11654642e01fSmrgCoreFocusFromPointerRootOrNone(DeviceIntPtr dev, 11664642e01fSmrg WindowPtr A, /* PointerRootWin or NoneWin */ 11674642e01fSmrg WindowPtr B, 11684642e01fSmrg int mode) 11694642e01fSmrg{ 11704642e01fSmrg WindowPtr root; 11714642e01fSmrg int i; 11724642e01fSmrg int nscreens = screenInfo.numScreens; 11734642e01fSmrg 11744642e01fSmrg#ifdef PANORAMIX 11754642e01fSmrg if (!noPanoramiXExtension) 11764642e01fSmrg nscreens = 1; 11774642e01fSmrg#endif 11784642e01fSmrg 11794642e01fSmrg for (i = 0; i < nscreens; i++) 11804642e01fSmrg { 11814202a189Smrg root = screenInfo.screens[i]->root; 11824642e01fSmrg if (!HasFocus(root) && !FirstFocusChild(root)) 11834642e01fSmrg { 11844642e01fSmrg /* If pointer was on PointerRootWin and changes to NoneWin, and 11854202a189Smrg * the pointer paired with dev is below the current root window, 11864642e01fSmrg * do a NotifyPointer run. */ 11874642e01fSmrg if (dev->focus && dev->focus->win == PointerRootWin && 11884642e01fSmrg B != PointerRootWin) 11894642e01fSmrg { 11904642e01fSmrg WindowPtr ptrwin = PointerWin(GetPairedDevice(dev)); 11914642e01fSmrg if (ptrwin) 11924642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, root, None, mode, TRUE); 11934642e01fSmrg } 1194eb61724eSmrg CoreFocusEvent(dev, FocusOut, mode, ((unsigned long)A) ? NotifyPointerRoot : NotifyDetailNone, root); 11954642e01fSmrg } 11964642e01fSmrg } 11974642e01fSmrg 11984642e01fSmrg root = B; /* get B's root window */ 11994642e01fSmrg while(root->parent) 12004642e01fSmrg root = root->parent; 12014642e01fSmrg 12024642e01fSmrg if (B != root) 12034642e01fSmrg { 12044642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinearVirtual, root); 12054642e01fSmrg CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual); 12064642e01fSmrg } 12074642e01fSmrg 12084642e01fSmrg 12094642e01fSmrg if (!HasFocus(B)) 12104642e01fSmrg { 12114642e01fSmrg WindowPtr child = FirstFocusChild(B); 12124642e01fSmrg if (child) 12134642e01fSmrg { 12144642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 12154642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 12164642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 12174642e01fSmrg } else { 12184642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 12194642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 12204642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 12214642e01fSmrg } 12224642e01fSmrg } 12234642e01fSmrg 12244642e01fSmrg} 12254642e01fSmrg 12264642e01fSmrgstatic void 12274642e01fSmrgCoreFocusEvents(DeviceIntPtr dev, 12284642e01fSmrg WindowPtr from, 12294642e01fSmrg WindowPtr to, 12304642e01fSmrg int mode) 12314642e01fSmrg{ 12324202a189Smrg if (!IsMaster(dev)) 12334642e01fSmrg return; 12344642e01fSmrg 12354202a189Smrg SetFocusOut(dev); 12364642e01fSmrg 12374642e01fSmrg if (((to == NullWindow) || (to == PointerRootWin)) && 12384642e01fSmrg ((from == NullWindow) || (from == PointerRootWin))) 12394642e01fSmrg CoreFocusPointerRootNoneSwitch(dev, from, to, mode); 12404642e01fSmrg else if ((to == NullWindow) || (to == PointerRootWin)) 12414642e01fSmrg CoreFocusToPointerRootOrNone(dev, from, to, mode); 12424642e01fSmrg else if ((from == NullWindow) || (from == PointerRootWin)) 12434642e01fSmrg CoreFocusFromPointerRootOrNone(dev, from, to, mode); 12444642e01fSmrg else if (IsParent(from, to)) 12454642e01fSmrg CoreFocusToDescendant(dev, from, to, mode); 12464642e01fSmrg else if (IsParent(to, from)) 12474642e01fSmrg CoreFocusToAncestor(dev, from, to, mode); 12484642e01fSmrg else 12494642e01fSmrg CoreFocusNonLinear(dev, from, to, mode); 12504642e01fSmrg 12514642e01fSmrg SetFocusIn(dev, to); 12524642e01fSmrg} 12534642e01fSmrg 12544202a189Smrg/** 12554202a189Smrg * The root window the given device is currently on. 12564202a189Smrg */ 12574642e01fSmrg#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] 12584642e01fSmrg 12594642e01fSmrgstatic void 12604642e01fSmrgDeviceFocusEvents(DeviceIntPtr dev, 12614642e01fSmrg WindowPtr from, 12624642e01fSmrg WindowPtr to, 12634642e01fSmrg int mode) 12644642e01fSmrg{ 12654642e01fSmrg int out, in; /* for holding details for to/from 12664642e01fSmrg PointerRoot/None */ 12674642e01fSmrg int i; 12684642e01fSmrg int nscreens = screenInfo.numScreens; 12694642e01fSmrg SpritePtr sprite = dev->spriteInfo->sprite; 12704642e01fSmrg 12714642e01fSmrg if (from == to) 12724642e01fSmrg return; 12734642e01fSmrg out = (from == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 12744642e01fSmrg in = (to == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 12754642e01fSmrg /* wrong values if neither, but then not referenced */ 12764642e01fSmrg 12774642e01fSmrg#ifdef PANORAMIX 12784642e01fSmrg if (!noPanoramiXExtension) 12794642e01fSmrg nscreens = 1; 12804642e01fSmrg#endif 12814642e01fSmrg 12824642e01fSmrg if ((to == NullWindow) || (to == PointerRootWin)) 12834642e01fSmrg { 12844642e01fSmrg if ((from == NullWindow) || (from == PointerRootWin)) 12854642e01fSmrg { 12864642e01fSmrg if (from == PointerRootWin) 12874642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, RootWindow(dev), mode, 12884642e01fSmrg NotifyPointer); 12894642e01fSmrg /* Notify all the roots */ 12904642e01fSmrg for (i = 0; i < nscreens; i++) 12914202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, out, screenInfo.screens[i]->root); 12924642e01fSmrg } 12934642e01fSmrg else 12944642e01fSmrg { 12954642e01fSmrg if (IsParent(from, sprite->win)) 12964642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 12974642e01fSmrg NotifyPointer); 12984202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 12994642e01fSmrg /* next call catches the root too, if the screen changed */ 13004642e01fSmrg DeviceFocusOutEvents(dev, from->parent, NullWindow, mode, 13014642e01fSmrg NotifyNonlinearVirtual); 13024642e01fSmrg } 13034642e01fSmrg /* Notify all the roots */ 13044642e01fSmrg for (i = 0; i < nscreens; i++) 13054202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, in, screenInfo.screens[i]->root); 13064642e01fSmrg if (to == PointerRootWin) 13074642e01fSmrg DeviceFocusInEvents(dev, RootWindow(dev), sprite->win, mode, NotifyPointer); 13084642e01fSmrg } 13094642e01fSmrg else 13104642e01fSmrg { 13114642e01fSmrg if ((from == NullWindow) || (from == PointerRootWin)) 13124642e01fSmrg { 13134642e01fSmrg if (from == PointerRootWin) 13144642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, RootWindow(dev), mode, 13154642e01fSmrg NotifyPointer); 13164642e01fSmrg for (i = 0; i < nscreens; i++) 13174202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, out, screenInfo.screens[i]->root); 13184642e01fSmrg if (to->parent != NullWindow) 13194642e01fSmrg DeviceFocusInEvents(dev, RootWindow(dev), to, mode, NotifyNonlinearVirtual); 13204202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 13214642e01fSmrg if (IsParent(to, sprite->win)) 13224642e01fSmrg DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer); 13234642e01fSmrg } 13244642e01fSmrg else 13254642e01fSmrg { 13264642e01fSmrg if (IsParent(to, from)) 13274642e01fSmrg { 13284202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyAncestor, from); 13294642e01fSmrg DeviceFocusOutEvents(dev, from->parent, to, mode, 13304642e01fSmrg NotifyVirtual); 13314202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyInferior, to); 13324642e01fSmrg if ((IsParent(to, sprite->win)) && 13334642e01fSmrg (sprite->win != from) && 13344642e01fSmrg (!IsParent(from, sprite->win)) && 13354642e01fSmrg (!IsParent(sprite->win, from))) 13364642e01fSmrg DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer); 13374642e01fSmrg } 13384642e01fSmrg else 13394642e01fSmrg if (IsParent(from, to)) 13404642e01fSmrg { 13414642e01fSmrg if ((IsParent(from, sprite->win)) && 13424642e01fSmrg (sprite->win != from) && 13434642e01fSmrg (!IsParent(to, sprite->win)) && 13444642e01fSmrg (!IsParent(sprite->win, to))) 13454642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 13464642e01fSmrg NotifyPointer); 13474202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyInferior, from); 13484642e01fSmrg DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual); 13494202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyAncestor, to); 13504642e01fSmrg } 13514642e01fSmrg else 13524642e01fSmrg { 13534642e01fSmrg /* neither from or to is child of other */ 13544642e01fSmrg WindowPtr common = CommonAncestor(to, from); 13554642e01fSmrg /* common == NullWindow ==> different screens */ 13564642e01fSmrg if (IsParent(from, sprite->win)) 13574642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 13584642e01fSmrg NotifyPointer); 13594202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 13604642e01fSmrg if (from->parent != NullWindow) 13614642e01fSmrg DeviceFocusOutEvents(dev, from->parent, common, mode, 13624642e01fSmrg NotifyNonlinearVirtual); 13634642e01fSmrg if (to->parent != NullWindow) 13644642e01fSmrg DeviceFocusInEvents(dev, common, to, mode, NotifyNonlinearVirtual); 13654202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 13664642e01fSmrg if (IsParent(to, sprite->win)) 13674642e01fSmrg DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer); 13684642e01fSmrg } 13694642e01fSmrg } 13704642e01fSmrg } 13714642e01fSmrg} 13724642e01fSmrg 13734642e01fSmrg/** 13744642e01fSmrg * Figure out if focus events are necessary and send them to the 13754642e01fSmrg * appropriate windows. 13764642e01fSmrg * 13774642e01fSmrg * @param from Window the focus moved out of. 13784642e01fSmrg * @param to Window the focus moved into. 13794642e01fSmrg */ 13804642e01fSmrgvoid 13814642e01fSmrgDoFocusEvents(DeviceIntPtr pDev, 13824642e01fSmrg WindowPtr from, 13834642e01fSmrg WindowPtr to, 13844642e01fSmrg int mode) 13854642e01fSmrg{ 13864642e01fSmrg if (!IsKeyboardDevice(pDev)) 13874642e01fSmrg return; 13884642e01fSmrg 13894642e01fSmrg if (from == to) 13904642e01fSmrg return; 13914642e01fSmrg 13924642e01fSmrg CoreFocusEvents(pDev, from, to, mode); 13934642e01fSmrg DeviceFocusEvents(pDev, from, to, mode); 13944642e01fSmrg} 1395