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