mirror of
https://github.com/brl/mutter.git
synced 2024-11-30 12:00:44 -05:00
0debb24e12
Prior to this commit, barriers were created with a MetaDisplay pointer, despite being entities related and owned by the backend. In the X11 case, it was also not hooked up to the backend X11 connection, but the clutter one, meaning for example that the logic was active (but dormant) also for the Xwayland connection. Fix this by moving X11 barrier management and event processing fully to the backend. Also replace passing a display pointer with passing a backend pointer. Keep the display pointer around for a release, but mark it as deprecated. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2442>
2037 lines
64 KiB
C
2037 lines
64 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
* Copyright (C) 2001 Havoc Pennington
|
|
* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
|
|
* Copyright (C) 2003, 2004 Rob Adams
|
|
* Copyright (C) 2004-2006 Elijah Newren
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "x11/events.h"
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/XKBlib.h>
|
|
#include <X11/extensions/Xdamage.h>
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include "backends/meta-cursor-tracker-private.h"
|
|
#include "backends/x11/meta-backend-x11.h"
|
|
#include "backends/x11/meta-cursor-tracker-x11.h"
|
|
#include "compositor/meta-compositor-x11.h"
|
|
#include "cogl/cogl.h"
|
|
#include "core/bell.h"
|
|
#include "core/display-private.h"
|
|
#include "core/meta-workspace-manager-private.h"
|
|
#include "core/window-private.h"
|
|
#include "core/workspace-private.h"
|
|
#include "meta/meta-backend.h"
|
|
#include "meta/meta-context.h"
|
|
#include "meta/meta-x11-errors.h"
|
|
#include "x11/meta-startup-notification-x11.h"
|
|
#include "x11/meta-x11-display-private.h"
|
|
#include "x11/meta-x11-selection-private.h"
|
|
#include "x11/meta-x11-selection-input-stream-private.h"
|
|
#include "x11/meta-x11-selection-output-stream-private.h"
|
|
#include "x11/window-x11.h"
|
|
#include "x11/xprops.h"
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
#include "wayland/meta-wayland-private.h"
|
|
#include "wayland/meta-xwayland-private.h"
|
|
#include "wayland/meta-xwayland.h"
|
|
#endif
|
|
|
|
static XIEvent *
|
|
get_input_event (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
if (event->type == GenericEvent &&
|
|
event->xcookie.extension == x11_display->xinput_opcode)
|
|
{
|
|
XIEvent *input_event;
|
|
|
|
/* NB: GDK event filters already have generic events
|
|
* allocated, so no need to do XGetEventData() on our own
|
|
*/
|
|
input_event = (XIEvent *) event->xcookie.data;
|
|
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_Motion:
|
|
case XI_ButtonPress:
|
|
case XI_ButtonRelease:
|
|
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
return input_event;
|
|
break;
|
|
case XI_KeyPress:
|
|
case XI_KeyRelease:
|
|
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
|
|
return input_event;
|
|
break;
|
|
case XI_FocusIn:
|
|
case XI_FocusOut:
|
|
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
|
|
return input_event;
|
|
break;
|
|
case XI_Enter:
|
|
case XI_Leave:
|
|
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
return input_event;
|
|
break;
|
|
case XI_BarrierHit:
|
|
case XI_BarrierLeave:
|
|
if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
return input_event;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static Window
|
|
xievent_get_modified_window (MetaX11Display *x11_display,
|
|
XIEvent *input_event)
|
|
{
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_Motion:
|
|
case XI_ButtonPress:
|
|
case XI_ButtonRelease:
|
|
case XI_KeyPress:
|
|
case XI_KeyRelease:
|
|
return ((XIDeviceEvent *) input_event)->event;
|
|
case XI_FocusIn:
|
|
case XI_FocusOut:
|
|
case XI_Enter:
|
|
case XI_Leave:
|
|
return ((XIEnterEvent *) input_event)->event;
|
|
case XI_BarrierHit:
|
|
case XI_BarrierLeave:
|
|
return ((XIBarrierEvent *) input_event)->event;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
/* Return the window this has to do with, if any, rather
|
|
* than the frame or root window that was selecting
|
|
* for substructure
|
|
*/
|
|
static Window
|
|
event_get_modified_window (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
XIEvent *input_event = get_input_event (x11_display, event);
|
|
|
|
if (input_event)
|
|
return xievent_get_modified_window (x11_display, input_event);
|
|
|
|
switch (event->type)
|
|
{
|
|
case KeymapNotify:
|
|
case Expose:
|
|
case GraphicsExpose:
|
|
case NoExpose:
|
|
case VisibilityNotify:
|
|
case ResizeRequest:
|
|
case PropertyNotify:
|
|
case SelectionClear:
|
|
case SelectionRequest:
|
|
case SelectionNotify:
|
|
case ColormapNotify:
|
|
case ClientMessage:
|
|
return event->xany.window;
|
|
|
|
case CreateNotify:
|
|
return event->xcreatewindow.window;
|
|
|
|
case DestroyNotify:
|
|
return event->xdestroywindow.window;
|
|
|
|
case UnmapNotify:
|
|
return event->xunmap.window;
|
|
|
|
case MapNotify:
|
|
return event->xmap.window;
|
|
|
|
case MapRequest:
|
|
return event->xmaprequest.window;
|
|
|
|
case ReparentNotify:
|
|
return event->xreparent.window;
|
|
|
|
case ConfigureNotify:
|
|
return event->xconfigure.window;
|
|
|
|
case ConfigureRequest:
|
|
return event->xconfigurerequest.window;
|
|
|
|
case GravityNotify:
|
|
return event->xgravity.window;
|
|
|
|
case CirculateNotify:
|
|
return event->xcirculate.window;
|
|
|
|
case CirculateRequest:
|
|
return event->xcirculaterequest.window;
|
|
|
|
case MappingNotify:
|
|
return None;
|
|
|
|
default:
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
{
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
return sev->window;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
}
|
|
|
|
static guint32
|
|
event_get_time (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
XIEvent *input_event = get_input_event (x11_display, event);
|
|
|
|
if (input_event)
|
|
return input_event->time;
|
|
|
|
switch (event->type)
|
|
{
|
|
case PropertyNotify:
|
|
return event->xproperty.time;
|
|
|
|
case SelectionClear:
|
|
case SelectionRequest:
|
|
case SelectionNotify:
|
|
return event->xselection.time;
|
|
|
|
case KeymapNotify:
|
|
case Expose:
|
|
case GraphicsExpose:
|
|
case NoExpose:
|
|
case MapNotify:
|
|
case UnmapNotify:
|
|
case VisibilityNotify:
|
|
case ResizeRequest:
|
|
case ColormapNotify:
|
|
case ClientMessage:
|
|
case CreateNotify:
|
|
case DestroyNotify:
|
|
case MapRequest:
|
|
case ReparentNotify:
|
|
case ConfigureNotify:
|
|
case ConfigureRequest:
|
|
case GravityNotify:
|
|
case CirculateNotify:
|
|
case CirculateRequest:
|
|
case MappingNotify:
|
|
default:
|
|
return META_CURRENT_TIME;
|
|
}
|
|
}
|
|
|
|
const char*
|
|
meta_event_detail_to_string (int d)
|
|
{
|
|
const char *detail = "???";
|
|
switch (d)
|
|
{
|
|
/* We are an ancestor in the A<->B focus change relationship */
|
|
case XINotifyAncestor:
|
|
detail = "NotifyAncestor";
|
|
break;
|
|
case XINotifyDetailNone:
|
|
detail = "NotifyDetailNone";
|
|
break;
|
|
/* We are a descendant in the A<->B focus change relationship */
|
|
case XINotifyInferior:
|
|
detail = "NotifyInferior";
|
|
break;
|
|
case XINotifyNonlinear:
|
|
detail = "NotifyNonlinear";
|
|
break;
|
|
case XINotifyNonlinearVirtual:
|
|
detail = "NotifyNonlinearVirtual";
|
|
break;
|
|
case XINotifyPointer:
|
|
detail = "NotifyPointer";
|
|
break;
|
|
case XINotifyPointerRoot:
|
|
detail = "NotifyPointerRoot";
|
|
break;
|
|
case XINotifyVirtual:
|
|
detail = "NotifyVirtual";
|
|
break;
|
|
}
|
|
|
|
return detail;
|
|
}
|
|
|
|
const char*
|
|
meta_event_mode_to_string (int m)
|
|
{
|
|
const char *mode = "???";
|
|
switch (m)
|
|
{
|
|
case XINotifyNormal:
|
|
mode = "NotifyNormal";
|
|
break;
|
|
case XINotifyGrab:
|
|
mode = "NotifyGrab";
|
|
break;
|
|
case XINotifyUngrab:
|
|
mode = "NotifyUngrab";
|
|
break;
|
|
case XINotifyWhileGrabbed:
|
|
mode = "NotifyWhileGrabbed";
|
|
break;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
G_GNUC_UNUSED static const char*
|
|
stack_mode_to_string (int mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case Above:
|
|
return "Above";
|
|
case Below:
|
|
return "Below";
|
|
case TopIf:
|
|
return "TopIf";
|
|
case BottomIf:
|
|
return "BottomIf";
|
|
case Opposite:
|
|
return "Opposite";
|
|
}
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
static gint64
|
|
sync_value_to_64 (const XSyncValue *value)
|
|
{
|
|
gint64 v;
|
|
|
|
v = XSyncValueLow32 (*value);
|
|
v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
|
|
|
|
return v;
|
|
}
|
|
|
|
static const char*
|
|
alarm_state_to_string (XSyncAlarmState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case XSyncAlarmActive:
|
|
return "Active";
|
|
case XSyncAlarmInactive:
|
|
return "Inactive";
|
|
case XSyncAlarmDestroyed:
|
|
return "Destroyed";
|
|
default:
|
|
return "(unknown)";
|
|
}
|
|
}
|
|
|
|
static const char *
|
|
get_xi2_event_name (XIEvent *input_event)
|
|
{
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_FocusIn:
|
|
return "XI_FocusIn";
|
|
case XI_FocusOut:
|
|
return "XI_FocusOut";
|
|
case XI_Enter:
|
|
return "XI_Enter";
|
|
case XI_Leave:
|
|
return "XI_Leave";
|
|
case XI_BarrierHit:
|
|
return "XI_BarrierHit";
|
|
case XI_BarrierLeave:
|
|
return "XI_BarrierLeave";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
meta_spew_xi2_event (MetaX11Display *x11_display,
|
|
XIEvent *input_event,
|
|
const char **name_p,
|
|
char **extra_p)
|
|
{
|
|
const char *name = NULL;
|
|
char *extra = NULL;
|
|
|
|
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
|
|
|
name = get_xi2_event_name (input_event);
|
|
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_FocusIn:
|
|
case XI_FocusOut:
|
|
extra = g_strdup_printf ("detail: %s mode: %s\n",
|
|
meta_event_detail_to_string (enter_event->detail),
|
|
meta_event_mode_to_string (enter_event->mode));
|
|
break;
|
|
case XI_Enter:
|
|
case XI_Leave:
|
|
extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g",
|
|
enter_event->event,
|
|
enter_event->root,
|
|
meta_event_mode_to_string (enter_event->mode),
|
|
meta_event_detail_to_string (enter_event->detail),
|
|
enter_event->focus,
|
|
enter_event->root_x,
|
|
enter_event->root_y);
|
|
break;
|
|
}
|
|
|
|
*name_p = name;
|
|
*extra_p = extra;
|
|
}
|
|
|
|
static const char *
|
|
get_core_event_name (XEvent *event)
|
|
{
|
|
/* GenericEvent is omitted here, as it's handled separately. */
|
|
switch (event->type)
|
|
{
|
|
case KeyPress:
|
|
return "KeyPress";
|
|
case KeyRelease:
|
|
return "KeyRelease";
|
|
case ButtonPress:
|
|
return "ButtonPress";
|
|
case ButtonRelease:
|
|
return "ButtonRelease";
|
|
case MotionNotify:
|
|
return "MotionNotify";
|
|
case EnterNotify:
|
|
return "EnterNotify";
|
|
case LeaveNotify:
|
|
return "LeaveNotify";
|
|
case FocusIn:
|
|
return "FocusIn";
|
|
case FocusOut:
|
|
return "FocusOut";
|
|
case KeymapNotify:
|
|
return "KeymapNotify";
|
|
case Expose:
|
|
return "Expose";
|
|
case GraphicsExpose:
|
|
return "GraphicsExpose";
|
|
case NoExpose:
|
|
return "NoExpose";
|
|
case VisibilityNotify:
|
|
return "VisibilityNotify";
|
|
case CreateNotify:
|
|
return "CreateNotify";
|
|
case DestroyNotify:
|
|
return "DestroyNotify";
|
|
case UnmapNotify:
|
|
return "UnmapNotify";
|
|
case MapNotify:
|
|
return "MapNotify";
|
|
case MapRequest:
|
|
return "MapRequest";
|
|
case ReparentNotify:
|
|
return "ReparentNotify";
|
|
case ConfigureNotify:
|
|
return "ConfigureNotify";
|
|
case ConfigureRequest:
|
|
return "ConfigureRequest";
|
|
case GravityNotify:
|
|
return "GravityNotify";
|
|
case ResizeRequest:
|
|
return "ResizeRequest";
|
|
case CirculateNotify:
|
|
return "CirculateNotify";
|
|
case CirculateRequest:
|
|
return "CirculateRequest";
|
|
case PropertyNotify:
|
|
return "PropertyNotify";
|
|
case SelectionClear:
|
|
return "SelectionClear";
|
|
case SelectionRequest:
|
|
return "SelectionRequest";
|
|
case SelectionNotify:
|
|
return "SelectionNotify";
|
|
case ColormapNotify:
|
|
return "ColormapNotify";
|
|
case ClientMessage:
|
|
return "ClientMessage";
|
|
case MappingNotify:
|
|
return "MappingNotify";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const char *
|
|
get_extension_event_name (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
|
return "XSyncAlarmNotify";
|
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
return "ShapeNotify";
|
|
|
|
if (META_X11_DISPLAY_HAS_DAMAGE (x11_display) &&
|
|
event->type == (x11_display->damage_event_base + XDamageNotify))
|
|
return "XDamageNotify";
|
|
|
|
if (event->type == (x11_display->xfixes_event_base + XFixesSelectionNotify))
|
|
return "XFixesSelectionNotify";
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const char *
|
|
get_event_name (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
const char *name;
|
|
XIEvent *input_event;
|
|
|
|
if (event->type < GenericEvent)
|
|
return get_core_event_name (event);
|
|
|
|
name = get_extension_event_name (x11_display, event);
|
|
if (name)
|
|
return name;
|
|
|
|
input_event = get_input_event (x11_display, event);
|
|
if (input_event)
|
|
{
|
|
name = get_xi2_event_name (input_event);
|
|
if (name)
|
|
return name;
|
|
}
|
|
|
|
return "Unknown event";
|
|
}
|
|
|
|
static void
|
|
meta_spew_core_event (MetaX11Display *x11_display,
|
|
XEvent *event,
|
|
const char **name_p,
|
|
char **extra_p)
|
|
{
|
|
const char *name = NULL;
|
|
char *extra = NULL;
|
|
|
|
name = get_core_event_name (event);
|
|
|
|
if (!name)
|
|
name = get_extension_event_name (x11_display, event);
|
|
|
|
switch (event->type)
|
|
{
|
|
case KeymapNotify:
|
|
case Expose:
|
|
case GraphicsExpose:
|
|
case NoExpose:
|
|
case VisibilityNotify:
|
|
case GravityNotify:
|
|
case CirculateNotify:
|
|
case CirculateRequest:
|
|
case SelectionClear:
|
|
case SelectionRequest:
|
|
case SelectionNotify:
|
|
case ColormapNotify:
|
|
break;
|
|
case CreateNotify:
|
|
extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
|
|
event->xcreatewindow.parent,
|
|
event->xcreatewindow.window);
|
|
break;
|
|
case DestroyNotify:
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
|
|
event->xdestroywindow.event,
|
|
event->xdestroywindow.window);
|
|
break;
|
|
case UnmapNotify:
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d",
|
|
event->xunmap.event,
|
|
event->xunmap.window,
|
|
event->xunmap.from_configure);
|
|
break;
|
|
case MapNotify:
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d",
|
|
event->xmap.event,
|
|
event->xmap.window,
|
|
event->xmap.override_redirect);
|
|
break;
|
|
case MapRequest:
|
|
extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
|
|
event->xmaprequest.window,
|
|
event->xmaprequest.parent);
|
|
break;
|
|
case ReparentNotify:
|
|
extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n",
|
|
event->xreparent.window,
|
|
event->xreparent.parent,
|
|
event->xreparent.event);
|
|
break;
|
|
case ConfigureNotify:
|
|
extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d",
|
|
event->xconfigure.x,
|
|
event->xconfigure.y,
|
|
event->xconfigure.width,
|
|
event->xconfigure.height,
|
|
event->xconfigure.above,
|
|
event->xconfigure.override_redirect);
|
|
break;
|
|
case ConfigureRequest:
|
|
extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s",
|
|
event->xconfigurerequest.parent,
|
|
event->xconfigurerequest.window,
|
|
event->xconfigurerequest.x,
|
|
event->xconfigurerequest.value_mask &
|
|
CWX ? "" : "(unset) ",
|
|
event->xconfigurerequest.y,
|
|
event->xconfigurerequest.value_mask &
|
|
CWY ? "" : "(unset) ",
|
|
event->xconfigurerequest.width,
|
|
event->xconfigurerequest.value_mask &
|
|
CWWidth ? "" : "(unset) ",
|
|
event->xconfigurerequest.height,
|
|
event->xconfigurerequest.value_mask &
|
|
CWHeight ? "" : "(unset) ",
|
|
event->xconfigurerequest.border_width,
|
|
event->xconfigurerequest.value_mask &
|
|
CWBorderWidth ? "" : "(unset)",
|
|
event->xconfigurerequest.above,
|
|
event->xconfigurerequest.value_mask &
|
|
CWSibling ? "" : "(unset)",
|
|
stack_mode_to_string (event->xconfigurerequest.detail),
|
|
event->xconfigurerequest.value_mask &
|
|
CWStackMode ? "" : "(unset)");
|
|
break;
|
|
case ResizeRequest:
|
|
extra = g_strdup_printf ("width = %d height = %d",
|
|
event->xresizerequest.width,
|
|
event->xresizerequest.height);
|
|
break;
|
|
case PropertyNotify:
|
|
{
|
|
char *str;
|
|
const char *state;
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
str = XGetAtomName (x11_display->xdisplay,
|
|
event->xproperty.atom);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
if (event->xproperty.state == PropertyNewValue)
|
|
state = "PropertyNewValue";
|
|
else if (event->xproperty.state == PropertyDelete)
|
|
state = "PropertyDelete";
|
|
else
|
|
state = "???";
|
|
|
|
extra = g_strdup_printf ("atom: %s state: %s",
|
|
str ? str : "(unknown atom)",
|
|
state);
|
|
meta_XFree (str);
|
|
}
|
|
break;
|
|
case ClientMessage:
|
|
{
|
|
char *str;
|
|
meta_x11_error_trap_push (x11_display);
|
|
str = XGetAtomName (x11_display->xdisplay,
|
|
event->xclient.message_type);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
extra = g_strdup_printf ("type: %s format: %d\n",
|
|
str ? str : "(unknown atom)",
|
|
event->xclient.format);
|
|
meta_XFree (str);
|
|
}
|
|
break;
|
|
case MappingNotify:
|
|
break;
|
|
default:
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
|
{
|
|
XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
|
|
|
|
extra =
|
|
g_strdup_printf ("alarm: 0x%lx"
|
|
" counter_value: %" G_GINT64_FORMAT
|
|
" alarm_value: %" G_GINT64_FORMAT
|
|
" time: %u alarm state: %s",
|
|
aevent->alarm,
|
|
(gint64) sync_value_to_64 (&aevent->counter_value),
|
|
(gint64) sync_value_to_64 (&aevent->alarm_value),
|
|
(unsigned int)aevent->time,
|
|
alarm_state_to_string (aevent->state));
|
|
}
|
|
else
|
|
{
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
{
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
|
|
extra =
|
|
g_strdup_printf ("kind: %s "
|
|
"x: %d y: %d w: %u h: %u "
|
|
"shaped: %d",
|
|
sev->kind == ShapeBounding ?
|
|
"ShapeBounding" :
|
|
(sev->kind == ShapeClip ?
|
|
"ShapeClip" : "(unknown)"),
|
|
sev->x, sev->y, sev->width, sev->height,
|
|
sev->shaped);
|
|
}
|
|
else
|
|
{
|
|
extra = g_strdup_printf ("type: %d", event->xany.type);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
*name_p = name;
|
|
*extra_p = extra;
|
|
}
|
|
|
|
static char *
|
|
meta_spew_event (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
const char *name = NULL;
|
|
char *extra = NULL;
|
|
char *winname;
|
|
char *ret;
|
|
XIEvent *input_event;
|
|
|
|
input_event = get_input_event (x11_display, event);
|
|
|
|
if (input_event)
|
|
meta_spew_xi2_event (x11_display, input_event, &name, &extra);
|
|
else
|
|
meta_spew_core_event (x11_display, event, &name, &extra);
|
|
|
|
if (event->xany.window == x11_display->xroot)
|
|
winname = g_strdup_printf ("root");
|
|
else
|
|
winname = g_strdup_printf ("0x%lx", event->xany.window);
|
|
|
|
ret = g_strdup_printf ("%s on %s%s %s %sserial %lu", name, winname,
|
|
extra ? ":" : "", extra ? extra : "",
|
|
event->xany.send_event ? "SEND " : "",
|
|
event->xany.serial);
|
|
|
|
g_free (winname);
|
|
g_free (extra);
|
|
|
|
return ret;
|
|
}
|
|
|
|
G_GNUC_UNUSED static void
|
|
meta_spew_event_print (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
char *event_str;
|
|
|
|
/* filter overnumerous events */
|
|
if (event->type == Expose || event->type == MotionNotify ||
|
|
event->type == NoExpose)
|
|
return;
|
|
|
|
if (event->type == (x11_display->damage_event_base + XDamageNotify))
|
|
return;
|
|
|
|
if (event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
|
return;
|
|
|
|
if (event->type == PropertyNotify &&
|
|
event->xproperty.atom == x11_display->atom__NET_WM_USER_TIME)
|
|
return;
|
|
|
|
event_str = meta_spew_event (x11_display, event);
|
|
g_print ("%s\n", event_str);
|
|
g_free (event_str);
|
|
}
|
|
|
|
static gboolean
|
|
handle_window_focus_event (MetaX11Display *x11_display,
|
|
MetaWindow *window,
|
|
XIEnterEvent *event,
|
|
unsigned long serial)
|
|
{
|
|
MetaDisplay *display = x11_display->display;
|
|
MetaWindow *focus_window;
|
|
#ifdef WITH_VERBOSE_MODE
|
|
const char *window_type;
|
|
|
|
/* Note the event can be on either the window or the frame,
|
|
* we focus the frame for shaded windows
|
|
*/
|
|
if (window)
|
|
{
|
|
if (event->event == window->xwindow)
|
|
window_type = "client window";
|
|
else if (window->frame && event->event == window->frame->xwindow)
|
|
window_type = "frame window";
|
|
else
|
|
window_type = "unknown client window";
|
|
}
|
|
else if (meta_x11_display_xwindow_is_a_no_focus_window (x11_display,
|
|
event->event))
|
|
window_type = "no_focus_window";
|
|
else if (event->event == x11_display->xroot)
|
|
window_type = "root window";
|
|
else
|
|
window_type = "unknown window";
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Focus %s event received on %s 0x%lx (%s) "
|
|
"mode %s detail %s serial %lu",
|
|
event->evtype == XI_FocusIn ? "in" :
|
|
event->evtype == XI_FocusOut ? "out" :
|
|
"???",
|
|
window ? window->desc : "",
|
|
event->event, window_type,
|
|
meta_event_mode_to_string (event->mode),
|
|
meta_event_detail_to_string (event->mode),
|
|
serial);
|
|
#endif
|
|
|
|
/* FIXME our pointer tracking is broken; see how
|
|
* gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c
|
|
* for how to handle it the correct way. In brief you need to track
|
|
* pointer focus and regular focus, and handle EnterNotify in
|
|
* PointerRoot mode with no window manager. However as noted above,
|
|
* accurate focus tracking will break things because we want to keep
|
|
* windows "focused" when using keybindings on them, and also we
|
|
* sometimes "focus" a window by focusing its frame or
|
|
* no_focus_window; so this all needs rethinking massively.
|
|
*
|
|
* My suggestion is to change it so that we clearly separate
|
|
* actual keyboard focus tracking using the xterm algorithm,
|
|
* and mutter's "pretend" focus window, and go through all
|
|
* the code and decide which one should be used in each place;
|
|
* a hard bit is deciding on a policy for that.
|
|
*
|
|
* http://bugzilla.gnome.org/show_bug.cgi?id=90382
|
|
*/
|
|
|
|
/* We ignore grabs, though this is questionable. It may be better to
|
|
* increase the intelligence of the focus window tracking.
|
|
*
|
|
* The problem is that keybindings for windows are done with
|
|
* XGrabKey, which means focus_window disappears and the front of
|
|
* the MRU list gets confused from what the user expects once a
|
|
* keybinding is used.
|
|
*/
|
|
|
|
if (event->mode == XINotifyGrab ||
|
|
event->mode == XINotifyUngrab ||
|
|
/* From WindowMaker, ignore all funky pointer root events */
|
|
event->detail > XINotifyNonlinearVirtual)
|
|
{
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Ignoring focus event generated by a grab or other weirdness");
|
|
return FALSE;
|
|
}
|
|
|
|
if (event->evtype == XI_FocusIn)
|
|
{
|
|
x11_display->server_focus_window = event->event;
|
|
x11_display->server_focus_serial = serial;
|
|
focus_window = window;
|
|
}
|
|
else if (event->evtype == XI_FocusOut)
|
|
{
|
|
if (event->detail == XINotifyInferior)
|
|
{
|
|
/* This event means the client moved focus to a subwindow */
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Ignoring focus out with NotifyInferior");
|
|
return FALSE;
|
|
}
|
|
|
|
x11_display->server_focus_window = None;
|
|
x11_display->server_focus_serial = serial;
|
|
focus_window = NULL;
|
|
}
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
/* If display->focused_by_us, then the focus_serial will be used only
|
|
* for a focus change we made and have already accounted for.
|
|
* (See request_xserver_input_focus_change().) Otherwise, we can get
|
|
* multiple focus events with the same serial.
|
|
*/
|
|
if (x11_display->server_focus_serial > x11_display->focus_serial ||
|
|
(!x11_display->focused_by_us &&
|
|
x11_display->server_focus_serial == x11_display->focus_serial))
|
|
{
|
|
meta_x11_display_update_focus_window (x11_display,
|
|
focus_window ?
|
|
focus_window->xwindow : None,
|
|
x11_display->server_focus_serial,
|
|
FALSE);
|
|
meta_display_update_focus_window (display, focus_window);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
crossing_serial_is_ignored (MetaX11Display *x11_display,
|
|
unsigned long serial)
|
|
{
|
|
int i;
|
|
|
|
i = 0;
|
|
while (i < N_IGNORED_CROSSING_SERIALS)
|
|
{
|
|
if (x11_display->display->ignored_crossing_serials[i] == serial)
|
|
return TRUE;
|
|
++i;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
handle_input_xevent (MetaX11Display *x11_display,
|
|
XIEvent *input_event,
|
|
unsigned long serial)
|
|
{
|
|
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
|
Window modified;
|
|
MetaWindow *window;
|
|
MetaDisplay *display = x11_display->display;
|
|
MetaWorkspaceManager *workspace_manager = display->workspace_manager;
|
|
MetaBackend *backend = meta_get_backend ();
|
|
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
|
|
|
if (input_event == NULL)
|
|
return FALSE;
|
|
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_Enter:
|
|
case XI_Leave:
|
|
case XI_FocusIn:
|
|
case XI_FocusOut:
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
modified = xievent_get_modified_window (x11_display, input_event);
|
|
window = modified != None ?
|
|
meta_x11_display_lookup_x_window (x11_display, modified) :
|
|
NULL;
|
|
|
|
/* If this is an event for a GTK+ widget, let GTK+ handle it. */
|
|
if (meta_ui_window_is_widget (x11_display->ui, modified))
|
|
return FALSE;
|
|
|
|
switch (input_event->evtype)
|
|
{
|
|
case XI_Enter:
|
|
if (display->event_route != META_EVENT_ROUTE_NORMAL)
|
|
break;
|
|
|
|
if (clutter_stage_get_grab_actor (stage) != NULL)
|
|
break;
|
|
|
|
/* Check if we've entered a window; do this even if window->has_focus to
|
|
* avoid races.
|
|
*/
|
|
if (window && !crossing_serial_is_ignored (x11_display, serial) &&
|
|
enter_event->mode != XINotifyGrab &&
|
|
enter_event->mode != XINotifyUngrab &&
|
|
enter_event->detail != XINotifyInferior &&
|
|
meta_x11_display_focus_sentinel_clear (x11_display))
|
|
{
|
|
meta_window_handle_enter (window,
|
|
enter_event->time,
|
|
enter_event->root_x,
|
|
enter_event->root_y);
|
|
}
|
|
break;
|
|
case XI_Leave:
|
|
if (display->event_route != META_EVENT_ROUTE_NORMAL)
|
|
break;
|
|
|
|
if (clutter_stage_get_grab_actor (stage) != NULL)
|
|
break;
|
|
|
|
if (window != NULL &&
|
|
enter_event->mode != XINotifyGrab &&
|
|
enter_event->mode != XINotifyUngrab)
|
|
{
|
|
meta_window_handle_leave (window);
|
|
}
|
|
break;
|
|
case XI_FocusIn:
|
|
case XI_FocusOut:
|
|
if (handle_window_focus_event (x11_display, window, enter_event, serial) &&
|
|
enter_event->event == enter_event->root)
|
|
{
|
|
if (enter_event->evtype == XI_FocusIn &&
|
|
enter_event->detail == XINotifyDetailNone)
|
|
{
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Focus got set to None, probably due to "
|
|
"brain-damage in the X protocol (see bug "
|
|
"125492). Setting the default focus window.");
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace,
|
|
NULL,
|
|
meta_x11_display_get_current_time_roundtrip (x11_display));
|
|
}
|
|
else if (enter_event->evtype == XI_FocusIn &&
|
|
enter_event->mode == XINotifyNormal &&
|
|
enter_event->detail == XINotifyInferior)
|
|
{
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Focus got set to root window, probably due to "
|
|
"gnome-session logout dialog usage (see bug "
|
|
"153220). Setting the default focus window.");
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace,
|
|
NULL,
|
|
meta_x11_display_get_current_time_roundtrip (x11_display));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Don't eat events for GTK frames (we need to update the :hover state on buttons) */
|
|
if (window && window->frame && modified == window->frame->xwindow)
|
|
return FALSE;
|
|
|
|
/* Don't pass these events through to Clutter / GTK+ */
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
process_request_frame_extents (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
/* The X window whose frame extents will be set. */
|
|
Window xwindow = event->xclient.window;
|
|
unsigned long data[4] = { 0, 0, 0, 0 };
|
|
|
|
MotifWmHints *hints = NULL;
|
|
gboolean hints_set = FALSE;
|
|
|
|
meta_verbose ("Setting frame extents for 0x%lx", xwindow);
|
|
|
|
/* See if the window is decorated. */
|
|
hints_set = meta_prop_get_motif_hints (x11_display,
|
|
xwindow,
|
|
x11_display->atom__MOTIF_WM_HINTS,
|
|
&hints);
|
|
if ((hints_set && hints->decorations) || !hints_set)
|
|
{
|
|
MetaFrameBorders borders;
|
|
|
|
/* Return estimated frame extents for a normal window. */
|
|
meta_ui_theme_get_frame_borders (x11_display->ui,
|
|
META_FRAME_TYPE_NORMAL,
|
|
0,
|
|
&borders);
|
|
data[0] = borders.visible.left;
|
|
data[1] = borders.visible.right;
|
|
data[2] = borders.visible.top;
|
|
data[3] = borders.visible.bottom;
|
|
}
|
|
|
|
meta_topic (META_DEBUG_GEOMETRY,
|
|
"Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx "
|
|
"to top = %lu, left = %lu, bottom = %lu, right = %lu",
|
|
xwindow, data[0], data[1], data[2], data[3]);
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
XChangeProperty (x11_display->xdisplay, xwindow,
|
|
x11_display->atom__NET_FRAME_EXTENTS,
|
|
XA_CARDINAL,
|
|
32, PropModeReplace, (guchar*) data, 4);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
g_free (hints);
|
|
}
|
|
|
|
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
|
|
static gboolean
|
|
convert_property (MetaX11Display *x11_display,
|
|
Window w,
|
|
Atom target,
|
|
Atom property)
|
|
{
|
|
#define N_TARGETS 4
|
|
Atom conversion_targets[N_TARGETS];
|
|
long icccm_version[] = { 2, 0 };
|
|
|
|
conversion_targets[0] = x11_display->atom_TARGETS;
|
|
conversion_targets[1] = x11_display->atom_MULTIPLE;
|
|
conversion_targets[2] = x11_display->atom_TIMESTAMP;
|
|
conversion_targets[3] = x11_display->atom_VERSION;
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
if (target == x11_display->atom_TARGETS)
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
|
XA_ATOM, 32, PropModeReplace,
|
|
(unsigned char *)conversion_targets, N_TARGETS);
|
|
else if (target == x11_display->atom_TIMESTAMP)
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
|
XA_INTEGER, 32, PropModeReplace,
|
|
(unsigned char *)&x11_display->wm_sn_timestamp, 1);
|
|
else if (target == x11_display->atom_VERSION)
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
|
XA_INTEGER, 32, PropModeReplace,
|
|
(unsigned char *)icccm_version, 2);
|
|
else
|
|
{
|
|
meta_x11_error_trap_pop_with_return (x11_display);
|
|
return FALSE;
|
|
}
|
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
|
|
return FALSE;
|
|
|
|
/* Be sure the PropertyNotify has arrived so we
|
|
* can send SelectionNotify
|
|
*/
|
|
/* FIXME the error trap pop synced anyway, right? */
|
|
meta_topic (META_DEBUG_SYNC, "Syncing on %s", G_STRFUNC);
|
|
XSync (x11_display->xdisplay, False);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
|
|
static void
|
|
process_selection_request (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
XSelectionEvent reply;
|
|
|
|
if (x11_display->wm_sn_selection_window != event->xselectionrequest.owner ||
|
|
x11_display->wm_sn_atom != event->xselectionrequest.selection)
|
|
{
|
|
char *str;
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
str = XGetAtomName (x11_display->xdisplay,
|
|
event->xselectionrequest.selection);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize",
|
|
str ? str : "(bad atom)", event->xselectionrequest.owner);
|
|
|
|
meta_XFree (str);
|
|
|
|
return;
|
|
}
|
|
|
|
reply.type = SelectionNotify;
|
|
reply.display = x11_display->xdisplay;
|
|
reply.requestor = event->xselectionrequest.requestor;
|
|
reply.selection = event->xselectionrequest.selection;
|
|
reply.target = event->xselectionrequest.target;
|
|
reply.property = None;
|
|
reply.time = event->xselectionrequest.time;
|
|
|
|
if (event->xselectionrequest.target == x11_display->atom_MULTIPLE)
|
|
{
|
|
if (event->xselectionrequest.property != None)
|
|
{
|
|
Atom type, *adata;
|
|
int i, format;
|
|
unsigned long num, rest;
|
|
unsigned char *data;
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
if (XGetWindowProperty (x11_display->xdisplay,
|
|
event->xselectionrequest.requestor,
|
|
event->xselectionrequest.property, 0, 256, False,
|
|
x11_display->atom_ATOM_PAIR,
|
|
&type, &format, &num, &rest, &data) != Success)
|
|
{
|
|
meta_x11_error_trap_pop_with_return (x11_display);
|
|
return;
|
|
}
|
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) == Success)
|
|
{
|
|
/* FIXME: to be 100% correct, should deal with rest > 0,
|
|
* but since we have 4 possible targets, we will hardly ever
|
|
* meet multiple requests with a length > 8
|
|
*/
|
|
adata = (Atom*)data;
|
|
i = 0;
|
|
while (i < (int) num)
|
|
{
|
|
if (!convert_property (x11_display,
|
|
event->xselectionrequest.requestor,
|
|
adata[i], adata[i+1]))
|
|
adata[i+1] = None;
|
|
i += 2;
|
|
}
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
XChangeProperty (x11_display->xdisplay,
|
|
event->xselectionrequest.requestor,
|
|
event->xselectionrequest.property,
|
|
x11_display->atom_ATOM_PAIR,
|
|
32, PropModeReplace, data, num);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
meta_XFree (data);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (event->xselectionrequest.property == None)
|
|
event->xselectionrequest.property = event->xselectionrequest.target;
|
|
|
|
if (convert_property (x11_display,
|
|
event->xselectionrequest.requestor,
|
|
event->xselectionrequest.target,
|
|
event->xselectionrequest.property))
|
|
reply.property = event->xselectionrequest.property;
|
|
}
|
|
|
|
XSendEvent (x11_display->xdisplay,
|
|
event->xselectionrequest.requestor,
|
|
False, 0L, (XEvent*)&reply);
|
|
|
|
meta_verbose ("Handled selection request");
|
|
}
|
|
|
|
static gboolean
|
|
close_display_idle_cb (gpointer user_data)
|
|
{
|
|
MetaX11Display *x11_display = META_X11_DISPLAY (user_data);
|
|
MetaDisplay *display = x11_display->display;
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
meta_display_close (display,
|
|
x11_display->xselectionclear_timestamp);
|
|
x11_display->display_close_idle = 0;
|
|
meta_context_terminate (context);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static gboolean
|
|
process_selection_clear (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
if (x11_display->wm_sn_selection_window != event->xselectionclear.window ||
|
|
x11_display->wm_sn_atom != event->xselectionclear.selection)
|
|
{
|
|
char *str;
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
str = XGetAtomName (x11_display->xdisplay,
|
|
event->xselectionclear.selection);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize",
|
|
str ? str : "(bad atom)", event->xselectionclear.window);
|
|
|
|
meta_XFree (str);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
meta_verbose ("Got selection clear for on display %s",
|
|
x11_display->name);
|
|
|
|
/* We can't close a GdkDisplay in an even handler. */
|
|
if (!x11_display->display_close_idle)
|
|
{
|
|
x11_display->xselectionclear_timestamp = event->xselectionclear.time;
|
|
x11_display->display_close_idle = g_idle_add (close_display_idle_cb, x11_display);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
notify_bell (MetaX11Display *x11_display,
|
|
XkbAnyEvent *xkb_ev)
|
|
{
|
|
MetaDisplay *display = x11_display->display;
|
|
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
|
|
MetaWindow *window;
|
|
|
|
window = meta_x11_display_lookup_x_window (x11_display,
|
|
xkb_bell_event->window);
|
|
if (!window && display->focus_window && display->focus_window->frame)
|
|
window = display->focus_window;
|
|
|
|
x11_display->last_bell_time = xkb_ev->time;
|
|
if (!meta_bell_notify (display, window) &&
|
|
meta_prefs_bell_is_audible ())
|
|
{
|
|
/* Force a classic bell if the libcanberra bell failed. */
|
|
XkbForceDeviceBell (x11_display->xdisplay,
|
|
xkb_bell_event->device,
|
|
xkb_bell_event->bell_class,
|
|
xkb_bell_event->bell_id,
|
|
xkb_bell_event->percent);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
handle_other_xevent (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
MetaDisplay *display = x11_display->display;
|
|
MetaWorkspaceManager *workspace_manager = display->workspace_manager;
|
|
Window modified;
|
|
MetaWindow *window;
|
|
MetaWindow *property_for_window;
|
|
gboolean frame_was_receiver;
|
|
gboolean bypass_gtk = FALSE;
|
|
|
|
modified = event_get_modified_window (x11_display, event);
|
|
window = modified != None ? meta_x11_display_lookup_x_window (x11_display, modified) : NULL;
|
|
frame_was_receiver = (window && window->frame && modified == window->frame->xwindow);
|
|
|
|
/* We only want to respond to _NET_WM_USER_TIME property notify
|
|
* events on _NET_WM_USER_TIME_WINDOW windows; in particular,
|
|
* responding to UnmapNotify events is kind of bad.
|
|
*/
|
|
property_for_window = NULL;
|
|
if (window && modified == window->user_time_window)
|
|
{
|
|
property_for_window = window;
|
|
window = NULL;
|
|
}
|
|
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
|
{
|
|
MetaWindow *alarm_window = meta_x11_display_lookup_sync_alarm (x11_display,
|
|
((XSyncAlarmNotifyEvent*)event)->alarm);
|
|
|
|
if (alarm_window != NULL)
|
|
{
|
|
XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value;
|
|
gint64 new_counter_value;
|
|
new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32);
|
|
meta_window_x11_update_sync_request_counter (alarm_window, new_counter_value);
|
|
bypass_gtk = TRUE; /* GTK doesn't want to see this really */
|
|
}
|
|
else
|
|
{
|
|
if (x11_display->alarm_filter &&
|
|
x11_display->alarm_filter (x11_display,
|
|
(XSyncAlarmNotifyEvent*)event,
|
|
x11_display->alarm_filter_data))
|
|
bypass_gtk = TRUE;
|
|
}
|
|
|
|
goto out;
|
|
}
|
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
{
|
|
bypass_gtk = TRUE; /* GTK doesn't want to see this really */
|
|
|
|
if (window && !frame_was_receiver)
|
|
{
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
|
|
if (sev->kind == ShapeBounding)
|
|
meta_window_x11_update_shape_region (window);
|
|
else if (sev->kind == ShapeInput)
|
|
meta_window_x11_update_input_region (window);
|
|
}
|
|
else
|
|
{
|
|
meta_topic (META_DEBUG_SHAPES,
|
|
"ShapeNotify not on a client window (window %s frame_was_receiver = %d)",
|
|
window ? window->desc : "(none)",
|
|
frame_was_receiver);
|
|
}
|
|
|
|
goto out;
|
|
}
|
|
|
|
switch (event->type)
|
|
{
|
|
case KeymapNotify:
|
|
break;
|
|
case Expose:
|
|
break;
|
|
case GraphicsExpose:
|
|
break;
|
|
case NoExpose:
|
|
break;
|
|
case VisibilityNotify:
|
|
break;
|
|
case CreateNotify:
|
|
{
|
|
if (event->xcreatewindow.parent == x11_display->xroot)
|
|
meta_stack_tracker_create_event (display->stack_tracker,
|
|
&event->xcreatewindow);
|
|
}
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
{
|
|
if (event->xdestroywindow.event == x11_display->xroot)
|
|
meta_stack_tracker_destroy_event (display->stack_tracker,
|
|
&event->xdestroywindow);
|
|
}
|
|
if (window)
|
|
{
|
|
/* FIXME: It sucks that DestroyNotify events don't come with
|
|
* a timestamp; could we do something better here? Maybe X
|
|
* will change one day?
|
|
*/
|
|
guint32 timestamp;
|
|
timestamp = meta_display_get_current_time_roundtrip (display);
|
|
|
|
if (display->grab_op != META_GRAB_OP_NONE &&
|
|
display->grab_window == window)
|
|
meta_display_end_grab_op (display, timestamp);
|
|
|
|
if (frame_was_receiver)
|
|
{
|
|
meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug",
|
|
window->frame->xwindow);
|
|
meta_x11_error_trap_push (x11_display);
|
|
meta_window_destroy_frame (window->frame->window);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
}
|
|
else
|
|
{
|
|
/* Unmanage destroyed window */
|
|
meta_window_unmanage (window, timestamp);
|
|
window = NULL;
|
|
}
|
|
}
|
|
break;
|
|
case UnmapNotify:
|
|
if (window)
|
|
{
|
|
/* FIXME: It sucks that UnmapNotify events don't come with
|
|
* a timestamp; could we do something better here? Maybe X
|
|
* will change one day?
|
|
*/
|
|
guint32 timestamp;
|
|
timestamp = meta_display_get_current_time_roundtrip (display);
|
|
|
|
if (display->grab_op != META_GRAB_OP_NONE &&
|
|
display->grab_window == window &&
|
|
window->frame == NULL)
|
|
meta_display_end_grab_op (display, timestamp);
|
|
|
|
if (!frame_was_receiver)
|
|
{
|
|
if (window->unmaps_pending == 0)
|
|
{
|
|
meta_topic (META_DEBUG_WINDOW_STATE,
|
|
"Window %s withdrawn",
|
|
window->desc);
|
|
|
|
/* Unmanage withdrawn window */
|
|
window->withdrawn = TRUE;
|
|
meta_window_unmanage (window, timestamp);
|
|
window = NULL;
|
|
}
|
|
else
|
|
{
|
|
window->unmaps_pending -= 1;
|
|
meta_topic (META_DEBUG_WINDOW_STATE,
|
|
"Received pending unmap, %d now pending",
|
|
window->unmaps_pending);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MapNotify:
|
|
/* NB: override redirect windows won't cause a map request so we
|
|
* watch out for map notifies against any root windows too if a
|
|
* compositor is enabled: */
|
|
if (window == NULL && event->xmap.event == x11_display->xroot)
|
|
{
|
|
window = meta_window_x11_new (display, event->xmap.window,
|
|
FALSE, META_COMP_EFFECT_CREATE);
|
|
}
|
|
else if (window && window->restore_focus_on_map &&
|
|
window->reparents_pending == 0)
|
|
{
|
|
meta_window_focus (window,
|
|
meta_display_get_current_time_roundtrip (display));
|
|
}
|
|
|
|
break;
|
|
case MapRequest:
|
|
if (window == NULL)
|
|
{
|
|
window = meta_window_x11_new (display, event->xmaprequest.window,
|
|
FALSE, META_COMP_EFFECT_CREATE);
|
|
/* The window might have initial iconic state, but this is a
|
|
* MapRequest, fall through to ensure it is unminimized in
|
|
* that case.
|
|
*/
|
|
}
|
|
else if (frame_was_receiver)
|
|
{
|
|
meta_warning ("Map requests on the frame window are unexpected");
|
|
break;
|
|
}
|
|
|
|
/* Double check that creating the MetaWindow succeeded */
|
|
if (window == NULL)
|
|
break;
|
|
|
|
meta_verbose ("MapRequest on %s mapped = %d minimized = %d",
|
|
window->desc, window->mapped, window->minimized);
|
|
|
|
if (window->minimized)
|
|
{
|
|
meta_window_unminimize (window);
|
|
if (window->workspace != workspace_manager->active_workspace)
|
|
{
|
|
meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d",
|
|
window->mapped, window->minimized);
|
|
meta_window_change_workspace (window,
|
|
workspace_manager->active_workspace);
|
|
}
|
|
}
|
|
break;
|
|
case ReparentNotify:
|
|
{
|
|
if (window && window->reparents_pending > 0)
|
|
window->reparents_pending -= 1;
|
|
if (event->xreparent.event == x11_display->xroot)
|
|
meta_stack_tracker_reparent_event (display->stack_tracker,
|
|
&event->xreparent);
|
|
}
|
|
break;
|
|
case ConfigureNotify:
|
|
if (event->xconfigure.event != event->xconfigure.window)
|
|
{
|
|
if (event->xconfigure.event == x11_display->xroot &&
|
|
event->xconfigure.window != x11_display->composite_overlay_window)
|
|
meta_stack_tracker_configure_event (display->stack_tracker,
|
|
&event->xconfigure);
|
|
}
|
|
|
|
if (window && window->override_redirect)
|
|
meta_window_x11_configure_notify (window, &event->xconfigure);
|
|
|
|
break;
|
|
case ConfigureRequest:
|
|
/* This comment and code is found in both twm and fvwm */
|
|
/*
|
|
* According to the July 27, 1988 ICCCM draft, we should ignore size and
|
|
* position fields in the WM_NORMAL_HINTS property when we map a window.
|
|
* Instead, we'll read the current geometry. Therefore, we should respond
|
|
* to configuration requests for windows which have never been mapped.
|
|
*/
|
|
if (window == NULL)
|
|
{
|
|
unsigned int xwcm;
|
|
XWindowChanges xwc;
|
|
|
|
xwcm = event->xconfigurerequest.value_mask &
|
|
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
|
|
|
|
xwc.x = event->xconfigurerequest.x;
|
|
xwc.y = event->xconfigurerequest.y;
|
|
xwc.width = event->xconfigurerequest.width;
|
|
xwc.height = event->xconfigurerequest.height;
|
|
xwc.border_width = event->xconfigurerequest.border_width;
|
|
|
|
meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)",
|
|
xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
|
|
meta_x11_error_trap_push (x11_display);
|
|
XConfigureWindow (x11_display->xdisplay, event->xconfigurerequest.window,
|
|
xwcm, &xwc);
|
|
meta_x11_error_trap_pop (x11_display);
|
|
}
|
|
else
|
|
{
|
|
if (!frame_was_receiver)
|
|
meta_window_x11_configure_request (window, event);
|
|
}
|
|
break;
|
|
case GravityNotify:
|
|
break;
|
|
case ResizeRequest:
|
|
break;
|
|
case CirculateNotify:
|
|
break;
|
|
case CirculateRequest:
|
|
break;
|
|
case PropertyNotify:
|
|
{
|
|
MetaGroup *group;
|
|
|
|
if (window && !frame_was_receiver)
|
|
meta_window_x11_property_notify (window, event);
|
|
else if (property_for_window && !frame_was_receiver)
|
|
meta_window_x11_property_notify (property_for_window, event);
|
|
|
|
group = meta_x11_display_lookup_group (x11_display,
|
|
event->xproperty.window);
|
|
if (group != NULL)
|
|
meta_group_property_notify (group, event);
|
|
|
|
if (event->xproperty.window == x11_display->xroot)
|
|
{
|
|
if (event->xproperty.atom ==
|
|
x11_display->atom__NET_DESKTOP_LAYOUT)
|
|
meta_x11_display_update_workspace_layout (x11_display);
|
|
else if (event->xproperty.atom ==
|
|
x11_display->atom__NET_DESKTOP_NAMES)
|
|
meta_x11_display_update_workspace_names (x11_display);
|
|
|
|
/* we just use this property as a sentinel to avoid
|
|
* certain race conditions. See the comment for the
|
|
* sentinel_counter variable declaration in display.h
|
|
*/
|
|
if (event->xproperty.atom ==
|
|
x11_display->atom__MUTTER_SENTINEL)
|
|
{
|
|
meta_x11_display_decrement_focus_sentinel (x11_display);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SelectionRequest:
|
|
process_selection_request (x11_display, event);
|
|
break;
|
|
case SelectionNotify:
|
|
break;
|
|
case ColormapNotify:
|
|
break;
|
|
case ClientMessage:
|
|
if (window)
|
|
{
|
|
#ifdef HAVE_WAYLAND
|
|
if (event->xclient.message_type == x11_display->atom_WL_SURFACE_ID)
|
|
{
|
|
guint32 surface_id = event->xclient.data.l[0];
|
|
meta_xwayland_handle_wl_surface_id (window, surface_id);
|
|
}
|
|
else if (event->xclient.message_type ==
|
|
x11_display->atom__XWAYLAND_MAY_GRAB_KEYBOARD)
|
|
{
|
|
if (meta_is_wayland_compositor ())
|
|
g_object_set (G_OBJECT (window),
|
|
"xwayland-may-grab-keyboard", (event->xclient.data.l[0] != 0),
|
|
NULL);
|
|
}
|
|
else
|
|
#endif
|
|
if (!frame_was_receiver)
|
|
meta_window_x11_client_message (window, event);
|
|
}
|
|
else
|
|
{
|
|
if (event->xclient.window == x11_display->xroot)
|
|
{
|
|
if (event->xclient.message_type ==
|
|
x11_display->atom__NET_CURRENT_DESKTOP)
|
|
{
|
|
int space;
|
|
MetaWorkspace *workspace;
|
|
guint32 time;
|
|
|
|
space = event->xclient.data.l[0];
|
|
time = event->xclient.data.l[1];
|
|
|
|
meta_verbose ("Request to change current workspace to %d with "
|
|
"specified timestamp of %u",
|
|
space, time);
|
|
|
|
workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, space);
|
|
|
|
if (workspace)
|
|
{
|
|
/* Handle clients using the older version of the spec... */
|
|
if (time == 0)
|
|
time = meta_x11_display_get_current_time_roundtrip (x11_display);
|
|
|
|
meta_workspace_activate (workspace, time);
|
|
}
|
|
else
|
|
{
|
|
meta_verbose ("Don't know about workspace %d", space);
|
|
}
|
|
}
|
|
else if (event->xclient.message_type ==
|
|
x11_display->atom__NET_NUMBER_OF_DESKTOPS)
|
|
{
|
|
int num_spaces;
|
|
|
|
num_spaces = event->xclient.data.l[0];
|
|
|
|
meta_verbose ("Request to set number of workspaces to %d",
|
|
num_spaces);
|
|
|
|
meta_prefs_set_num_workspaces (num_spaces);
|
|
}
|
|
else if (event->xclient.message_type ==
|
|
x11_display->atom__NET_SHOWING_DESKTOP)
|
|
{
|
|
gboolean showing_desktop;
|
|
guint32 timestamp;
|
|
|
|
showing_desktop = event->xclient.data.l[0] != 0;
|
|
/* FIXME: Braindead protocol doesn't have a timestamp */
|
|
timestamp = meta_x11_display_get_current_time_roundtrip (x11_display);
|
|
meta_verbose ("Request to %s desktop",
|
|
showing_desktop ? "show" : "hide");
|
|
|
|
if (showing_desktop)
|
|
meta_workspace_manager_show_desktop (workspace_manager, timestamp);
|
|
else
|
|
{
|
|
meta_workspace_manager_unshow_desktop (workspace_manager);
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace, NULL, timestamp);
|
|
}
|
|
}
|
|
else if (event->xclient.message_type ==
|
|
x11_display->atom_WM_PROTOCOLS)
|
|
{
|
|
meta_verbose ("Received WM_PROTOCOLS message");
|
|
|
|
if ((Atom)event->xclient.data.l[0] == x11_display->atom__NET_WM_PING)
|
|
{
|
|
guint32 timestamp = event->xclient.data.l[1];
|
|
|
|
meta_display_pong_for_serial (display, timestamp);
|
|
|
|
/* We don't want ping reply events going into
|
|
* the GTK+ event loop because gtk+ will treat
|
|
* them as ping requests and send more replies.
|
|
*/
|
|
bypass_gtk = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (event->xclient.message_type ==
|
|
x11_display->atom__NET_REQUEST_FRAME_EXTENTS)
|
|
{
|
|
meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message");
|
|
process_request_frame_extents (x11_display, event);
|
|
}
|
|
}
|
|
break;
|
|
case MappingNotify:
|
|
{
|
|
gboolean ignore_current;
|
|
|
|
ignore_current = FALSE;
|
|
|
|
/* Check whether the next event is an identical MappingNotify
|
|
* event. If it is, ignore the current event, we'll update
|
|
* when we get the next one.
|
|
*/
|
|
if (XPending (x11_display->xdisplay))
|
|
{
|
|
XEvent next_event;
|
|
|
|
XPeekEvent (x11_display->xdisplay, &next_event);
|
|
|
|
if (next_event.type == MappingNotify &&
|
|
next_event.xmapping.request == event->xmapping.request)
|
|
ignore_current = TRUE;
|
|
}
|
|
|
|
if (!ignore_current)
|
|
{
|
|
/* Let XLib know that there is a new keyboard mapping.
|
|
*/
|
|
XRefreshKeyboardMapping (&event->xmapping);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (event->type == x11_display->xkb_base_event_type)
|
|
{
|
|
XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
|
|
|
|
switch (xkb_ev->xkb_type)
|
|
{
|
|
case XkbBellNotify:
|
|
if (XSERVER_TIME_IS_BEFORE(x11_display->last_bell_time,
|
|
xkb_ev->time - 100))
|
|
{
|
|
notify_bell (x11_display, xkb_ev);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
out:
|
|
return bypass_gtk;
|
|
}
|
|
|
|
static gboolean
|
|
window_has_xwindow (MetaWindow *window,
|
|
Window xwindow)
|
|
{
|
|
if (window->xwindow == xwindow)
|
|
return TRUE;
|
|
|
|
if (window->frame && window->frame->xwindow == xwindow)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
process_selection_event (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
gboolean handled = FALSE;
|
|
GList *l;
|
|
|
|
handled |= meta_x11_selection_handle_event (x11_display, event);
|
|
|
|
for (l = x11_display->selection.input_streams; l && !handled;)
|
|
{
|
|
GList *next = l->next;
|
|
|
|
handled |= meta_x11_selection_input_stream_xevent (l->data, event);
|
|
l = next;
|
|
}
|
|
|
|
for (l = x11_display->selection.output_streams; l && !handled;)
|
|
{
|
|
GList *next = l->next;
|
|
|
|
handled |= meta_x11_selection_output_stream_xevent (l->data, event);
|
|
l = next;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
/**
|
|
* meta_display_handle_xevent:
|
|
* @display: The MetaDisplay that events are coming from
|
|
* @event: The event that just happened
|
|
*
|
|
* This is the most important function in the whole program. It is the heart,
|
|
* it is the nexus, it is the Grand Central Station of Mutter's world.
|
|
* When we create a #MetaDisplay, we ask GDK to pass *all* events for *all*
|
|
* windows to this function. So every time anything happens that we might
|
|
* want to know about, this function gets called. You see why it gets a bit
|
|
* busy around here. Most of this function is a ginormous switch statement
|
|
* dealing with all the kinds of events that might turn up.
|
|
*/
|
|
static gboolean
|
|
meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
|
XEvent *event)
|
|
{
|
|
MetaDisplay *display = x11_display->display;
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Window modified;
|
|
gboolean bypass_compositor = FALSE, bypass_gtk = FALSE;
|
|
XIEvent *input_event;
|
|
MetaCursorTracker *cursor_tracker;
|
|
|
|
COGL_TRACE_BEGIN (MetaX11DisplayHandleXevent,
|
|
"X11Display (handle X11 event)");
|
|
|
|
#if 0
|
|
meta_spew_event_print (x11_display, event);
|
|
#endif
|
|
|
|
if (meta_x11_startup_notification_handle_xevent (x11_display, event))
|
|
{
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
#ifdef HAVE_WAYLAND
|
|
if (meta_is_wayland_compositor () &&
|
|
meta_xwayland_handle_xevent (event))
|
|
{
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
if (process_selection_event (x11_display, event))
|
|
{
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
display->current_time = event_get_time (x11_display, event);
|
|
|
|
if (META_IS_BACKEND_X11 (backend))
|
|
meta_backend_x11_handle_event (META_BACKEND_X11 (backend), event);
|
|
|
|
if (x11_display->focused_by_us &&
|
|
event->xany.serial > x11_display->focus_serial &&
|
|
display->focus_window &&
|
|
!window_has_xwindow (display->focus_window, x11_display->server_focus_window))
|
|
{
|
|
meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed",
|
|
display->focus_window->desc);
|
|
meta_x11_display_update_focus_window (x11_display,
|
|
x11_display->server_focus_window,
|
|
x11_display->server_focus_serial,
|
|
FALSE);
|
|
meta_display_update_focus_window (display,
|
|
meta_x11_display_lookup_x_window (x11_display,
|
|
x11_display->server_focus_window));
|
|
}
|
|
|
|
if (event->xany.window == x11_display->xroot)
|
|
{
|
|
cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
|
if (META_IS_CURSOR_TRACKER_X11 (cursor_tracker))
|
|
{
|
|
MetaCursorTrackerX11 *cursor_tracker_x11 =
|
|
META_CURSOR_TRACKER_X11 (cursor_tracker);
|
|
|
|
if (meta_cursor_tracker_x11_handle_xevent (cursor_tracker_x11, event))
|
|
{
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
modified = event_get_modified_window (x11_display, event);
|
|
|
|
input_event = get_input_event (x11_display, event);
|
|
|
|
if (event->type == UnmapNotify)
|
|
{
|
|
if (meta_ui_window_should_not_cause_focus (x11_display->xdisplay,
|
|
modified))
|
|
{
|
|
meta_display_add_ignored_crossing_serial (display, event->xany.serial);
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
"Adding EnterNotify serial %lu to ignored focus serials",
|
|
event->xany.serial);
|
|
}
|
|
}
|
|
|
|
if (handle_input_xevent (x11_display, input_event, event->xany.serial))
|
|
{
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
if (handle_other_xevent (x11_display, event))
|
|
{
|
|
bypass_gtk = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
if (event->type == SelectionClear)
|
|
{
|
|
if (process_selection_clear (x11_display, event))
|
|
{
|
|
bypass_gtk = TRUE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
if (!bypass_compositor && META_IS_COMPOSITOR_X11 (display->compositor))
|
|
{
|
|
MetaCompositorX11 *compositor_x11 =
|
|
META_COMPOSITOR_X11 (display->compositor);
|
|
MetaWindow *window;
|
|
|
|
if (modified != None)
|
|
window = meta_x11_display_lookup_x_window (x11_display, modified);
|
|
else
|
|
window = NULL;
|
|
|
|
meta_compositor_x11_process_xevent (compositor_x11, event, window);
|
|
}
|
|
|
|
display->current_time = META_CURRENT_TIME;
|
|
|
|
COGL_TRACE_DESCRIBE (MetaX11DisplayHandleXevent,
|
|
get_event_name (x11_display, event));
|
|
COGL_TRACE_END (MetaX11DisplayHandleXevent);
|
|
|
|
return bypass_gtk;
|
|
}
|
|
|
|
|
|
static GdkFilterReturn
|
|
xevent_filter (GdkXEvent *xevent,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
MetaX11Display *x11_display = data;
|
|
|
|
if (meta_x11_display_handle_xevent (x11_display, xevent))
|
|
return GDK_FILTER_REMOVE;
|
|
else
|
|
return GDK_FILTER_CONTINUE;
|
|
}
|
|
|
|
void
|
|
meta_x11_display_init_events (MetaX11Display *x11_display)
|
|
{
|
|
gdk_window_add_filter (NULL, xevent_filter, x11_display);
|
|
}
|
|
|
|
void
|
|
meta_x11_display_free_events (MetaX11Display *x11_display)
|
|
{
|
|
gdk_window_remove_filter (NULL, xevent_filter, x11_display);
|
|
}
|