enterleave.c revision 5a112b11
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> 33f7df2e56Smrg#include <X11/extensions/XIproto.h> 34f7df2e56Smrg#include <X11/extensions/XI2proto.h> 354202a189Smrg#include "inputstr.h" 364642e01fSmrg#include "windowstr.h" 374642e01fSmrg#include "scrnintstr.h" 384642e01fSmrg#include "exglobals.h" 394642e01fSmrg#include "enterleave.h" 40f7df2e56Smrg#include "eventconvert.h" 41f7df2e56Smrg#include "xkbsrv.h" 42f7df2e56Smrg#include "inpututils.h" 434642e01fSmrg 444202a189Smrg/** 454202a189Smrg * @file 464202a189Smrg * This file describes the model for sending core enter/leave events and 474202a189Smrg * focus in/out in the case of multiple pointers/keyboard foci. 484202a189Smrg * 494642e01fSmrg * Since we can't send more than one Enter or Leave/Focus in or out event per 504642e01fSmrg * window to a core client without confusing it, this is a rather complicated 514642e01fSmrg * approach. 524642e01fSmrg * 534642e01fSmrg * For a full description of the enter/leave model from a window's 544642e01fSmrg * perspective, see 554642e01fSmrg * http://lists.freedesktop.org/archives/xorg/2008-August/037606.html 564642e01fSmrg * 574642e01fSmrg * For a full description of the focus in/out model from a window's 584642e01fSmrg * perspective, see 595a112b11Smrg * https://lists.freedesktop.org/archives/xorg/2008-December/041684.html 604642e01fSmrg * 614642e01fSmrg * Additional notes: 624202a189Smrg * - The core protocol spec says that "In a LeaveNotify event, if a child of the 634642e01fSmrg * event window contains the initial position of the pointer, then the child 644642e01fSmrg * component is set to that child. Otherwise, it is None. For an EnterNotify 654642e01fSmrg * event, if a child of the event window contains the final pointer position, 664642e01fSmrg * then the child component is set to that child. Otherwise, it is None." 674642e01fSmrg * 684642e01fSmrg * By inference, this means that only NotifyVirtual or NotifyNonlinearVirtual 694642e01fSmrg * events may have a subwindow set to other than None. 704642e01fSmrg * 714202a189Smrg * - NotifyPointer events may be sent if the focus changes from window A to 724642e01fSmrg * B. The assumption used in this model is that NotifyPointer events are only 734642e01fSmrg * sent for the pointer paired with the keyboard that is involved in the focus 744642e01fSmrg * events. For example, if F(W) changes because of keyboard 2, then 754642e01fSmrg * NotifyPointer events are only sent for pointer 2. 764642e01fSmrg */ 774642e01fSmrg 784642e01fSmrgstatic WindowPtr PointerWindows[MAXDEVICES]; 794642e01fSmrgstatic WindowPtr FocusWindows[MAXDEVICES]; 804642e01fSmrg 814642e01fSmrg/** 824202a189Smrg * Return TRUE if 'win' has a pointer within its boundaries, excluding child 834642e01fSmrg * window. 844642e01fSmrg */ 854642e01fSmrgstatic BOOL 864202a189SmrgHasPointer(DeviceIntPtr dev, WindowPtr win) 874642e01fSmrg{ 884642e01fSmrg int i; 894642e01fSmrg 904202a189Smrg /* FIXME: The enter/leave model does not cater for grabbed devices. For 914202a189Smrg * now, a quickfix: if the device about to send an enter/leave event to 924202a189Smrg * a window is grabbed, assume there is no pointer in that window. 934202a189Smrg * Fixes fdo 27804. 944202a189Smrg * There isn't enough beer in my fridge to fix this properly. 954202a189Smrg */ 964202a189Smrg if (dev->deviceGrab.grab) 974202a189Smrg return FALSE; 984202a189Smrg 994642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 1004642e01fSmrg if (PointerWindows[i] == win) 1014642e01fSmrg return TRUE; 1024642e01fSmrg 1034642e01fSmrg return FALSE; 1044642e01fSmrg} 1054642e01fSmrg 1064642e01fSmrg/** 1074202a189Smrg * Return TRUE if at least one keyboard focus is set to 'win' (excluding 1084642e01fSmrg * descendants of win). 1094642e01fSmrg */ 1104642e01fSmrgstatic BOOL 1114642e01fSmrgHasFocus(WindowPtr win) 1124642e01fSmrg{ 1134642e01fSmrg int i; 114f7df2e56Smrg 1154642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 1164642e01fSmrg if (FocusWindows[i] == win) 1174642e01fSmrg return TRUE; 1184642e01fSmrg 1194642e01fSmrg return FALSE; 1204642e01fSmrg} 1214642e01fSmrg 1224642e01fSmrg/** 1234202a189Smrg * Return the window the device dev is currently on. 1244642e01fSmrg */ 1254642e01fSmrgstatic WindowPtr 1264642e01fSmrgPointerWin(DeviceIntPtr dev) 1274642e01fSmrg{ 1284642e01fSmrg return PointerWindows[dev->id]; 1294642e01fSmrg} 1304642e01fSmrg 1314642e01fSmrg/** 1324202a189Smrg * Search for the first window below 'win' that has a pointer directly within 1335a112b11Smrg * its boundaries (excluding boundaries of its own descendants). 1344642e01fSmrg * 1354642e01fSmrg * @return The child window that has the pointer within its boundaries or 1364642e01fSmrg * NULL. 1374642e01fSmrg */ 1384642e01fSmrgstatic WindowPtr 1394642e01fSmrgFirstPointerChild(WindowPtr win) 1404642e01fSmrg{ 1414642e01fSmrg int i; 142f7df2e56Smrg 143f7df2e56Smrg for (i = 0; i < MAXDEVICES; i++) { 1444642e01fSmrg if (PointerWindows[i] && IsParent(win, PointerWindows[i])) 1454642e01fSmrg return PointerWindows[i]; 1464642e01fSmrg } 1474642e01fSmrg 1484642e01fSmrg return NULL; 1494642e01fSmrg} 1504642e01fSmrg 1514642e01fSmrg/** 1524202a189Smrg * Search for the first window below 'win' that has a focus directly within 1535a112b11Smrg * its boundaries (excluding boundaries of its own descendants). 1544642e01fSmrg * 1554642e01fSmrg * @return The child window that has the pointer within its boundaries or 1564642e01fSmrg * NULL. 1574642e01fSmrg */ 1584642e01fSmrgstatic WindowPtr 1594642e01fSmrgFirstFocusChild(WindowPtr win) 1604642e01fSmrg{ 1614642e01fSmrg int i; 162f7df2e56Smrg 163f7df2e56Smrg for (i = 0; i < MAXDEVICES; i++) { 1644642e01fSmrg if (FocusWindows[i] && FocusWindows[i] != PointerRootWin && 1654642e01fSmrg IsParent(win, FocusWindows[i])) 1664642e01fSmrg return FocusWindows[i]; 1674642e01fSmrg } 1684642e01fSmrg 1694642e01fSmrg return NULL; 1704642e01fSmrg} 1714642e01fSmrg 1724642e01fSmrg/** 1734202a189Smrg * Set the presence flag for dev to mark that it is now in 'win'. 1744642e01fSmrg */ 1754642e01fSmrgvoid 1764642e01fSmrgEnterWindow(DeviceIntPtr dev, WindowPtr win, int mode) 1774642e01fSmrg{ 1784642e01fSmrg PointerWindows[dev->id] = win; 1794642e01fSmrg} 1804642e01fSmrg 1814642e01fSmrg/** 1824202a189Smrg * Unset the presence flag for dev to mark that it is not in 'win' anymore. 1834642e01fSmrg */ 1844202a189Smrgvoid 1854202a189SmrgLeaveWindow(DeviceIntPtr dev) 1864642e01fSmrg{ 1874642e01fSmrg PointerWindows[dev->id] = NULL; 1884642e01fSmrg} 1894642e01fSmrg 1904642e01fSmrg/** 1914202a189Smrg * Set the presence flag for dev to mark that it is now in 'win'. 1924642e01fSmrg */ 1934642e01fSmrgvoid 1944642e01fSmrgSetFocusIn(DeviceIntPtr dev, WindowPtr win) 1954642e01fSmrg{ 1964642e01fSmrg FocusWindows[dev->id] = win; 1974642e01fSmrg} 1984642e01fSmrg 1994642e01fSmrg/** 2004202a189Smrg * Unset the presence flag for dev to mark that it is not in 'win' anymore. 2014642e01fSmrg */ 2024642e01fSmrgvoid 2034202a189SmrgSetFocusOut(DeviceIntPtr dev) 2044642e01fSmrg{ 2054642e01fSmrg FocusWindows[dev->id] = NULL; 2064642e01fSmrg} 2074642e01fSmrg 2084642e01fSmrg/** 2094202a189Smrg * Return the common ancestor of 'a' and 'b' (if one exists). 2104202a189Smrg * @param a A window with the same ancestor as b. 2114202a189Smrg * @param b A window with the same ancestor as a. 2124202a189Smrg * @return The window that is the first ancestor of both 'a' and 'b', or the 2134202a189Smrg * NullWindow if they do not have a common ancestor. 2144642e01fSmrg */ 215f7df2e56Smrgstatic WindowPtr 216f7df2e56SmrgCommonAncestor(WindowPtr a, WindowPtr b) 2174642e01fSmrg{ 2184642e01fSmrg for (b = b->parent; b; b = b->parent) 219f7df2e56Smrg if (IsParent(b, a)) 220f7df2e56Smrg return b; 2214642e01fSmrg return NullWindow; 2224642e01fSmrg} 2234642e01fSmrg 2244642e01fSmrg/** 2254202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 2264642e01fSmrg * both). Events are sent running up the window hierarchy. This function 2274642e01fSmrg * recurses. 2284642e01fSmrg */ 2294642e01fSmrgstatic void 2304642e01fSmrgDeviceEnterNotifies(DeviceIntPtr dev, 231f7df2e56Smrg int sourceid, 232f7df2e56Smrg WindowPtr ancestor, WindowPtr child, int mode, int detail) 2334642e01fSmrg{ 234f7df2e56Smrg WindowPtr parent = child->parent; 2354642e01fSmrg 2364642e01fSmrg if (ancestor == parent) 237f7df2e56Smrg return; 2384202a189Smrg DeviceEnterNotifies(dev, sourceid, ancestor, parent, mode, detail); 2394202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, detail, parent, 2404642e01fSmrg child->drawable.id); 2414642e01fSmrg} 2424642e01fSmrg 2434642e01fSmrg/** 2444202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 2454642e01fSmrg * both). Events are sent running down the window hierarchy. This function 2464642e01fSmrg * recurses. 2474642e01fSmrg */ 2484642e01fSmrgstatic void 2494642e01fSmrgCoreEnterNotifies(DeviceIntPtr dev, 250f7df2e56Smrg WindowPtr ancestor, WindowPtr child, int mode, int detail) 2514642e01fSmrg{ 252f7df2e56Smrg WindowPtr parent = child->parent; 253f7df2e56Smrg 2544642e01fSmrg if (ancestor == parent) 255f7df2e56Smrg return; 2564642e01fSmrg CoreEnterNotifies(dev, ancestor, parent, mode, detail); 2574642e01fSmrg 2584642e01fSmrg /* Case 3: 259f7df2e56Smrg A is above W, B is a descendant 260f7df2e56Smrg 261f7df2e56Smrg Classically: The move generates an EnterNotify on W with a detail of 262f7df2e56Smrg Virtual or NonlinearVirtual 263f7df2e56Smrg 264f7df2e56Smrg MPX: 265f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 266f7df2e56Smrg P(W) doesn't change, so the event should be suppressed 267f7df2e56Smrg Case 3B: Otherwise, if there is at least one other pointer in a 268f7df2e56Smrg descendant 269f7df2e56Smrg P(W) stays on the same descendant, or changes to a different 270f7df2e56Smrg descendant. The event should be suppressed. 271f7df2e56Smrg Case 3C: Otherwise: 272f7df2e56Smrg P(W) moves from a window above W to a descendant. The subwindow 273f7df2e56Smrg field is set to the child containing the descendant. The detail 274f7df2e56Smrg may need to be changed from Virtual to NonlinearVirtual depending 275f7df2e56Smrg on the previous P(W). */ 2764642e01fSmrg 2774202a189Smrg if (!HasPointer(dev, parent) && !FirstPointerChild(parent)) 278f7df2e56Smrg CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent, 279f7df2e56Smrg child->drawable.id); 2804642e01fSmrg} 2814642e01fSmrg 2824642e01fSmrgstatic void 2834642e01fSmrgCoreLeaveNotifies(DeviceIntPtr dev, 284f7df2e56Smrg WindowPtr child, WindowPtr ancestor, int mode, int detail) 2854642e01fSmrg{ 286f7df2e56Smrg WindowPtr win; 2874642e01fSmrg 2884642e01fSmrg if (ancestor == child) 2894642e01fSmrg return; 2904642e01fSmrg 291f7df2e56Smrg for (win = child->parent; win != ancestor; win = win->parent) { 2924642e01fSmrg /*Case 7: 293f7df2e56Smrg A is a descendant of W, B is above W 294f7df2e56Smrg 295f7df2e56Smrg Classically: A LeaveNotify is generated on W with a detail of Virtual 296f7df2e56Smrg or NonlinearVirtual. 297f7df2e56Smrg 298f7df2e56Smrg MPX: 299f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 300f7df2e56Smrg P(W) doesn't change, the event should be suppressed. 301f7df2e56Smrg Case 3B: Otherwise, if there is at least one other pointer in a 302f7df2e56Smrg descendant 303f7df2e56Smrg P(W) stays on the same descendant, or changes to a different 304f7df2e56Smrg descendant. The event should be suppressed. 305f7df2e56Smrg Case 3C: Otherwise: 306f7df2e56Smrg P(W) changes from the descendant of W to a window above W. 307f7df2e56Smrg The detail may need to be changed from Virtual to NonlinearVirtual 308f7df2e56Smrg or vice-versa depending on the new P(W). */ 3094642e01fSmrg 3104642e01fSmrg /* If one window has a pointer or a child with a pointer, skip some 3114642e01fSmrg * work and exit. */ 3124202a189Smrg if (HasPointer(dev, win) || FirstPointerChild(win)) 3134642e01fSmrg return; 3144642e01fSmrg 315f7df2e56Smrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win, 316f7df2e56Smrg child->drawable.id); 3174642e01fSmrg 3184642e01fSmrg child = win; 3194642e01fSmrg } 3204642e01fSmrg} 3214642e01fSmrg 3224642e01fSmrg/** 3234202a189Smrg * Send leave notifies to all windows between 'child' and 'ancestor'. 3244642e01fSmrg * Events are sent running up the hierarchy. 3254642e01fSmrg */ 3264642e01fSmrgstatic void 3274642e01fSmrgDeviceLeaveNotifies(DeviceIntPtr dev, 328f7df2e56Smrg int sourceid, 329f7df2e56Smrg WindowPtr child, WindowPtr ancestor, int mode, int detail) 3304642e01fSmrg{ 331f7df2e56Smrg WindowPtr win; 3324642e01fSmrg 3334642e01fSmrg if (ancestor == child) 334f7df2e56Smrg return; 335f7df2e56Smrg for (win = child->parent; win != ancestor; win = win->parent) { 3364202a189Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, detail, win, 337f7df2e56Smrg child->drawable.id); 3384642e01fSmrg child = win; 3394642e01fSmrg } 3404642e01fSmrg} 3414642e01fSmrg 3424642e01fSmrg/** 3434202a189Smrg * Pointer dev moves from A to B and A neither a descendant of B nor is 3444202a189Smrg * B a descendant of A. 3454642e01fSmrg */ 3464642e01fSmrgstatic void 347f7df2e56SmrgCoreEnterLeaveNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 3484642e01fSmrg{ 3494642e01fSmrg WindowPtr X = CommonAncestor(A, B); 350f7df2e56Smrg 3514642e01fSmrg /* Case 4: 352f7df2e56Smrg A is W, B is above W 3534642e01fSmrg 354f7df2e56Smrg Classically: The move generates a LeaveNotify on W with a detail of 3554642e01fSmrg Ancestor or Nonlinear 3564642e01fSmrg 357f7df2e56Smrg MPX: 358f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 359f7df2e56Smrg P(W) doesn't change, the event should be suppressed 360f7df2e56Smrg Case 3B: Otherwise, if there is at least one other pointer in a 361f7df2e56Smrg descendant of W 362f7df2e56Smrg P(W) changes from W to a descendant of W. The subwindow field 363f7df2e56Smrg is set to the child containing the new P(W), the detail field 364f7df2e56Smrg is set to Inferior 365f7df2e56Smrg Case 3C: Otherwise: 366f7df2e56Smrg The pointer window moves from W to a window above W. 367f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear or 368f7df2e56Smrg vice versa depending on the the new P(W) 3694642e01fSmrg */ 3704642e01fSmrg 371f7df2e56Smrg if (!HasPointer(dev, A)) { 3724642e01fSmrg WindowPtr child = FirstPointerChild(A); 373f7df2e56Smrg 3744642e01fSmrg if (child) 375f7df2e56Smrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, 376f7df2e56Smrg None); 3774642e01fSmrg else 378f7df2e56Smrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyNonlinear, A, 379f7df2e56Smrg None); 3804642e01fSmrg } 3814642e01fSmrg 3824642e01fSmrg CoreLeaveNotifies(dev, A, X, mode, NotifyNonlinearVirtual); 3834642e01fSmrg 3844642e01fSmrg /* 385f7df2e56Smrg Case 9: 386f7df2e56Smrg A is a descendant of W, B is a descendant of W 3874642e01fSmrg 388f7df2e56Smrg Classically: No events are generated on W 389f7df2e56Smrg MPX: The pointer window stays the same or moves to a different 390f7df2e56Smrg descendant of W. No events should be generated on W. 3914642e01fSmrg 3924642e01fSmrg Therefore, no event to X. 393f7df2e56Smrg */ 3944642e01fSmrg 3954642e01fSmrg CoreEnterNotifies(dev, X, B, mode, NotifyNonlinearVirtual); 3964642e01fSmrg 3974642e01fSmrg /* Case 2: 398f7df2e56Smrg A is above W, B=W 399f7df2e56Smrg 400f7df2e56Smrg Classically: The move generates an EnterNotify on W with a detail of 401f7df2e56Smrg Ancestor or Nonlinear 402f7df2e56Smrg 403f7df2e56Smrg MPX: 404f7df2e56Smrg Case 2A: There is at least one other pointer on W itself 405f7df2e56Smrg P(W) doesn't change, so the event should be suppressed 406f7df2e56Smrg Case 2B: Otherwise, if there is at least one other pointer in a 407f7df2e56Smrg descendant 408f7df2e56Smrg P(W) moves from a descendant to W. detail is changed to Inferior, 409f7df2e56Smrg subwindow is set to the child containing the previous P(W) 410f7df2e56Smrg Case 2C: Otherwise: 411f7df2e56Smrg P(W) changes from a window above W to W itself. 412f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear 413f7df2e56Smrg or vice-versa depending on the previous P(W). */ 414f7df2e56Smrg 415f7df2e56Smrg if (!HasPointer(dev, B)) { 416f7df2e56Smrg WindowPtr child = FirstPointerChild(B); 417f7df2e56Smrg 418f7df2e56Smrg if (child) 419f7df2e56Smrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, 420f7df2e56Smrg None); 421f7df2e56Smrg else 422f7df2e56Smrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyNonlinear, B, 423f7df2e56Smrg None); 424f7df2e56Smrg } 4254642e01fSmrg} 4264642e01fSmrg 4274642e01fSmrg/** 4284202a189Smrg * Pointer dev moves from A to B and A is a descendant of B. 4294642e01fSmrg */ 4304642e01fSmrgstatic void 431f7df2e56SmrgCoreEnterLeaveToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 4324642e01fSmrg{ 4334642e01fSmrg /* Case 4: 434f7df2e56Smrg A is W, B is above W 4354642e01fSmrg 436f7df2e56Smrg Classically: The move generates a LeaveNotify on W with a detail of 4374642e01fSmrg Ancestor or Nonlinear 4384642e01fSmrg 439f7df2e56Smrg MPX: 440f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 441f7df2e56Smrg P(W) doesn't change, the event should be suppressed 442f7df2e56Smrg Case 3B: Otherwise, if there is at least one other pointer in a 443f7df2e56Smrg descendant of W 444f7df2e56Smrg P(W) changes from W to a descendant of W. The subwindow field 445f7df2e56Smrg is set to the child containing the new P(W), the detail field 446f7df2e56Smrg is set to Inferior 447f7df2e56Smrg Case 3C: Otherwise: 448f7df2e56Smrg The pointer window moves from W to a window above W. 449f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear or 450f7df2e56Smrg vice versa depending on the the new P(W) 4514642e01fSmrg */ 452f7df2e56Smrg if (!HasPointer(dev, A)) { 4534642e01fSmrg WindowPtr child = FirstPointerChild(A); 454f7df2e56Smrg 4554642e01fSmrg if (child) 456f7df2e56Smrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, 457f7df2e56Smrg None); 4584642e01fSmrg else 459f7df2e56Smrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyAncestor, A, 460f7df2e56Smrg None); 4614642e01fSmrg } 4624642e01fSmrg 4634642e01fSmrg CoreLeaveNotifies(dev, A, B, mode, NotifyVirtual); 4644642e01fSmrg 4654642e01fSmrg /* Case 8: 466f7df2e56Smrg A is a descendant of W, B is W 4674642e01fSmrg 468f7df2e56Smrg Classically: A EnterNotify is generated on W with a detail of 469f7df2e56Smrg NotifyInferior 4704642e01fSmrg 471f7df2e56Smrg MPX: 472f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 473f7df2e56Smrg P(W) doesn't change, the event should be suppressed 474f7df2e56Smrg Case 3B: Otherwise: 475f7df2e56Smrg P(W) changes from a descendant to W itself. The subwindow 476f7df2e56Smrg field should be set to the child containing the old P(W) <<< WRONG */ 4774642e01fSmrg 4784202a189Smrg if (!HasPointer(dev, B)) 4794642e01fSmrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, None); 4804642e01fSmrg 4814642e01fSmrg} 4824642e01fSmrg 4834642e01fSmrg/** 4844202a189Smrg * Pointer dev moves from A to B and B is a descendant of A. 4854642e01fSmrg */ 4864642e01fSmrgstatic void 487f7df2e56SmrgCoreEnterLeaveToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 4884642e01fSmrg{ 4894642e01fSmrg /* Case 6: 490f7df2e56Smrg A is W, B is a descendant of W 4914642e01fSmrg 492f7df2e56Smrg Classically: A LeaveNotify is generated on W with a detail of 4934642e01fSmrg NotifyInferior 4944642e01fSmrg 495f7df2e56Smrg MPX: 496f7df2e56Smrg Case 3A: There is at least one other pointer on W itself 497f7df2e56Smrg P(W) doesn't change, the event should be suppressed 498f7df2e56Smrg Case 3B: Otherwise: 499f7df2e56Smrg P(W) changes from W to a descendant of W. The subwindow field 500f7df2e56Smrg is set to the child containing the new P(W) <<< THIS IS WRONG */ 5014642e01fSmrg 5024202a189Smrg if (!HasPointer(dev, A)) 5034642e01fSmrg CoreEnterLeaveEvent(dev, LeaveNotify, mode, NotifyInferior, A, None); 5044642e01fSmrg 5054642e01fSmrg CoreEnterNotifies(dev, A, B, mode, NotifyVirtual); 5064642e01fSmrg 5074642e01fSmrg /* Case 2: 508f7df2e56Smrg A is above W, B=W 509f7df2e56Smrg 510f7df2e56Smrg Classically: The move generates an EnterNotify on W with a detail of 511f7df2e56Smrg Ancestor or Nonlinear 512f7df2e56Smrg 513f7df2e56Smrg MPX: 514f7df2e56Smrg Case 2A: There is at least one other pointer on W itself 515f7df2e56Smrg P(W) doesn't change, so the event should be suppressed 516f7df2e56Smrg Case 2B: Otherwise, if there is at least one other pointer in a 517f7df2e56Smrg descendant 518f7df2e56Smrg P(W) moves from a descendant to W. detail is changed to Inferior, 519f7df2e56Smrg subwindow is set to the child containing the previous P(W) 520f7df2e56Smrg Case 2C: Otherwise: 521f7df2e56Smrg P(W) changes from a window above W to W itself. 522f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear 523f7df2e56Smrg or vice-versa depending on the previous P(W). */ 524f7df2e56Smrg 525f7df2e56Smrg if (!HasPointer(dev, B)) { 526f7df2e56Smrg WindowPtr child = FirstPointerChild(B); 527f7df2e56Smrg 528f7df2e56Smrg if (child) 529f7df2e56Smrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyInferior, B, 530f7df2e56Smrg None); 531f7df2e56Smrg else 532f7df2e56Smrg CoreEnterLeaveEvent(dev, EnterNotify, mode, NotifyAncestor, B, 533f7df2e56Smrg None); 534f7df2e56Smrg } 5354642e01fSmrg} 5364642e01fSmrg 5374642e01fSmrgstatic void 538f7df2e56SmrgCoreEnterLeaveEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 5394642e01fSmrg{ 5404202a189Smrg if (!IsMaster(dev)) 5414642e01fSmrg return; 5424642e01fSmrg 5434202a189Smrg LeaveWindow(dev); 5444642e01fSmrg 5454642e01fSmrg if (IsParent(from, to)) 5464642e01fSmrg CoreEnterLeaveToDescendant(dev, from, to, mode); 5474642e01fSmrg else if (IsParent(to, from)) 5484642e01fSmrg CoreEnterLeaveToAncestor(dev, from, to, mode); 5494642e01fSmrg else 5504642e01fSmrg CoreEnterLeaveNonLinear(dev, from, to, mode); 5514642e01fSmrg 5524642e01fSmrg EnterWindow(dev, to, mode); 5534642e01fSmrg} 5544642e01fSmrg 5554642e01fSmrgstatic void 5564642e01fSmrgDeviceEnterLeaveEvents(DeviceIntPtr dev, 557f7df2e56Smrg int sourceid, WindowPtr from, WindowPtr to, int mode) 5584642e01fSmrg{ 559f7df2e56Smrg if (IsParent(from, to)) { 560f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyInferior, 561f7df2e56Smrg from, None); 5624202a189Smrg DeviceEnterNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 563f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyAncestor, to, 564f7df2e56Smrg None); 5654642e01fSmrg } 566f7df2e56Smrg else if (IsParent(to, from)) { 567f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyAncestor, 568f7df2e56Smrg from, None); 569f7df2e56Smrg DeviceLeaveNotifies(dev, sourceid, from, to, mode, NotifyVirtual); 570f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyInferior, to, 571f7df2e56Smrg None); 5724642e01fSmrg } 573f7df2e56Smrg else { /* neither from nor to is descendent of the other */ 574f7df2e56Smrg WindowPtr common = CommonAncestor(to, from); 575f7df2e56Smrg 576f7df2e56Smrg /* common == NullWindow ==> different screens */ 577f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Leave, mode, NotifyNonlinear, 578f7df2e56Smrg from, None); 579f7df2e56Smrg DeviceLeaveNotifies(dev, sourceid, from, common, mode, 580f7df2e56Smrg NotifyNonlinearVirtual); 581f7df2e56Smrg DeviceEnterNotifies(dev, sourceid, common, to, mode, 582f7df2e56Smrg NotifyNonlinearVirtual); 583f7df2e56Smrg DeviceEnterLeaveEvent(dev, sourceid, XI_Enter, mode, NotifyNonlinear, 584f7df2e56Smrg to, None); 5854642e01fSmrg } 5864642e01fSmrg} 5874642e01fSmrg 5884642e01fSmrg/** 5894642e01fSmrg * Figure out if enter/leave events are necessary and send them to the 5904642e01fSmrg * appropriate windows. 5914642e01fSmrg * 5924642e01fSmrg * @param fromWin Window the sprite moved out of. 5934642e01fSmrg * @param toWin Window the sprite moved into. 5944642e01fSmrg */ 5954642e01fSmrgvoid 5964642e01fSmrgDoEnterLeaveEvents(DeviceIntPtr pDev, 597f7df2e56Smrg int sourceid, WindowPtr fromWin, WindowPtr toWin, int mode) 5984642e01fSmrg{ 5994642e01fSmrg if (!IsPointerDevice(pDev)) 6004642e01fSmrg return; 6014642e01fSmrg 6024642e01fSmrg if (fromWin == toWin) 603f7df2e56Smrg return; 6044642e01fSmrg 6054202a189Smrg if (mode != XINotifyPassiveGrab && mode != XINotifyPassiveUngrab) 6064202a189Smrg CoreEnterLeaveEvents(pDev, fromWin, toWin, mode); 6074202a189Smrg DeviceEnterLeaveEvents(pDev, sourceid, fromWin, toWin, mode); 6084642e01fSmrg} 6094642e01fSmrg 610f7df2e56Smrgstatic void 611f7df2e56SmrgFixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, 612f7df2e56Smrg int first) 613f7df2e56Smrg{ 614f7df2e56Smrg int nval = v->numAxes - first; 615f7df2e56Smrg 616f7df2e56Smrg ev->type = DeviceValuator; 617f7df2e56Smrg ev->deviceid = dev->id; 618f7df2e56Smrg ev->num_valuators = nval < 3 ? nval : 3; 619f7df2e56Smrg ev->first_valuator = first; 620f7df2e56Smrg switch (ev->num_valuators) { 621f7df2e56Smrg case 3: 622f7df2e56Smrg ev->valuator2 = v->axisVal[first + 2]; 623f7df2e56Smrg case 2: 624f7df2e56Smrg ev->valuator1 = v->axisVal[first + 1]; 625f7df2e56Smrg case 1: 626f7df2e56Smrg ev->valuator0 = v->axisVal[first]; 627f7df2e56Smrg break; 628f7df2e56Smrg } 629f7df2e56Smrg first += ev->num_valuators; 630f7df2e56Smrg} 631f7df2e56Smrg 632f7df2e56Smrgstatic void 633f7df2e56SmrgFixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, 634f7df2e56Smrg ButtonClassPtr b, ValuatorClassPtr v, int first) 635f7df2e56Smrg{ 636f7df2e56Smrg ev->type = DeviceStateNotify; 637f7df2e56Smrg ev->deviceid = dev->id; 638f7df2e56Smrg ev->time = currentTime.milliseconds; 639f7df2e56Smrg ev->classes_reported = 0; 640f7df2e56Smrg ev->num_keys = 0; 641f7df2e56Smrg ev->num_buttons = 0; 642f7df2e56Smrg ev->num_valuators = 0; 643f7df2e56Smrg 644f7df2e56Smrg if (b) { 645f7df2e56Smrg ev->classes_reported |= (1 << ButtonClass); 646f7df2e56Smrg ev->num_buttons = b->numButtons; 647f7df2e56Smrg memcpy((char *) ev->buttons, (char *) b->down, 4); 648f7df2e56Smrg } 649f7df2e56Smrg else if (k) { 650f7df2e56Smrg ev->classes_reported |= (1 << KeyClass); 651f7df2e56Smrg ev->num_keys = k->xkbInfo->desc->max_key_code - 652f7df2e56Smrg k->xkbInfo->desc->min_key_code; 653f7df2e56Smrg memmove((char *) &ev->keys[0], (char *) k->down, 4); 654f7df2e56Smrg } 655f7df2e56Smrg if (v) { 656f7df2e56Smrg int nval = v->numAxes - first; 657f7df2e56Smrg 658f7df2e56Smrg ev->classes_reported |= (1 << ValuatorClass); 659f7df2e56Smrg ev->classes_reported |= valuator_get_mode(dev, 0) << ModeBitsShift; 660f7df2e56Smrg ev->num_valuators = nval < 3 ? nval : 3; 661f7df2e56Smrg switch (ev->num_valuators) { 662f7df2e56Smrg case 3: 663f7df2e56Smrg ev->valuator2 = v->axisVal[first + 2]; 664f7df2e56Smrg case 2: 665f7df2e56Smrg ev->valuator1 = v->axisVal[first + 1]; 666f7df2e56Smrg case 1: 667f7df2e56Smrg ev->valuator0 = v->axisVal[first]; 668f7df2e56Smrg break; 669f7df2e56Smrg } 670f7df2e56Smrg } 671f7df2e56Smrg} 672f7df2e56Smrg 673f7df2e56Smrg 674f7df2e56Smrgstatic void 675f7df2e56SmrgDeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win) 676f7df2e56Smrg{ 677f7df2e56Smrg int evcount = 1; 678f7df2e56Smrg deviceStateNotify *ev, *sev; 679f7df2e56Smrg deviceKeyStateNotify *kev; 680f7df2e56Smrg deviceButtonStateNotify *bev; 681f7df2e56Smrg 682f7df2e56Smrg KeyClassPtr k; 683f7df2e56Smrg ButtonClassPtr b; 684f7df2e56Smrg ValuatorClassPtr v; 685f7df2e56Smrg int nval = 0, nkeys = 0, nbuttons = 0, first = 0; 686f7df2e56Smrg 687f7df2e56Smrg if (!(wOtherInputMasks(win)) || 688f7df2e56Smrg !(wOtherInputMasks(win)->inputEvents[dev->id] & DeviceStateNotifyMask)) 689f7df2e56Smrg return; 690f7df2e56Smrg 691f7df2e56Smrg if ((b = dev->button) != NULL) { 692f7df2e56Smrg nbuttons = b->numButtons; 693f7df2e56Smrg if (nbuttons > 32) 694f7df2e56Smrg evcount++; 695f7df2e56Smrg } 696f7df2e56Smrg if ((k = dev->key) != NULL) { 697f7df2e56Smrg nkeys = k->xkbInfo->desc->max_key_code - k->xkbInfo->desc->min_key_code; 698f7df2e56Smrg if (nkeys > 32) 699f7df2e56Smrg evcount++; 700f7df2e56Smrg if (nbuttons > 0) { 701f7df2e56Smrg evcount++; 702f7df2e56Smrg } 703f7df2e56Smrg } 704f7df2e56Smrg if ((v = dev->valuator) != NULL) { 705f7df2e56Smrg nval = v->numAxes; 706f7df2e56Smrg 707f7df2e56Smrg if (nval > 3) 708f7df2e56Smrg evcount++; 709f7df2e56Smrg if (nval > 6) { 710f7df2e56Smrg if (!(k && b)) 711f7df2e56Smrg evcount++; 712f7df2e56Smrg if (nval > 9) 713f7df2e56Smrg evcount += ((nval - 7) / 3); 714f7df2e56Smrg } 715f7df2e56Smrg } 716f7df2e56Smrg 717f7df2e56Smrg sev = ev = xallocarray(evcount, sizeof(xEvent)); 718f7df2e56Smrg FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); 719f7df2e56Smrg 720f7df2e56Smrg if (b != NULL) { 721f7df2e56Smrg FixDeviceStateNotify(dev, ev++, NULL, b, v, first); 722f7df2e56Smrg first += 3; 723f7df2e56Smrg nval -= 3; 724f7df2e56Smrg if (nbuttons > 32) { 725f7df2e56Smrg (ev - 1)->deviceid |= MORE_EVENTS; 726f7df2e56Smrg bev = (deviceButtonStateNotify *) ev++; 727f7df2e56Smrg bev->type = DeviceButtonStateNotify; 728f7df2e56Smrg bev->deviceid = dev->id; 729f7df2e56Smrg memcpy((char *) &bev->buttons[4], (char *) &b->down[4], 730f7df2e56Smrg DOWN_LENGTH - 4); 731f7df2e56Smrg } 732f7df2e56Smrg if (nval > 0) { 733f7df2e56Smrg (ev - 1)->deviceid |= MORE_EVENTS; 734f7df2e56Smrg FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 735f7df2e56Smrg first += 3; 736f7df2e56Smrg nval -= 3; 737f7df2e56Smrg } 738f7df2e56Smrg } 739f7df2e56Smrg 740f7df2e56Smrg if (k != NULL) { 741f7df2e56Smrg FixDeviceStateNotify(dev, ev++, k, NULL, v, first); 742f7df2e56Smrg first += 3; 743f7df2e56Smrg nval -= 3; 744f7df2e56Smrg if (nkeys > 32) { 745f7df2e56Smrg (ev - 1)->deviceid |= MORE_EVENTS; 746f7df2e56Smrg kev = (deviceKeyStateNotify *) ev++; 747f7df2e56Smrg kev->type = DeviceKeyStateNotify; 748f7df2e56Smrg kev->deviceid = dev->id; 749f7df2e56Smrg memmove((char *) &kev->keys[0], (char *) &k->down[4], 28); 750f7df2e56Smrg } 751f7df2e56Smrg if (nval > 0) { 752f7df2e56Smrg (ev - 1)->deviceid |= MORE_EVENTS; 753f7df2e56Smrg FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 754f7df2e56Smrg first += 3; 755f7df2e56Smrg nval -= 3; 756f7df2e56Smrg } 757f7df2e56Smrg } 758f7df2e56Smrg 759f7df2e56Smrg while (nval > 0) { 760f7df2e56Smrg FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); 761f7df2e56Smrg first += 3; 762f7df2e56Smrg nval -= 3; 763f7df2e56Smrg if (nval > 0) { 764f7df2e56Smrg (ev - 1)->deviceid |= MORE_EVENTS; 765f7df2e56Smrg FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); 766f7df2e56Smrg first += 3; 767f7df2e56Smrg nval -= 3; 768f7df2e56Smrg } 769f7df2e56Smrg } 770f7df2e56Smrg 771f7df2e56Smrg DeliverEventsToWindow(dev, win, (xEvent *) sev, evcount, 772f7df2e56Smrg DeviceStateNotifyMask, NullGrab); 773f7df2e56Smrg free(sev); 774f7df2e56Smrg} 775f7df2e56Smrg 776f7df2e56Smrgvoid 777f7df2e56SmrgDeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, 778f7df2e56Smrg WindowPtr pWin) 779f7df2e56Smrg{ 780f7df2e56Smrg deviceFocus event; 781f7df2e56Smrg xXIFocusInEvent *xi2event; 782f7df2e56Smrg DeviceIntPtr mouse; 783f7df2e56Smrg int btlen, len, i; 784f7df2e56Smrg 785f7df2e56Smrg mouse = IsFloating(dev) ? dev : GetMaster(dev, MASTER_POINTER); 786f7df2e56Smrg 787f7df2e56Smrg /* XI 2 event */ 788f7df2e56Smrg btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; 789f7df2e56Smrg btlen = bytes_to_int32(btlen); 790f7df2e56Smrg len = sizeof(xXIFocusInEvent) + btlen * 4; 791f7df2e56Smrg 792f7df2e56Smrg xi2event = calloc(1, len); 793f7df2e56Smrg xi2event->type = GenericEvent; 794f7df2e56Smrg xi2event->extension = IReqCode; 795f7df2e56Smrg xi2event->evtype = type; 796f7df2e56Smrg xi2event->length = bytes_to_int32(len - sizeof(xEvent)); 797f7df2e56Smrg xi2event->buttons_len = btlen; 798f7df2e56Smrg xi2event->detail = detail; 799f7df2e56Smrg xi2event->time = currentTime.milliseconds; 800f7df2e56Smrg xi2event->deviceid = dev->id; 801f7df2e56Smrg xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ 802f7df2e56Smrg xi2event->mode = mode; 803f7df2e56Smrg xi2event->root_x = double_to_fp1616(mouse->spriteInfo->sprite->hot.x); 804f7df2e56Smrg xi2event->root_y = double_to_fp1616(mouse->spriteInfo->sprite->hot.y); 805f7df2e56Smrg 806f7df2e56Smrg for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) 807f7df2e56Smrg if (BitIsOn(mouse->button->down, i)) 808f7df2e56Smrg SetBit(&xi2event[1], mouse->button->map[i]); 809f7df2e56Smrg 810f7df2e56Smrg if (dev->key) { 811f7df2e56Smrg xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; 812f7df2e56Smrg xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; 813f7df2e56Smrg xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; 814f7df2e56Smrg xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; 815f7df2e56Smrg 816f7df2e56Smrg xi2event->group.base_group = dev->key->xkbInfo->state.base_group; 817f7df2e56Smrg xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; 818f7df2e56Smrg xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; 819f7df2e56Smrg xi2event->group.effective_group = dev->key->xkbInfo->state.group; 820f7df2e56Smrg } 821f7df2e56Smrg 822f7df2e56Smrg FixUpEventFromWindow(dev->spriteInfo->sprite, (xEvent *) xi2event, pWin, 823f7df2e56Smrg None, FALSE); 824f7df2e56Smrg 825f7df2e56Smrg DeliverEventsToWindow(dev, pWin, (xEvent *) xi2event, 1, 826f7df2e56Smrg GetEventFilter(dev, (xEvent *) xi2event), NullGrab); 827f7df2e56Smrg 828f7df2e56Smrg free(xi2event); 829f7df2e56Smrg 830f7df2e56Smrg /* XI 1.x event */ 831f7df2e56Smrg event = (deviceFocus) { 832f7df2e56Smrg .deviceid = dev->id, 833f7df2e56Smrg .mode = mode, 834f7df2e56Smrg .type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut, 835f7df2e56Smrg .detail = detail, 836f7df2e56Smrg .window = pWin->drawable.id, 837f7df2e56Smrg .time = currentTime.milliseconds 838f7df2e56Smrg }; 839f7df2e56Smrg 840f7df2e56Smrg DeliverEventsToWindow(dev, pWin, (xEvent *) &event, 1, 841f7df2e56Smrg DeviceFocusChangeMask, NullGrab); 842f7df2e56Smrg 843f7df2e56Smrg if (event.type == DeviceFocusIn) 844f7df2e56Smrg DeliverStateNotifyEvent(dev, pWin); 845f7df2e56Smrg} 846f7df2e56Smrg 8474642e01fSmrg/** 8484202a189Smrg * Send focus out events to all windows between 'child' and 'ancestor'. 8494642e01fSmrg * Events are sent running up the hierarchy. 8504642e01fSmrg */ 8514642e01fSmrgstatic void 8524642e01fSmrgDeviceFocusOutEvents(DeviceIntPtr dev, 853f7df2e56Smrg WindowPtr child, WindowPtr ancestor, int mode, int detail) 8544642e01fSmrg{ 855f7df2e56Smrg WindowPtr win; 8564642e01fSmrg 8574642e01fSmrg if (ancestor == child) 858f7df2e56Smrg return; 8594642e01fSmrg for (win = child->parent; win != ancestor; win = win->parent) 8604202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, detail, win); 8614642e01fSmrg} 8624642e01fSmrg 8634642e01fSmrg/** 8644202a189Smrg * Send enter notifies to all windows between 'ancestor' and 'child' (excluding 8654642e01fSmrg * both). Events are sent running up the window hierarchy. This function 8664642e01fSmrg * recurses. 8674642e01fSmrg */ 8684642e01fSmrgstatic void 8694642e01fSmrgDeviceFocusInEvents(DeviceIntPtr dev, 870f7df2e56Smrg WindowPtr ancestor, WindowPtr child, int mode, int detail) 8714642e01fSmrg{ 872f7df2e56Smrg WindowPtr parent = child->parent; 8734642e01fSmrg 8744642e01fSmrg if (ancestor == parent || !parent) 875f7df2e56Smrg return; 8764642e01fSmrg DeviceFocusInEvents(dev, ancestor, parent, mode, detail); 8774202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, detail, parent); 8784642e01fSmrg} 8794642e01fSmrg 8804642e01fSmrg/** 8814202a189Smrg * Send FocusIn events to all windows between 'ancestor' and 'child' (excluding 8824642e01fSmrg * both). Events are sent running down the window hierarchy. This function 8834642e01fSmrg * recurses. 8844642e01fSmrg */ 8854642e01fSmrgstatic void 8864642e01fSmrgCoreFocusInEvents(DeviceIntPtr dev, 887f7df2e56Smrg WindowPtr ancestor, WindowPtr child, int mode, int detail) 8884642e01fSmrg{ 889f7df2e56Smrg WindowPtr parent = child->parent; 890f7df2e56Smrg 8914642e01fSmrg if (ancestor == parent) 892f7df2e56Smrg return; 8934642e01fSmrg CoreFocusInEvents(dev, ancestor, parent, mode, detail); 8944642e01fSmrg 8954642e01fSmrg /* Case 3: 896f7df2e56Smrg A is above W, B is a descendant 897f7df2e56Smrg 898f7df2e56Smrg Classically: The move generates an FocusIn on W with a detail of 899f7df2e56Smrg Virtual or NonlinearVirtual 900f7df2e56Smrg 901f7df2e56Smrg MPX: 902f7df2e56Smrg Case 3A: There is at least one other focus on W itself 903f7df2e56Smrg F(W) doesn't change, so the event should be suppressed 904f7df2e56Smrg Case 3B: Otherwise, if there is at least one other focus in a 905f7df2e56Smrg descendant 906f7df2e56Smrg F(W) stays on the same descendant, or changes to a different 907f7df2e56Smrg descendant. The event should be suppressed. 908f7df2e56Smrg Case 3C: Otherwise: 909f7df2e56Smrg F(W) moves from a window above W to a descendant. The detail may 910f7df2e56Smrg need to be changed from Virtual to NonlinearVirtual depending 911f7df2e56Smrg on the previous F(W). */ 9124642e01fSmrg 9134642e01fSmrg if (!HasFocus(parent) && !FirstFocusChild(parent)) 914f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, detail, parent); 9154642e01fSmrg} 9164642e01fSmrg 9174642e01fSmrgstatic void 9184642e01fSmrgCoreFocusOutEvents(DeviceIntPtr dev, 919f7df2e56Smrg WindowPtr child, WindowPtr ancestor, int mode, int detail) 9204642e01fSmrg{ 921f7df2e56Smrg WindowPtr win; 9224642e01fSmrg 9234642e01fSmrg if (ancestor == child) 9244642e01fSmrg return; 9254642e01fSmrg 926f7df2e56Smrg for (win = child->parent; win != ancestor; win = win->parent) { 9274642e01fSmrg /*Case 7: 928f7df2e56Smrg A is a descendant of W, B is above W 929f7df2e56Smrg 930f7df2e56Smrg Classically: A FocusOut is generated on W with a detail of Virtual 931f7df2e56Smrg or NonlinearVirtual. 932f7df2e56Smrg 933f7df2e56Smrg MPX: 934f7df2e56Smrg Case 3A: There is at least one other focus on W itself 935f7df2e56Smrg F(W) doesn't change, the event should be suppressed. 936f7df2e56Smrg Case 3B: Otherwise, if there is at least one other focus in a 937f7df2e56Smrg descendant 938f7df2e56Smrg F(W) stays on the same descendant, or changes to a different 939f7df2e56Smrg descendant. The event should be suppressed. 940f7df2e56Smrg Case 3C: Otherwise: 941f7df2e56Smrg F(W) changes from the descendant of W to a window above W. 942f7df2e56Smrg The detail may need to be changed from Virtual to NonlinearVirtual 943f7df2e56Smrg or vice-versa depending on the new P(W). */ 9444642e01fSmrg 9454642e01fSmrg /* If one window has a focus or a child with a focuspointer, skip some 9464642e01fSmrg * work and exit. */ 9474642e01fSmrg if (HasFocus(win) || FirstFocusChild(win)) 9484642e01fSmrg return; 9494642e01fSmrg 9504642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, detail, win); 9514642e01fSmrg } 9524642e01fSmrg} 9534642e01fSmrg 9544642e01fSmrg/** 9554642e01fSmrg * Send FocusOut(NotifyPointer) events from the current pointer window (which 9564202a189Smrg * is a descendant of pwin_parent) up to (excluding) pwin_parent. 9574642e01fSmrg * 9584202a189Smrg * NotifyPointer events are only sent for the device paired with dev. 9594642e01fSmrg * 9604202a189Smrg * If the current pointer window is a descendant of 'exclude' or an ancestor of 9614202a189Smrg * 'exclude', no events are sent. If the current pointer IS 'exclude', events 9624202a189Smrg * are sent! 9634642e01fSmrg */ 9644642e01fSmrgstatic void 9654642e01fSmrgCoreFocusOutNotifyPointerEvents(DeviceIntPtr dev, 9664642e01fSmrg WindowPtr pwin_parent, 967f7df2e56Smrg WindowPtr exclude, int mode, int inclusive) 9684642e01fSmrg{ 9694642e01fSmrg WindowPtr P, stopAt; 9704642e01fSmrg 971f7df2e56Smrg P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 9724642e01fSmrg 9734642e01fSmrg if (!P) 9744642e01fSmrg return; 9754642e01fSmrg if (!IsParent(pwin_parent, P)) 9764642e01fSmrg if (!(pwin_parent == P && inclusive)) 9774642e01fSmrg return; 9784642e01fSmrg 9794642e01fSmrg if (exclude != None && exclude != PointerRootWin && 9804642e01fSmrg (IsParent(exclude, P) || IsParent(P, exclude))) 9814642e01fSmrg return; 9824642e01fSmrg 9834642e01fSmrg stopAt = (inclusive) ? pwin_parent->parent : pwin_parent; 9844642e01fSmrg 9854642e01fSmrg for (; P && P != stopAt; P = P->parent) 9864642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyPointer, P); 9874642e01fSmrg} 9884642e01fSmrg 9894642e01fSmrg/** 9904642e01fSmrg * DO NOT CALL DIRECTLY. 9914642e01fSmrg * Recursion helper for CoreFocusInNotifyPointerEvents. 9924642e01fSmrg */ 9934642e01fSmrgstatic void 9944642e01fSmrgCoreFocusInRecurse(DeviceIntPtr dev, 995f7df2e56Smrg WindowPtr win, WindowPtr stopAt, int mode, int inclusive) 9964642e01fSmrg{ 9974642e01fSmrg if ((!inclusive && win == stopAt) || !win) 9984642e01fSmrg return; 9994642e01fSmrg 10004642e01fSmrg CoreFocusInRecurse(dev, win->parent, stopAt, mode, inclusive); 10014642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyPointer, win); 10024642e01fSmrg} 10034642e01fSmrg 10044642e01fSmrg/** 10054202a189Smrg * Send FocusIn(NotifyPointer) events from pwin_parent down to 10064202a189Smrg * including the current pointer window (which is a descendant of pwin_parent). 10074642e01fSmrg * 10084202a189Smrg * @param pwin The pointer window. 10094202a189Smrg * @param exclude If the pointer window is a child of 'exclude', no events are 10104202a189Smrg * sent. 10114202a189Smrg * @param inclusive If TRUE, pwin_parent will receive the event too. 10124642e01fSmrg */ 10134642e01fSmrgstatic void 10144642e01fSmrgCoreFocusInNotifyPointerEvents(DeviceIntPtr dev, 10154642e01fSmrg WindowPtr pwin_parent, 1016f7df2e56Smrg WindowPtr exclude, int mode, int inclusive) 10174642e01fSmrg{ 10184642e01fSmrg WindowPtr P; 10194642e01fSmrg 1020f7df2e56Smrg P = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 10214642e01fSmrg 10224642e01fSmrg if (!P || P == exclude || (pwin_parent != P && !IsParent(pwin_parent, P))) 10234642e01fSmrg return; 10244642e01fSmrg 10254642e01fSmrg if (exclude != None && (IsParent(exclude, P) || IsParent(P, exclude))) 10264642e01fSmrg return; 10274642e01fSmrg 10284642e01fSmrg CoreFocusInRecurse(dev, P, pwin_parent, mode, inclusive); 10294642e01fSmrg} 10304642e01fSmrg 10314642e01fSmrg/** 10324202a189Smrg * Focus of dev moves from A to B and A neither a descendant of B nor is 10334202a189Smrg * B a descendant of A. 10344642e01fSmrg */ 10354642e01fSmrgstatic void 1036f7df2e56SmrgCoreFocusNonLinear(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 10374642e01fSmrg{ 10384642e01fSmrg WindowPtr X = CommonAncestor(A, B); 10394642e01fSmrg 10404642e01fSmrg /* Case 4: 1041f7df2e56Smrg A is W, B is above W 10424642e01fSmrg 1043f7df2e56Smrg Classically: The change generates a FocusOut on W with a detail of 10444642e01fSmrg Ancestor or Nonlinear 10454642e01fSmrg 1046f7df2e56Smrg MPX: 1047f7df2e56Smrg Case 3A: There is at least one other focus on W itself 1048f7df2e56Smrg F(W) doesn't change, the event should be suppressed 1049f7df2e56Smrg Case 3B: Otherwise, if there is at least one other focus in a 1050f7df2e56Smrg descendant of W 1051f7df2e56Smrg F(W) changes from W to a descendant of W. The detail field 1052f7df2e56Smrg is set to Inferior 1053f7df2e56Smrg Case 3C: Otherwise: 1054f7df2e56Smrg The focus window moves from W to a window above W. 1055f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear or 1056f7df2e56Smrg vice versa depending on the the new F(W) 10574642e01fSmrg */ 10584642e01fSmrg 1059f7df2e56Smrg if (!HasFocus(A)) { 10604642e01fSmrg WindowPtr child = FirstFocusChild(A); 1061f7df2e56Smrg 1062f7df2e56Smrg if (child) { 1063f7df2e56Smrg /* NotifyPointer P-A unless P is child or below */ 10644642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 10654642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1066f7df2e56Smrg } 1067f7df2e56Smrg else { 10684642e01fSmrg /* NotifyPointer P-A */ 10694642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 10704642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 10714642e01fSmrg } 10724642e01fSmrg } 10734642e01fSmrg 10744642e01fSmrg CoreFocusOutEvents(dev, A, X, mode, NotifyNonlinearVirtual); 10754642e01fSmrg 10764642e01fSmrg /* 1077f7df2e56Smrg Case 9: 1078f7df2e56Smrg A is a descendant of W, B is a descendant of W 10794642e01fSmrg 1080f7df2e56Smrg Classically: No events are generated on W 1081f7df2e56Smrg MPX: The focus window stays the same or moves to a different 1082f7df2e56Smrg descendant of W. No events should be generated on W. 10834642e01fSmrg 10844642e01fSmrg Therefore, no event to X. 1085f7df2e56Smrg */ 10864642e01fSmrg 10874642e01fSmrg CoreFocusInEvents(dev, X, B, mode, NotifyNonlinearVirtual); 10884642e01fSmrg 10894642e01fSmrg /* Case 2: 1090f7df2e56Smrg A is above W, B=W 10914642e01fSmrg 1092f7df2e56Smrg Classically: The move generates an EnterNotify on W with a detail of 1093f7df2e56Smrg Ancestor or Nonlinear 1094f7df2e56Smrg 1095f7df2e56Smrg MPX: 1096f7df2e56Smrg Case 2A: There is at least one other focus on W itself 1097f7df2e56Smrg F(W) doesn't change, so the event should be suppressed 1098f7df2e56Smrg Case 2B: Otherwise, if there is at least one other focus in a 1099f7df2e56Smrg descendant 1100f7df2e56Smrg F(W) moves from a descendant to W. detail is changed to Inferior. 1101f7df2e56Smrg Case 2C: Otherwise: 1102f7df2e56Smrg F(W) changes from a window above W to W itself. 1103f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear 1104f7df2e56Smrg or vice-versa depending on the previous F(W). */ 1105f7df2e56Smrg 1106f7df2e56Smrg if (!HasFocus(B)) { 1107f7df2e56Smrg WindowPtr child = FirstFocusChild(B); 1108f7df2e56Smrg 1109f7df2e56Smrg if (child) { 1110f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1111f7df2e56Smrg /* NotifyPointer B-P unless P is child or below. */ 1112f7df2e56Smrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1113f7df2e56Smrg } 1114f7df2e56Smrg else { 1115f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 1116f7df2e56Smrg /* NotifyPointer B-P unless P is child or below. */ 1117f7df2e56Smrg CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 1118f7df2e56Smrg } 1119f7df2e56Smrg } 1120f7df2e56Smrg} 11214642e01fSmrg 11224642e01fSmrg/** 11234202a189Smrg * Focus of dev moves from A to B and A is a descendant of B. 11244642e01fSmrg */ 11254642e01fSmrgstatic void 1126f7df2e56SmrgCoreFocusToAncestor(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 11274642e01fSmrg{ 11284642e01fSmrg /* Case 4: 1129f7df2e56Smrg A is W, B is above W 11304642e01fSmrg 1131f7df2e56Smrg Classically: The change generates a FocusOut on W with a detail of 11324642e01fSmrg Ancestor or Nonlinear 11334642e01fSmrg 1134f7df2e56Smrg MPX: 1135f7df2e56Smrg Case 3A: There is at least one other focus on W itself 1136f7df2e56Smrg F(W) doesn't change, the event should be suppressed 1137f7df2e56Smrg Case 3B: Otherwise, if there is at least one other focus in a 1138f7df2e56Smrg descendant of W 1139f7df2e56Smrg F(W) changes from W to a descendant of W. The detail field 1140f7df2e56Smrg is set to Inferior 1141f7df2e56Smrg Case 3C: Otherwise: 1142f7df2e56Smrg The focus window moves from W to a window above W. 1143f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear or 1144f7df2e56Smrg vice versa depending on the the new F(W) 11454642e01fSmrg */ 1146f7df2e56Smrg if (!HasFocus(A)) { 11474642e01fSmrg WindowPtr child = FirstFocusChild(A); 1148f7df2e56Smrg 1149f7df2e56Smrg if (child) { 1150f7df2e56Smrg /* NotifyPointer P-A unless P is child or below */ 11514642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, child, mode, FALSE); 11524642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1153f7df2e56Smrg } 1154f7df2e56Smrg else 11554642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyAncestor, A); 11564642e01fSmrg } 11574642e01fSmrg 11584642e01fSmrg CoreFocusOutEvents(dev, A, B, mode, NotifyVirtual); 11594642e01fSmrg 11604642e01fSmrg /* Case 8: 1161f7df2e56Smrg A is a descendant of W, B is W 11624642e01fSmrg 1163f7df2e56Smrg Classically: A FocusOut is generated on W with a detail of 1164f7df2e56Smrg NotifyInferior 11654642e01fSmrg 1166f7df2e56Smrg MPX: 1167f7df2e56Smrg Case 3A: There is at least one other focus on W itself 1168f7df2e56Smrg F(W) doesn't change, the event should be suppressed 1169f7df2e56Smrg Case 3B: Otherwise: 1170f7df2e56Smrg F(W) changes from a descendant to W itself. */ 11714642e01fSmrg 1172f7df2e56Smrg if (!HasFocus(B)) { 11734642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 11744642e01fSmrg /* NotifyPointer B-P unless P is A or below. */ 11754642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, A, mode, FALSE); 11764642e01fSmrg } 11774642e01fSmrg} 11784642e01fSmrg 11794642e01fSmrg/** 11804202a189Smrg * Focus of dev moves from A to B and B is a descendant of A. 11814642e01fSmrg */ 11824642e01fSmrgstatic void 1183f7df2e56SmrgCoreFocusToDescendant(DeviceIntPtr dev, WindowPtr A, WindowPtr B, int mode) 11844642e01fSmrg{ 11854642e01fSmrg /* Case 6: 1186f7df2e56Smrg A is W, B is a descendant of W 11874642e01fSmrg 1188f7df2e56Smrg Classically: A FocusOut is generated on W with a detail of 11894642e01fSmrg NotifyInferior 11904642e01fSmrg 1191f7df2e56Smrg MPX: 1192f7df2e56Smrg Case 3A: There is at least one other focus on W itself 1193f7df2e56Smrg F(W) doesn't change, the event should be suppressed 1194f7df2e56Smrg Case 3B: Otherwise: 1195f7df2e56Smrg F(W) changes from W to a descendant of W. */ 11964642e01fSmrg 1197f7df2e56Smrg if (!HasFocus(A)) { 1198f7df2e56Smrg /* NotifyPointer P-A unless P is B or below */ 11994642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 12004642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 12014642e01fSmrg } 12024642e01fSmrg 12034642e01fSmrg CoreFocusInEvents(dev, A, B, mode, NotifyVirtual); 12044642e01fSmrg 12054642e01fSmrg /* Case 2: 1206f7df2e56Smrg A is above W, B=W 1207f7df2e56Smrg 1208f7df2e56Smrg Classically: The move generates an FocusIn on W with a detail of 1209f7df2e56Smrg Ancestor or Nonlinear 1210f7df2e56Smrg 1211f7df2e56Smrg MPX: 1212f7df2e56Smrg Case 2A: There is at least one other focus on W itself 1213f7df2e56Smrg F(W) doesn't change, so the event should be suppressed 1214f7df2e56Smrg Case 2B: Otherwise, if there is at least one other focus in a 1215f7df2e56Smrg descendant 1216f7df2e56Smrg F(W) moves from a descendant to W. detail is changed to Inferior. 1217f7df2e56Smrg Case 2C: Otherwise: 1218f7df2e56Smrg F(W) changes from a window above W to W itself. 1219f7df2e56Smrg The detail may need to be changed from Ancestor to Nonlinear 1220f7df2e56Smrg or vice-versa depending on the previous F(W). */ 1221f7df2e56Smrg 1222f7df2e56Smrg if (!HasFocus(B)) { 1223f7df2e56Smrg WindowPtr child = FirstFocusChild(B); 1224f7df2e56Smrg 1225f7df2e56Smrg if (child) { 1226f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1227f7df2e56Smrg /* NotifyPointer B-P unless P is child or below. */ 1228f7df2e56Smrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1229f7df2e56Smrg } 1230f7df2e56Smrg else 1231f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, NotifyAncestor, B); 1232f7df2e56Smrg } 12334642e01fSmrg} 12344642e01fSmrg 12354642e01fSmrgstatic BOOL 12364642e01fSmrgHasOtherPointer(WindowPtr win, DeviceIntPtr exclude) 12374642e01fSmrg{ 12384642e01fSmrg int i; 12394642e01fSmrg 12404642e01fSmrg for (i = 0; i < MAXDEVICES; i++) 12414642e01fSmrg if (i != exclude->id && PointerWindows[i] == win) 12424642e01fSmrg return TRUE; 12434642e01fSmrg 12444642e01fSmrg return FALSE; 12454642e01fSmrg} 12464642e01fSmrg 12474642e01fSmrg/** 12484642e01fSmrg * Focus moves from PointerRoot to None or from None to PointerRoot. 12494642e01fSmrg * Assumption: Neither A nor B are valid windows. 12504642e01fSmrg */ 12514642e01fSmrgstatic void 12524642e01fSmrgCoreFocusPointerRootNoneSwitch(DeviceIntPtr dev, 1253f7df2e56Smrg WindowPtr A, /* PointerRootWin or NoneWin */ 1254f7df2e56Smrg WindowPtr B, /* NoneWin or PointerRootWin */ 12554642e01fSmrg int mode) 12564642e01fSmrg{ 12574642e01fSmrg WindowPtr root; 12584642e01fSmrg int i; 12594642e01fSmrg int nscreens = screenInfo.numScreens; 12604642e01fSmrg 12614642e01fSmrg#ifdef PANORAMIX 12624642e01fSmrg if (!noPanoramiXExtension) 12634642e01fSmrg nscreens = 1; 12644642e01fSmrg#endif 12654642e01fSmrg 1266f7df2e56Smrg for (i = 0; i < nscreens; i++) { 12674202a189Smrg root = screenInfo.screens[i]->root; 1268f7df2e56Smrg if (!HasOtherPointer(root, GetMaster(dev, POINTER_OR_FLOAT)) && 1269f7df2e56Smrg !FirstFocusChild(root)) { 12704642e01fSmrg /* If pointer was on PointerRootWin and changes to NoneWin, and 12714202a189Smrg * the pointer paired with dev is below the current root window, 12724642e01fSmrg * do a NotifyPointer run. */ 12734642e01fSmrg if (dev->focus && dev->focus->win == PointerRootWin && 1274f7df2e56Smrg B != PointerRootWin) { 1275f7df2e56Smrg WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 1276f7df2e56Smrg 12774642e01fSmrg if (ptrwin && IsParent(root, ptrwin)) 1278f7df2e56Smrg CoreFocusOutNotifyPointerEvents(dev, root, None, mode, 1279f7df2e56Smrg TRUE); 12804642e01fSmrg } 1281f7df2e56Smrg CoreFocusEvent(dev, FocusOut, mode, 1282f7df2e56Smrg A ? NotifyPointerRoot : NotifyDetailNone, root); 1283f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, 1284f7df2e56Smrg B ? NotifyPointerRoot : NotifyDetailNone, root); 12854642e01fSmrg if (B == PointerRootWin) 12864642e01fSmrg CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 12874642e01fSmrg } 12884642e01fSmrg 12894642e01fSmrg } 12904642e01fSmrg} 12914642e01fSmrg 12924642e01fSmrg/** 12934202a189Smrg * Focus moves from window A to PointerRoot or to None. 12944202a189Smrg * Assumption: A is a valid window and not PointerRoot or None. 12954642e01fSmrg */ 12964642e01fSmrgstatic void 1297f7df2e56SmrgCoreFocusToPointerRootOrNone(DeviceIntPtr dev, WindowPtr A, 1298f7df2e56Smrg WindowPtr B, /* PointerRootWin or NoneWin */ 1299f7df2e56Smrg int mode) 13004642e01fSmrg{ 13014642e01fSmrg WindowPtr root; 13024642e01fSmrg int i; 13034642e01fSmrg int nscreens = screenInfo.numScreens; 13044642e01fSmrg 13054642e01fSmrg#ifdef PANORAMIX 13064642e01fSmrg if (!noPanoramiXExtension) 13074642e01fSmrg nscreens = 1; 13084642e01fSmrg#endif 13094642e01fSmrg 1310f7df2e56Smrg if (!HasFocus(A)) { 13114642e01fSmrg WindowPtr child = FirstFocusChild(A); 1312f7df2e56Smrg 1313f7df2e56Smrg if (child) { 1314f7df2e56Smrg /* NotifyPointer P-A unless P is B or below */ 13154642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, B, mode, FALSE); 13164642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyInferior, A); 1317f7df2e56Smrg } 1318f7df2e56Smrg else { 13194642e01fSmrg /* NotifyPointer P-A */ 13204642e01fSmrg CoreFocusOutNotifyPointerEvents(dev, A, None, mode, FALSE); 13214642e01fSmrg CoreFocusEvent(dev, FocusOut, mode, NotifyNonlinear, A); 13224642e01fSmrg } 13234642e01fSmrg } 13244642e01fSmrg 13254642e01fSmrg /* NullWindow means we include the root window */ 13264642e01fSmrg CoreFocusOutEvents(dev, A, NullWindow, mode, NotifyNonlinearVirtual); 13274642e01fSmrg 1328f7df2e56Smrg for (i = 0; i < nscreens; i++) { 13294202a189Smrg root = screenInfo.screens[i]->root; 1330f7df2e56Smrg if (!HasFocus(root) && !FirstFocusChild(root)) { 1331f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, 1332f7df2e56Smrg B ? NotifyPointerRoot : NotifyDetailNone, root); 13334642e01fSmrg if (B == PointerRootWin) 13344642e01fSmrg CoreFocusInNotifyPointerEvents(dev, root, None, mode, TRUE); 13354642e01fSmrg } 13364642e01fSmrg } 13374642e01fSmrg} 13384642e01fSmrg 13394642e01fSmrg/** 13404202a189Smrg * Focus moves from PointerRoot or None to a window B. 13414202a189Smrg * Assumption: B is a valid window and not PointerRoot or None. 13424642e01fSmrg */ 13434642e01fSmrgstatic void 13444642e01fSmrgCoreFocusFromPointerRootOrNone(DeviceIntPtr dev, 1345f7df2e56Smrg WindowPtr A, /* PointerRootWin or NoneWin */ 1346f7df2e56Smrg WindowPtr B, int mode) 13474642e01fSmrg{ 13484642e01fSmrg WindowPtr root; 13494642e01fSmrg int i; 13504642e01fSmrg int nscreens = screenInfo.numScreens; 13514642e01fSmrg 13524642e01fSmrg#ifdef PANORAMIX 13534642e01fSmrg if (!noPanoramiXExtension) 13544642e01fSmrg nscreens = 1; 13554642e01fSmrg#endif 13564642e01fSmrg 1357f7df2e56Smrg for (i = 0; i < nscreens; i++) { 13584202a189Smrg root = screenInfo.screens[i]->root; 1359f7df2e56Smrg if (!HasFocus(root) && !FirstFocusChild(root)) { 13604642e01fSmrg /* If pointer was on PointerRootWin and changes to NoneWin, and 13614202a189Smrg * the pointer paired with dev is below the current root window, 13624642e01fSmrg * do a NotifyPointer run. */ 13634642e01fSmrg if (dev->focus && dev->focus->win == PointerRootWin && 1364f7df2e56Smrg B != PointerRootWin) { 1365f7df2e56Smrg WindowPtr ptrwin = PointerWin(GetMaster(dev, POINTER_OR_FLOAT)); 1366f7df2e56Smrg 13674642e01fSmrg if (ptrwin) 1368f7df2e56Smrg CoreFocusOutNotifyPointerEvents(dev, root, None, mode, 1369f7df2e56Smrg TRUE); 13704642e01fSmrg } 1371f7df2e56Smrg CoreFocusEvent(dev, FocusOut, mode, 1372f7df2e56Smrg A ? NotifyPointerRoot : NotifyDetailNone, root); 13734642e01fSmrg } 13744642e01fSmrg } 13754642e01fSmrg 1376f7df2e56Smrg root = B; /* get B's root window */ 1377f7df2e56Smrg while (root->parent) 13784642e01fSmrg root = root->parent; 13794642e01fSmrg 1380f7df2e56Smrg if (B != root) { 13814642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinearVirtual, root); 13824642e01fSmrg CoreFocusInEvents(dev, root, B, mode, NotifyNonlinearVirtual); 13834642e01fSmrg } 13844642e01fSmrg 1385f7df2e56Smrg if (!HasFocus(B)) { 13864642e01fSmrg WindowPtr child = FirstFocusChild(B); 1387f7df2e56Smrg 1388f7df2e56Smrg if (child) { 1389f7df2e56Smrg CoreFocusEvent(dev, FocusIn, mode, NotifyInferior, B); 1390f7df2e56Smrg /* NotifyPointer B-P unless P is child or below. */ 1391f7df2e56Smrg CoreFocusInNotifyPointerEvents(dev, B, child, mode, FALSE); 1392f7df2e56Smrg } 1393f7df2e56Smrg else { 13944642e01fSmrg CoreFocusEvent(dev, FocusIn, mode, NotifyNonlinear, B); 13954642e01fSmrg /* NotifyPointer B-P unless P is child or below. */ 13964642e01fSmrg CoreFocusInNotifyPointerEvents(dev, B, None, mode, FALSE); 13974642e01fSmrg } 13984642e01fSmrg } 13994642e01fSmrg 14004642e01fSmrg} 14014642e01fSmrg 14024642e01fSmrgstatic void 1403f7df2e56SmrgCoreFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 14044642e01fSmrg{ 14054202a189Smrg if (!IsMaster(dev)) 14064642e01fSmrg return; 14074642e01fSmrg 14084202a189Smrg SetFocusOut(dev); 14094642e01fSmrg 14104642e01fSmrg if (((to == NullWindow) || (to == PointerRootWin)) && 14114642e01fSmrg ((from == NullWindow) || (from == PointerRootWin))) 14124642e01fSmrg CoreFocusPointerRootNoneSwitch(dev, from, to, mode); 14134642e01fSmrg else if ((to == NullWindow) || (to == PointerRootWin)) 14144642e01fSmrg CoreFocusToPointerRootOrNone(dev, from, to, mode); 14154642e01fSmrg else if ((from == NullWindow) || (from == PointerRootWin)) 14164642e01fSmrg CoreFocusFromPointerRootOrNone(dev, from, to, mode); 14174642e01fSmrg else if (IsParent(from, to)) 14184642e01fSmrg CoreFocusToDescendant(dev, from, to, mode); 14194642e01fSmrg else if (IsParent(to, from)) 14204642e01fSmrg CoreFocusToAncestor(dev, from, to, mode); 14214642e01fSmrg else 14224642e01fSmrg CoreFocusNonLinear(dev, from, to, mode); 14234642e01fSmrg 14244642e01fSmrg SetFocusIn(dev, to); 14254642e01fSmrg} 14264642e01fSmrg 14274642e01fSmrgstatic void 1428f7df2e56SmrgDeviceFocusEvents(DeviceIntPtr dev, WindowPtr from, WindowPtr to, int mode) 14294642e01fSmrg{ 1430f7df2e56Smrg int out, in; /* for holding details for to/from 1431f7df2e56Smrg PointerRoot/None */ 14324642e01fSmrg int i; 14334642e01fSmrg int nscreens = screenInfo.numScreens; 1434f7df2e56Smrg SpritePtr sprite = dev->spriteInfo->sprite; 14354642e01fSmrg 14364642e01fSmrg if (from == to) 14374642e01fSmrg return; 14384642e01fSmrg out = (from == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 14394642e01fSmrg in = (to == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; 14404642e01fSmrg /* wrong values if neither, but then not referenced */ 14414642e01fSmrg 14424642e01fSmrg#ifdef PANORAMIX 14434642e01fSmrg if (!noPanoramiXExtension) 14444642e01fSmrg nscreens = 1; 14454642e01fSmrg#endif 14464642e01fSmrg 1447f7df2e56Smrg if ((to == NullWindow) || (to == PointerRootWin)) { 1448f7df2e56Smrg if ((from == NullWindow) || (from == PointerRootWin)) { 1449f7df2e56Smrg if (from == PointerRootWin) { 1450f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1451f7df2e56Smrg sprite->win); 1452f7df2e56Smrg DeviceFocusOutEvents(dev, sprite->win, 1453f7df2e56Smrg GetCurrentRootWindow(dev), mode, 1454f7df2e56Smrg NotifyPointer); 1455f7df2e56Smrg } 14564642e01fSmrg /* Notify all the roots */ 14574642e01fSmrg for (i = 0; i < nscreens; i++) 1458f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, out, 1459f7df2e56Smrg screenInfo.screens[i]->root); 14604642e01fSmrg } 1461f7df2e56Smrg else { 1462f7df2e56Smrg if (IsParent(from, sprite->win)) { 1463f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1464f7df2e56Smrg sprite->win); 14654642e01fSmrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 1466f7df2e56Smrg NotifyPointer); 1467f7df2e56Smrg } 14684202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 14694642e01fSmrg /* next call catches the root too, if the screen changed */ 1470f7df2e56Smrg DeviceFocusOutEvents(dev, from, NullWindow, mode, 1471f7df2e56Smrg NotifyNonlinearVirtual); 14724642e01fSmrg } 14734642e01fSmrg /* Notify all the roots */ 14744642e01fSmrg for (i = 0; i < nscreens; i++) 1475f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, in, 1476f7df2e56Smrg screenInfo.screens[i]->root); 1477f7df2e56Smrg if (to == PointerRootWin) { 1478f7df2e56Smrg DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), sprite->win, 1479f7df2e56Smrg mode, NotifyPointer); 1480f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyPointer, sprite->win); 1481f7df2e56Smrg } 14824642e01fSmrg } 1483f7df2e56Smrg else { 1484f7df2e56Smrg if ((from == NullWindow) || (from == PointerRootWin)) { 1485f7df2e56Smrg if (from == PointerRootWin) { 1486f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1487f7df2e56Smrg sprite->win); 1488f7df2e56Smrg DeviceFocusOutEvents(dev, sprite->win, 1489f7df2e56Smrg GetCurrentRootWindow(dev), mode, 1490f7df2e56Smrg NotifyPointer); 1491f7df2e56Smrg } 14924642e01fSmrg for (i = 0; i < nscreens; i++) 1493f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, out, 1494f7df2e56Smrg screenInfo.screens[i]->root); 14954642e01fSmrg if (to->parent != NullWindow) 1496f7df2e56Smrg DeviceFocusInEvents(dev, GetCurrentRootWindow(dev), to, mode, 1497f7df2e56Smrg NotifyNonlinearVirtual); 14984202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 14994642e01fSmrg if (IsParent(to, sprite->win)) 15004642e01fSmrg DeviceFocusInEvents(dev, to, sprite->win, mode, NotifyPointer); 15014642e01fSmrg } 1502f7df2e56Smrg else { 1503f7df2e56Smrg if (IsParent(to, from)) { 15044202a189Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyAncestor, from); 1505f7df2e56Smrg DeviceFocusOutEvents(dev, from, to, mode, NotifyVirtual); 15064202a189Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyInferior, to); 15074642e01fSmrg if ((IsParent(to, sprite->win)) && 1508f7df2e56Smrg (sprite->win != from) && 1509f7df2e56Smrg (!IsParent(from, sprite->win)) && 1510f7df2e56Smrg (!IsParent(sprite->win, from))) 1511f7df2e56Smrg DeviceFocusInEvents(dev, to, sprite->win, mode, 1512f7df2e56Smrg NotifyPointer); 15134642e01fSmrg } 1514f7df2e56Smrg else if (IsParent(from, to)) { 1515f7df2e56Smrg if ((IsParent(from, sprite->win)) && 1516f7df2e56Smrg (sprite->win != from) && 1517f7df2e56Smrg (!IsParent(to, sprite->win)) && 1518f7df2e56Smrg (!IsParent(sprite->win, to))) { 1519f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyPointer, 1520f7df2e56Smrg sprite->win); 1521f7df2e56Smrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 1522f7df2e56Smrg NotifyPointer); 15234642e01fSmrg } 1524f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyInferior, from); 1525f7df2e56Smrg DeviceFocusInEvents(dev, from, to, mode, NotifyVirtual); 1526f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyAncestor, to); 1527f7df2e56Smrg } 1528f7df2e56Smrg else { 1529f7df2e56Smrg /* neither from or to is child of other */ 1530f7df2e56Smrg WindowPtr common = CommonAncestor(to, from); 1531f7df2e56Smrg 1532f7df2e56Smrg /* common == NullWindow ==> different screens */ 1533f7df2e56Smrg if (IsParent(from, sprite->win)) 1534f7df2e56Smrg DeviceFocusOutEvents(dev, sprite->win, from, mode, 1535f7df2e56Smrg NotifyPointer); 1536f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusOut, mode, NotifyNonlinear, from); 1537f7df2e56Smrg if (from->parent != NullWindow) 1538f7df2e56Smrg DeviceFocusOutEvents(dev, from, common, mode, 1539f7df2e56Smrg NotifyNonlinearVirtual); 1540f7df2e56Smrg if (to->parent != NullWindow) 1541f7df2e56Smrg DeviceFocusInEvents(dev, common, to, mode, 1542f7df2e56Smrg NotifyNonlinearVirtual); 1543f7df2e56Smrg DeviceFocusEvent(dev, XI_FocusIn, mode, NotifyNonlinear, to); 1544f7df2e56Smrg if (IsParent(to, sprite->win)) 1545f7df2e56Smrg DeviceFocusInEvents(dev, to, sprite->win, mode, 1546f7df2e56Smrg NotifyPointer); 1547f7df2e56Smrg } 15484642e01fSmrg } 15494642e01fSmrg } 15504642e01fSmrg} 15514642e01fSmrg 15524642e01fSmrg/** 15534642e01fSmrg * Figure out if focus events are necessary and send them to the 15544642e01fSmrg * appropriate windows. 15554642e01fSmrg * 15564642e01fSmrg * @param from Window the focus moved out of. 15574642e01fSmrg * @param to Window the focus moved into. 15584642e01fSmrg */ 15594642e01fSmrgvoid 1560f7df2e56SmrgDoFocusEvents(DeviceIntPtr pDev, WindowPtr from, WindowPtr to, int mode) 15614642e01fSmrg{ 15624642e01fSmrg if (!IsKeyboardDevice(pDev)) 15634642e01fSmrg return; 15644642e01fSmrg 15657e31ba66Smrg if (from == to && mode != NotifyGrab && mode != NotifyUngrab) 1566f7df2e56Smrg return; 15674642e01fSmrg 15684642e01fSmrg CoreFocusEvents(pDev, from, to, mode); 15694642e01fSmrg DeviceFocusEvents(pDev, from, to, mode); 15704642e01fSmrg} 1571