[mutter] Move all X11 event processing to a new file in x11/
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] Move all X11 event processing to a new file in x11/
- Date: Wed, 11 Jun 2014 20:32:41 +0000 (UTC)
commit 53814fefc11a1c3d56a3d6ddd016dd07aa3cb527
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Wed Jun 11 16:08:33 2014 -0400
Move all X11 event processing to a new file in x11/
src/Makefile.am | 2 +
src/core/events.c | 1786 +---------------------------------------------------
src/core/events.h | 1 -
src/x11/events.c | 1821 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/x11/events.h | 31 +
5 files changed, 1858 insertions(+), 1783 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 7bebe04..6f7cf5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -191,6 +191,8 @@ libmutter_la_SOURCES = \
x11/iconcache.h \
x11/async-getprop.c \
x11/async-getprop.h \
+ x11/events.c \
+ x11/events.h \
x11/group-private.h \
x11/group-props.c \
x11/group-props.h \
diff --git a/src/core/events.c b/src/core/events.c
index c77b604..c5930a4 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -23,15 +23,8 @@
#include "config.h"
#include "events.h"
-#include <X11/Xatom.h>
-#include <X11/extensions/Xdamage.h>
-#include <X11/extensions/shape.h>
-
-#include <meta/errors.h>
#include "display-private.h"
#include "window-private.h"
-#include "bell.h"
-#include "workspace-private.h"
#include "backends/meta-backend.h"
#include "backends/x11/meta-backend-x11.h"
@@ -40,11 +33,9 @@
#include "backends/native/meta-idle-monitor-native.h"
#endif
-#include "x11/window-x11.h"
-#include "x11/xprops.h"
-#include "wayland/meta-xwayland.h"
+#include "x11/events.h"
#include "wayland/meta-wayland-private.h"
-#include "meta-surface-actor-wayland.h"
+#include "meta-surface-actor.h"
static MetaWindow *
get_window_for_event (MetaDisplay *display,
@@ -72,1762 +63,6 @@ get_window_for_event (MetaDisplay *display,
return NULL;
}
-static XIEvent *
-get_input_event (MetaDisplay *display,
- XEvent *event)
-{
- if (event->type == GenericEvent &&
- event->xcookie.extension == 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;
-#ifdef HAVE_XI23
- case XI_BarrierHit:
- case XI_BarrierLeave:
- if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
- return input_event;
- break;
-#endif /* HAVE_XI23 */
- default:
- break;
- }
- }
-
- return NULL;
-}
-
-static Window
-xievent_get_modified_window (MetaDisplay *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;
-#ifdef HAVE_XI23
- case XI_BarrierHit:
- case XI_BarrierLeave:
- return ((XIBarrierEvent *) input_event)->event;
-#endif /* HAVE_XI23 */
- }
-
- 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 (MetaDisplay *display,
- XEvent *event)
-{
- XIEvent *input_event = get_input_event (display, event);
-
- if (input_event)
- return xievent_get_modified_window (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_DISPLAY_HAS_SHAPE (display) &&
- event->type == (display->shape_event_base + ShapeNotify))
- {
- XShapeEvent *sev = (XShapeEvent*) event;
- return sev->window;
- }
-
- return None;
- }
-}
-
-static guint32
-event_get_time (MetaDisplay *display,
- XEvent *event)
-{
- XIEvent *input_event = get_input_event (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 CurrentTime;
- }
-}
-
-G_GNUC_UNUSED 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;
-}
-
-G_GNUC_UNUSED 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";
-}
-
-G_GNUC_UNUSED static gint64
-sync_value_to_64 (const XSyncValue *value)
-{
- gint64 v;
-
- v = XSyncValueLow32 (*value);
- v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
-
- return v;
-}
-
-G_GNUC_UNUSED 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)";
- }
-}
-
-G_GNUC_UNUSED static void
-meta_spew_xi2_event (MetaDisplay *display,
- XIEvent *input_event,
- const char **name_p,
- char **extra_p)
-{
- const char *name = NULL;
- char *extra = NULL;
-
- XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
-
- switch (input_event->evtype)
- {
- case XI_FocusIn:
- name = "XI_FocusIn";
- break;
- case XI_FocusOut:
- name = "XI_FocusOut";
- break;
- case XI_Enter:
- name = "XI_Enter";
- break;
- case XI_Leave:
- name = "XI_Leave";
- break;
-#ifdef HAVE_XI23
- case XI_BarrierHit:
- name = "XI_BarrierHit";
- break;
- case XI_BarrierLeave:
- name = "XI_BarrierLeave";
- break;
-#endif /* HAVE_XI23 */
- }
-
- 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;
-}
-
-G_GNUC_UNUSED static void
-meta_spew_core_event (MetaDisplay *display,
- XEvent *event,
- const char **name_p,
- char **extra_p)
-{
- const char *name = NULL;
- char *extra = NULL;
-
- switch (event->type)
- {
- case KeymapNotify:
- name = "KeymapNotify";
- break;
- case Expose:
- name = "Expose";
- break;
- case GraphicsExpose:
- name = "GraphicsExpose";
- break;
- case NoExpose:
- name = "NoExpose";
- break;
- case VisibilityNotify:
- name = "VisibilityNotify";
- break;
- case CreateNotify:
- name = "CreateNotify";
- extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
- event->xcreatewindow.parent,
- event->xcreatewindow.window);
- break;
- case DestroyNotify:
- name = "DestroyNotify";
- extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
- event->xdestroywindow.event,
- event->xdestroywindow.window);
- break;
- case UnmapNotify:
- name = "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:
- name = "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:
- name = "MapRequest";
- extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
- event->xmaprequest.window,
- event->xmaprequest.parent);
- break;
- case ReparentNotify:
- name = "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:
- name = "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:
- name = "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 GravityNotify:
- name = "GravityNotify";
- break;
- case ResizeRequest:
- name = "ResizeRequest";
- extra = g_strdup_printf ("width = %d height = %d",
- event->xresizerequest.width,
- event->xresizerequest.height);
- break;
- case CirculateNotify:
- name = "CirculateNotify";
- break;
- case CirculateRequest:
- name = "CirculateRequest";
- break;
- case PropertyNotify:
- {
- char *str;
- const char *state;
-
- name = "PropertyNotify";
-
- meta_error_trap_push (display);
- str = XGetAtomName (display->xdisplay,
- event->xproperty.atom);
- meta_error_trap_pop (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 SelectionClear:
- name = "SelectionClear";
- break;
- case SelectionRequest:
- name = "SelectionRequest";
- break;
- case SelectionNotify:
- name = "SelectionNotify";
- break;
- case ColormapNotify:
- name = "ColormapNotify";
- break;
- case ClientMessage:
- {
- char *str;
- name = "ClientMessage";
- meta_error_trap_push (display);
- str = XGetAtomName (display->xdisplay,
- event->xclient.message_type);
- meta_error_trap_pop (display);
- extra = g_strdup_printf ("type: %s format: %d\n",
- str ? str : "(unknown atom)",
- event->xclient.format);
- meta_XFree (str);
- }
- break;
- case MappingNotify:
- name = "MappingNotify";
- break;
- default:
- if (META_DISPLAY_HAS_XSYNC (display) &&
- event->type == (display->xsync_event_base + XSyncAlarmNotify))
- {
- XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
-
- name = "XSyncAlarmNotify";
- 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_DISPLAY_HAS_SHAPE (display) &&
- event->type == (display->shape_event_base + ShapeNotify))
- {
- XShapeEvent *sev = (XShapeEvent*) event;
-
- name = "ShapeNotify";
-
- 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
- {
- name = "(Unknown event)";
- extra = g_strdup_printf ("type: %d", event->xany.type);
- }
- break;
- }
-
- *name_p = name;
- *extra_p = extra;
-}
-
-G_GNUC_UNUSED static void
-meta_spew_event (MetaDisplay *display,
- XEvent *event)
-{
- MetaScreen *screen = display->screen;
- const char *name = NULL;
- char *extra = NULL;
- char *winname;
- XIEvent *input_event;
-
- /* filter overnumerous events */
- if (event->type == Expose || event->type == MotionNotify ||
- event->type == NoExpose)
- return;
-
- if (event->type == (display->damage_event_base + XDamageNotify))
- return;
-
- if (event->type == (display->xsync_event_base + XSyncAlarmNotify))
- return;
-
- if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME)
- return;
-
- input_event = get_input_event (display, event);
-
- if (input_event)
- meta_spew_xi2_event (display, input_event, &name, &extra);
- else
- meta_spew_core_event (display, event, &name, &extra);
-
- if (event->xany.window == screen->xroot)
- winname = g_strdup_printf ("root %d", screen->number);
- else
- winname = g_strdup_printf ("0x%lx", event->xany.window);
-
- g_print ("%s on %s%s %s %sserial %lu\n", name, winname,
- extra ? ":" : "", extra ? extra : "",
- event->xany.send_event ? "SEND " : "",
- event->xany.serial);
-
- g_free (winname);
-
- if (extra)
- g_free (extra);
-}
-
-static void
-handle_window_focus_event (MetaDisplay *display,
- MetaWindow *window,
- XIEnterEvent *event,
- unsigned long serial)
-{
- 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_display_xwindow_is_a_no_focus_window (display, event->event))
- window_type = "no_focus_window";
- else if (event->event == display->screen->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\n",
- 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),
- event->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\n");
- return;
- }
-
- if (event->evtype == XI_FocusIn)
- {
- display->server_focus_window = event->event;
- 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\n");
- return;
- }
-
- display->server_focus_window = None;
- display->server_focus_serial = serial;
- focus_window = NULL;
- }
- else
- g_return_if_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 (display->server_focus_serial > display->focus_serial ||
- (!display->focused_by_us &&
- display->server_focus_serial == display->focus_serial))
- {
- meta_display_update_focus_window (display,
- focus_window,
- focus_window ? focus_window->xwindow : None,
- display->server_focus_serial,
- FALSE);
- }
-}
-
-static gboolean
-crossing_serial_is_ignored (MetaDisplay *display,
- unsigned long serial)
-{
- int i;
-
- i = 0;
- while (i < N_IGNORED_CROSSING_SERIALS)
- {
- if (display->ignored_crossing_serials[i] == serial)
- return TRUE;
- ++i;
- }
- return FALSE;
-}
-
-static gboolean
-handle_input_xevent (MetaDisplay *display,
- XIEvent *input_event,
- gulong serial)
-{
- XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
- Window modified;
- MetaWindow *window;
- MetaScreen *screen = display->screen;
-
- 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 (display, input_event);
- window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
-
- /* If this is an event for a GTK+ widget, let GTK+ handle it. */
- if (meta_ui_window_is_widget (display->screen->ui, modified))
- return FALSE;
-
- switch (input_event->evtype)
- {
- case XI_Enter:
- if (display->grab_op == META_GRAB_OP_COMPOSITOR)
- break;
-
- /* Check if we've entered a window; do this even if window->has_focus to
- * avoid races.
- */
- if (window && !crossing_serial_is_ignored (display, serial) &&
- enter_event->mode != XINotifyGrab &&
- enter_event->mode != XINotifyUngrab &&
- enter_event->detail != XINotifyInferior &&
- meta_display_focus_sentinel_clear (display))
- {
- meta_window_handle_enter (window,
- enter_event->time,
- enter_event->root_x,
- enter_event->root_y);
- }
- break;
- case XI_Leave:
- if (display->grab_op == META_GRAB_OP_COMPOSITOR)
- break;
-
- if (window != NULL &&
- enter_event->mode != XINotifyGrab &&
- enter_event->mode != XINotifyUngrab)
- {
- meta_window_handle_leave (window);
- }
- break;
- case XI_FocusIn:
- case XI_FocusOut:
- handle_window_focus_event (display, window, enter_event, serial);
- if (!window)
- {
- /* Check if the window is a root window. */
- if (enter_event->root != enter_event->event)
- break;
-
- if (enter_event->evtype == XI_FocusIn &&
- enter_event->mode == 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.\n");
- meta_workspace_focus_default_window (screen->active_workspace,
- NULL,
- meta_display_get_current_time_roundtrip (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.\n");
- meta_workspace_focus_default_window (screen->active_workspace,
- NULL,
- meta_display_get_current_time_roundtrip (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
-reload_xkb_rules (MetaScreen *screen)
-{
- MetaWaylandCompositor *compositor;
- char **names;
- int n_names;
- gboolean ok;
- const char *rules, *model, *layout, *variant, *options;
-
- compositor = meta_wayland_compositor_get_default ();
-
- ok = meta_prop_get_latin1_list (screen->display, screen->xroot,
- screen->display->atom__XKB_RULES_NAMES,
- &names, &n_names);
- if (!ok)
- return;
-
- if (n_names != 5)
- goto out;
-
- rules = names[0];
- model = names[1];
- layout = names[2];
- variant = names[3];
- options = names[4];
-
- meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard,
- rules, model, layout, variant, options,
- META_WAYLAND_KEYBOARD_SKIP_XCLIENTS);
-
- out:
- g_strfreev (names);
-}
-
-static void
-process_request_frame_extents (MetaDisplay *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\n", xwindow);
-
- /* See if the window is decorated. */
- hints_set = meta_prop_get_motif_hints (display,
- xwindow,
- 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 (display->screen->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\n",
- xwindow, data[0], data[1], data[2], data[3]);
-
- meta_error_trap_push (display);
- XChangeProperty (display->xdisplay, xwindow,
- display->atom__NET_FRAME_EXTENTS,
- XA_CARDINAL,
- 32, PropModeReplace, (guchar*) data, 4);
- meta_error_trap_pop (display);
-
- meta_XFree (hints);
-}
-
-/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
-static gboolean
-convert_property (MetaDisplay *display,
- MetaScreen *screen,
- Window w,
- Atom target,
- Atom property)
-{
-#define N_TARGETS 4
- Atom conversion_targets[N_TARGETS];
- long icccm_version[] = { 2, 0 };
-
- conversion_targets[0] = display->atom_TARGETS;
- conversion_targets[1] = display->atom_MULTIPLE;
- conversion_targets[2] = display->atom_TIMESTAMP;
- conversion_targets[3] = display->atom_VERSION;
-
- meta_error_trap_push (display);
- if (target == display->atom_TARGETS)
- XChangeProperty (display->xdisplay, w, property,
- XA_ATOM, 32, PropModeReplace,
- (unsigned char *)conversion_targets, N_TARGETS);
- else if (target == display->atom_TIMESTAMP)
- XChangeProperty (display->xdisplay, w, property,
- XA_INTEGER, 32, PropModeReplace,
- (unsigned char *)&screen->wm_sn_timestamp, 1);
- else if (target == display->atom_VERSION)
- XChangeProperty (display->xdisplay, w, property,
- XA_INTEGER, 32, PropModeReplace,
- (unsigned char *)icccm_version, 2);
- else
- {
- meta_error_trap_pop_with_return (display);
- return FALSE;
- }
-
- if (meta_error_trap_pop_with_return (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\n", G_STRFUNC);
- XSync (display->xdisplay, False);
-
- return TRUE;
-}
-
-/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
-static void
-process_selection_request (MetaDisplay *display,
- XEvent *event)
-{
- MetaScreen *screen = display->screen;
- XSelectionEvent reply;
-
- if (screen->wm_sn_selection_window != event->xselectionrequest.owner ||
- screen->wm_sn_atom != event->xselectionrequest.selection)
- {
- char *str;
-
- meta_error_trap_push (display);
- str = XGetAtomName (display->xdisplay,
- event->xselectionrequest.selection);
- meta_error_trap_pop (display);
-
- meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
- str ? str : "(bad atom)", event->xselectionrequest.owner);
-
- meta_XFree (str);
-
- return;
- }
-
- reply.type = SelectionNotify;
- reply.display = 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 == display->atom_MULTIPLE)
- {
- if (event->xselectionrequest.property != None)
- {
- Atom type, *adata;
- int i, format;
- unsigned long num, rest;
- unsigned char *data;
-
- meta_error_trap_push (display);
- if (XGetWindowProperty (display->xdisplay,
- event->xselectionrequest.requestor,
- event->xselectionrequest.property, 0, 256, False,
- display->atom_ATOM_PAIR,
- &type, &format, &num, &rest, &data) != Success)
- {
- meta_error_trap_pop_with_return (display);
- return;
- }
-
- if (meta_error_trap_pop_with_return (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 (display, screen,
- event->xselectionrequest.requestor,
- adata[i], adata[i+1]))
- adata[i+1] = None;
- i += 2;
- }
-
- meta_error_trap_push (display);
- XChangeProperty (display->xdisplay,
- event->xselectionrequest.requestor,
- event->xselectionrequest.property,
- display->atom_ATOM_PAIR,
- 32, PropModeReplace, data, num);
- meta_error_trap_pop (display);
- meta_XFree (data);
- }
- }
- }
- else
- {
- if (event->xselectionrequest.property == None)
- event->xselectionrequest.property = event->xselectionrequest.target;
-
- if (convert_property (display, screen,
- event->xselectionrequest.requestor,
- event->xselectionrequest.target,
- event->xselectionrequest.property))
- reply.property = event->xselectionrequest.property;
- }
-
- XSendEvent (display->xdisplay,
- event->xselectionrequest.requestor,
- False, 0L, (XEvent*)&reply);
-
- meta_verbose ("Handled selection request\n");
-}
-
-static void
-process_selection_clear (MetaDisplay *display,
- XEvent *event)
-{
- MetaScreen *screen = display->screen;
-
- if (screen->wm_sn_selection_window != event->xselectionclear.window ||
- screen->wm_sn_atom != event->xselectionclear.selection)
- {
- char *str;
-
- meta_error_trap_push (display);
- str = XGetAtomName (display->xdisplay,
- event->xselectionclear.selection);
- meta_error_trap_pop (display);
-
- meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
- str ? str : "(bad atom)", event->xselectionclear.window);
-
- meta_XFree (str);
-
- return;
- }
-
- meta_verbose ("Got selection clear for screen %d on display %s\n",
- screen->number, display->name);
-
- meta_display_unmanage_screen (display, display->screen,
- event->xselectionclear.time);
-}
-
-static gboolean
-handle_other_xevent (MetaDisplay *display,
- XEvent *event)
-{
- Window modified;
- MetaWindow *window;
- MetaWindow *property_for_window;
- gboolean frame_was_receiver;
- gboolean bypass_gtk = FALSE;
-
- modified = event_get_modified_window (display, event);
- window = modified != None ? meta_display_lookup_x_window (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_DISPLAY_HAS_XSYNC (display) &&
- event->type == (display->xsync_event_base + XSyncAlarmNotify))
- {
- MetaWindow *alarm_window = meta_display_lookup_sync_alarm (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 */
- }
-
- goto out;
- }
-
- if (META_DISPLAY_HAS_SHAPE (display) &&
- event->type == (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)\n",
- 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 == display->screen->xroot)
- meta_stack_tracker_create_event (display->screen->stack_tracker,
- &event->xcreatewindow);
- }
- break;
-
- case DestroyNotify:
- {
- if (event->xdestroywindow.event == display->screen->xroot)
- meta_stack_tracker_destroy_event (display->screen->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\n",
- window->frame->xwindow);
- meta_error_trap_push (display);
- meta_window_destroy_frame (window->frame->window);
- meta_error_trap_pop (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\n",
- 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\n",
- window->unmaps_pending);
- }
- }
- }
- break;
- case MapNotify:
- /* NB: override redirect windows wont 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 == display->screen->xroot)
- {
- window = meta_window_x11_new (display, event->xmap.window,
- FALSE, META_COMP_EFFECT_CREATE);
- }
- break;
- case MapRequest:
- if (window == NULL)
- {
- window = meta_window_x11_new (display, event->xmaprequest.window,
- FALSE, META_COMP_EFFECT_CREATE);
- }
- /* if frame was receiver it's some malicious send event or something */
- else if (!frame_was_receiver && window)
- {
- meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n",
- window->desc, window->mapped, window->minimized);
- if (window->minimized)
- {
- meta_window_unminimize (window);
- if (window->workspace != window->screen->active_workspace)
- {
- meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n",
- window->mapped, window->minimized);
- meta_window_change_workspace (window,
- window->screen->active_workspace);
- }
- }
- }
- break;
- case ReparentNotify:
- {
- if (event->xreparent.event == display->screen->xroot)
- meta_stack_tracker_reparent_event (display->screen->stack_tracker,
- &event->xreparent);
- }
- break;
- case ConfigureNotify:
- if (event->xconfigure.event != event->xconfigure.window)
- {
- if (event->xconfigure.event == display->screen->xroot)
- meta_stack_tracker_configure_event (display->screen->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)\n",
- xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
- meta_error_trap_push (display);
- XConfigureWindow (display->xdisplay, event->xconfigurerequest.window,
- xwcm, &xwc);
- meta_error_trap_pop (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_display_lookup_group (display,
- event->xproperty.window);
- if (group != NULL)
- meta_group_property_notify (group, event);
-
- if (event->xproperty.window == display->screen->xroot)
- {
- if (event->xproperty.atom ==
- display->atom__NET_DESKTOP_LAYOUT)
- meta_screen_update_workspace_layout (display->screen);
- else if (event->xproperty.atom ==
- display->atom__NET_DESKTOP_NAMES)
- meta_screen_update_workspace_names (display->screen);
- else if (meta_is_wayland_compositor () &&
- event->xproperty.atom ==
- display->atom__XKB_RULES_NAMES)
- reload_xkb_rules (display->screen);
-
- /* 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 ==
- display->atom__MUTTER_SENTINEL)
- {
- meta_display_decrement_focus_sentinel (display);
- }
- }
- }
- break;
- case SelectionRequest:
- process_selection_request (display, event);
- break;
- case SelectionNotify:
- break;
- case ColormapNotify:
- break;
- case ClientMessage:
- if (window)
- {
- if (event->xclient.message_type == display->atom_WL_SURFACE_ID)
- {
- guint32 surface_id = event->xclient.data.l[0];
- meta_xwayland_handle_wl_surface_id (window, surface_id);
- }
- else if (!frame_was_receiver)
- meta_window_x11_client_message (window, event);
- }
- else
- {
- if (event->xclient.window == display->screen->xroot)
- {
- if (event->xclient.message_type ==
- 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\n",
- space, time);
-
- workspace = meta_screen_get_workspace_by_index (display->screen, space);
-
- /* Handle clients using the older version of the spec... */
- if (time == 0 && workspace)
- {
- meta_warning ("Received a NET_CURRENT_DESKTOP message "
- "from a broken (outdated) client who sent "
- "a 0 timestamp\n");
- time = meta_display_get_current_time_roundtrip (display);
- }
-
- if (workspace)
- meta_workspace_activate (workspace, time);
- else
- meta_verbose ("Don't know about workspace %d\n", space);
- }
- else if (event->xclient.message_type ==
- 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\n",
- num_spaces);
-
- meta_prefs_set_num_workspaces (num_spaces);
- }
- else if (event->xclient.message_type ==
- 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_display_get_current_time_roundtrip (display);
- meta_verbose ("Request to %s desktop\n",
- showing_desktop ? "show" : "hide");
-
- if (showing_desktop)
- meta_screen_show_desktop (display->screen, timestamp);
- else
- {
- meta_screen_unshow_desktop (display->screen);
- meta_workspace_focus_default_window (display->screen->active_workspace, NULL,
timestamp);
- }
- }
- else if (event->xclient.message_type ==
- display->atom_WM_PROTOCOLS)
- {
- meta_verbose ("Received WM_PROTOCOLS message\n");
-
- if ((Atom)event->xclient.data.l[0] == 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 ==
- display->atom__NET_REQUEST_FRAME_EXTENTS)
- {
- meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n");
- process_request_frame_extents (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 (display->xdisplay))
- {
- XEvent next_event;
-
- XPeekEvent (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);
- meta_display_process_mapping_event (display, event);
- }
- }
- break;
- default:
-#ifdef HAVE_XKB
- if (event->type == display->xkb_base_event_type)
- {
- XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
-
- switch (xkb_ev->xkb_type)
- {
- case XkbBellNotify:
- if (XSERVER_TIME_IS_BEFORE(display->last_bell_time,
- xkb_ev->time - 100))
- {
- display->last_bell_time = xkb_ev->time;
- meta_bell_notify (display, xkb_ev);
- }
- break;
- case XkbNewKeyboardNotify:
- case XkbMapNotify:
- if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID)
- meta_display_process_mapping_event (display, event);
- break;
- }
- }
-#endif
- 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;
-}
-
-/**
- * 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_display_handle_xevent (MetaDisplay *display,
- XEvent *event)
-{
- Window modified;
- gboolean bypass_compositor = FALSE, bypass_gtk = FALSE;
- XIEvent *input_event;
-
-#if 0
- meta_spew_event (display, event);
-#endif
-
-#ifdef HAVE_STARTUP_NOTIFICATION
- if (sn_display_process_event (display->sn_display, event))
- {
- bypass_gtk = bypass_compositor = TRUE;
- goto out;
- }
-#endif
-
- display->current_time = event_get_time (display, event);
- display->monitor_cache_invalidated = TRUE;
-
- if (display->focused_by_us &&
- event->xany.serial > display->focus_serial &&
- display->focus_window &&
- !window_has_xwindow (display->focus_window, display->server_focus_window))
- {
- meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
- display->focus_window->desc);
- meta_display_update_focus_window (display,
- meta_display_lookup_x_window (display, display->server_focus_window),
- display->server_focus_window,
- display->server_focus_serial,
- FALSE);
- }
-
- if (event->xany.window == display->screen->xroot)
- {
- if (meta_screen_handle_xevent (display->screen, event))
- {
- bypass_gtk = bypass_compositor = TRUE;
- goto out;
- }
- }
-
- modified = event_get_modified_window (display, event);
-
- input_event = get_input_event (display, event);
-
- if (event->type == UnmapNotify)
- {
- if (meta_ui_window_should_not_cause_focus (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\n",
- event->xany.serial);
- }
- }
- else if (input_event &&
- input_event->evtype == XI_Leave &&
- ((XILeaveEvent *)input_event)->mode == XINotifyUngrab &&
- modified == display->ungrab_should_not_cause_focus_window)
- {
- meta_display_add_ignored_crossing_serial (display, event->xany.serial);
- meta_topic (META_DEBUG_FOCUS,
- "Adding LeaveNotify serial %lu to ignored focus serials\n",
- event->xany.serial);
- }
-
-#ifdef HAVE_XI23
- if (meta_display_process_barrier_event (display, input_event))
- {
- bypass_gtk = bypass_compositor = TRUE;
- goto out;
- }
-#endif /* HAVE_XI23 */
-
- /* libXi does not properly copy the serial to XI2 events, so pull it
- * from the parent XAnyEvent and pass it to handle_input_xevent.
- * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687
- */
- if (handle_input_xevent (display, input_event, event->xany.serial))
- {
- bypass_gtk = bypass_compositor = TRUE;
- goto out;
- }
-
- if (handle_other_xevent (display, event))
- {
- bypass_gtk = TRUE;
- goto out;
- }
-
- if (event->type == SelectionClear)
- {
- /* Do this here so we can return without any further
- * processing. */
- process_selection_clear (display, event);
- /* Note that processing that may have resulted in
- * closing the display... */
- bypass_gtk = bypass_compositor = TRUE;
- goto out;
- }
-
- out:
- if (!bypass_compositor)
- {
- MetaWindow *window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
-
- if (meta_compositor_process_event (display->compositor, event, window))
- bypass_gtk = TRUE;
- }
-
- display->current_time = CurrentTime;
- return bypass_gtk;
-}
-
static void
handle_idletime_for_event (const ClutterEvent *event)
{
@@ -1978,19 +213,6 @@ meta_display_handle_event (MetaDisplay *display,
return bypass_clutter;
}
-static GdkFilterReturn
-xevent_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data)
-{
- MetaDisplay *display = data;
-
- if (meta_display_handle_xevent (display, xevent))
- return GDK_FILTER_REMOVE;
- else
- return GDK_FILTER_CONTINUE;
-}
-
static gboolean
event_callback (const ClutterEvent *event,
gpointer data)
@@ -2003,7 +225,7 @@ event_callback (const ClutterEvent *event,
void
meta_display_init_events (MetaDisplay *display)
{
- gdk_window_add_filter (NULL, xevent_filter, display);
+ meta_display_init_events_x11 (display);
display->clutter_event_filter = clutter_event_add_filter (NULL,
event_callback,
NULL,
@@ -2013,7 +235,7 @@ meta_display_init_events (MetaDisplay *display)
void
meta_display_free_events (MetaDisplay *display)
{
- gdk_window_remove_filter (NULL, xevent_filter, display);
+ meta_display_free_events_x11 (display);
clutter_event_remove_filter (display->clutter_event_filter);
display->clutter_event_filter = 0;
}
diff --git a/src/core/events.h b/src/core/events.h
index 66a34ca..7ac2792 100644
--- a/src/core/events.h
+++ b/src/core/events.h
@@ -29,4 +29,3 @@ void meta_display_init_events (MetaDisplay *display);
void meta_display_free_events (MetaDisplay *display);
#endif
-
diff --git a/src/x11/events.c b/src/x11/events.c
new file mode 100644
index 0000000..7355714
--- /dev/null
+++ b/src/x11/events.c
@@ -0,0 +1,1821 @@
+/* -*- 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/extensions/Xdamage.h>
+#include <X11/extensions/shape.h>
+
+#include <meta/errors.h>
+#include "bell.h"
+#include "display-private.h"
+#include "window-private.h"
+#include "workspace-private.h"
+
+#include "x11/window-x11.h"
+#include "x11/xprops.h"
+#include "wayland/meta-xwayland.h"
+#include "wayland/meta-wayland-private.h"
+
+static XIEvent *
+get_input_event (MetaDisplay *display,
+ XEvent *event)
+{
+ if (event->type == GenericEvent &&
+ event->xcookie.extension == 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;
+#ifdef HAVE_XI23
+ case XI_BarrierHit:
+ case XI_BarrierLeave:
+ if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
+ return input_event;
+ break;
+#endif /* HAVE_XI23 */
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static Window
+xievent_get_modified_window (MetaDisplay *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;
+#ifdef HAVE_XI23
+ case XI_BarrierHit:
+ case XI_BarrierLeave:
+ return ((XIBarrierEvent *) input_event)->event;
+#endif /* HAVE_XI23 */
+ }
+
+ 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 (MetaDisplay *display,
+ XEvent *event)
+{
+ XIEvent *input_event = get_input_event (display, event);
+
+ if (input_event)
+ return xievent_get_modified_window (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_DISPLAY_HAS_SHAPE (display) &&
+ event->type == (display->shape_event_base + ShapeNotify))
+ {
+ XShapeEvent *sev = (XShapeEvent*) event;
+ return sev->window;
+ }
+
+ return None;
+ }
+}
+
+static guint32
+event_get_time (MetaDisplay *display,
+ XEvent *event)
+{
+ XIEvent *input_event = get_input_event (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 CurrentTime;
+ }
+}
+
+G_GNUC_UNUSED 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;
+}
+
+G_GNUC_UNUSED 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";
+}
+
+G_GNUC_UNUSED static gint64
+sync_value_to_64 (const XSyncValue *value)
+{
+ gint64 v;
+
+ v = XSyncValueLow32 (*value);
+ v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
+
+ return v;
+}
+
+G_GNUC_UNUSED 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)";
+ }
+}
+
+G_GNUC_UNUSED static void
+meta_spew_xi2_event (MetaDisplay *display,
+ XIEvent *input_event,
+ const char **name_p,
+ char **extra_p)
+{
+ const char *name = NULL;
+ char *extra = NULL;
+
+ XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
+
+ switch (input_event->evtype)
+ {
+ case XI_FocusIn:
+ name = "XI_FocusIn";
+ break;
+ case XI_FocusOut:
+ name = "XI_FocusOut";
+ break;
+ case XI_Enter:
+ name = "XI_Enter";
+ break;
+ case XI_Leave:
+ name = "XI_Leave";
+ break;
+#ifdef HAVE_XI23
+ case XI_BarrierHit:
+ name = "XI_BarrierHit";
+ break;
+ case XI_BarrierLeave:
+ name = "XI_BarrierLeave";
+ break;
+#endif /* HAVE_XI23 */
+ }
+
+ 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;
+}
+
+G_GNUC_UNUSED static void
+meta_spew_core_event (MetaDisplay *display,
+ XEvent *event,
+ const char **name_p,
+ char **extra_p)
+{
+ const char *name = NULL;
+ char *extra = NULL;
+
+ switch (event->type)
+ {
+ case KeymapNotify:
+ name = "KeymapNotify";
+ break;
+ case Expose:
+ name = "Expose";
+ break;
+ case GraphicsExpose:
+ name = "GraphicsExpose";
+ break;
+ case NoExpose:
+ name = "NoExpose";
+ break;
+ case VisibilityNotify:
+ name = "VisibilityNotify";
+ break;
+ case CreateNotify:
+ name = "CreateNotify";
+ extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
+ event->xcreatewindow.parent,
+ event->xcreatewindow.window);
+ break;
+ case DestroyNotify:
+ name = "DestroyNotify";
+ extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
+ event->xdestroywindow.event,
+ event->xdestroywindow.window);
+ break;
+ case UnmapNotify:
+ name = "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:
+ name = "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:
+ name = "MapRequest";
+ extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
+ event->xmaprequest.window,
+ event->xmaprequest.parent);
+ break;
+ case ReparentNotify:
+ name = "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:
+ name = "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:
+ name = "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 GravityNotify:
+ name = "GravityNotify";
+ break;
+ case ResizeRequest:
+ name = "ResizeRequest";
+ extra = g_strdup_printf ("width = %d height = %d",
+ event->xresizerequest.width,
+ event->xresizerequest.height);
+ break;
+ case CirculateNotify:
+ name = "CirculateNotify";
+ break;
+ case CirculateRequest:
+ name = "CirculateRequest";
+ break;
+ case PropertyNotify:
+ {
+ char *str;
+ const char *state;
+
+ name = "PropertyNotify";
+
+ meta_error_trap_push (display);
+ str = XGetAtomName (display->xdisplay,
+ event->xproperty.atom);
+ meta_error_trap_pop (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 SelectionClear:
+ name = "SelectionClear";
+ break;
+ case SelectionRequest:
+ name = "SelectionRequest";
+ break;
+ case SelectionNotify:
+ name = "SelectionNotify";
+ break;
+ case ColormapNotify:
+ name = "ColormapNotify";
+ break;
+ case ClientMessage:
+ {
+ char *str;
+ name = "ClientMessage";
+ meta_error_trap_push (display);
+ str = XGetAtomName (display->xdisplay,
+ event->xclient.message_type);
+ meta_error_trap_pop (display);
+ extra = g_strdup_printf ("type: %s format: %d\n",
+ str ? str : "(unknown atom)",
+ event->xclient.format);
+ meta_XFree (str);
+ }
+ break;
+ case MappingNotify:
+ name = "MappingNotify";
+ break;
+ default:
+ if (META_DISPLAY_HAS_XSYNC (display) &&
+ event->type == (display->xsync_event_base + XSyncAlarmNotify))
+ {
+ XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
+
+ name = "XSyncAlarmNotify";
+ 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_DISPLAY_HAS_SHAPE (display) &&
+ event->type == (display->shape_event_base + ShapeNotify))
+ {
+ XShapeEvent *sev = (XShapeEvent*) event;
+
+ name = "ShapeNotify";
+
+ 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
+ {
+ name = "(Unknown event)";
+ extra = g_strdup_printf ("type: %d", event->xany.type);
+ }
+ break;
+ }
+
+ *name_p = name;
+ *extra_p = extra;
+}
+
+G_GNUC_UNUSED static void
+meta_spew_event (MetaDisplay *display,
+ XEvent *event)
+{
+ MetaScreen *screen = display->screen;
+ const char *name = NULL;
+ char *extra = NULL;
+ char *winname;
+ XIEvent *input_event;
+
+ /* filter overnumerous events */
+ if (event->type == Expose || event->type == MotionNotify ||
+ event->type == NoExpose)
+ return;
+
+ if (event->type == (display->damage_event_base + XDamageNotify))
+ return;
+
+ if (event->type == (display->xsync_event_base + XSyncAlarmNotify))
+ return;
+
+ if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME)
+ return;
+
+ input_event = get_input_event (display, event);
+
+ if (input_event)
+ meta_spew_xi2_event (display, input_event, &name, &extra);
+ else
+ meta_spew_core_event (display, event, &name, &extra);
+
+ if (event->xany.window == screen->xroot)
+ winname = g_strdup_printf ("root %d", screen->number);
+ else
+ winname = g_strdup_printf ("0x%lx", event->xany.window);
+
+ g_print ("%s on %s%s %s %sserial %lu\n", name, winname,
+ extra ? ":" : "", extra ? extra : "",
+ event->xany.send_event ? "SEND " : "",
+ event->xany.serial);
+
+ g_free (winname);
+
+ if (extra)
+ g_free (extra);
+}
+
+static void
+handle_window_focus_event (MetaDisplay *display,
+ MetaWindow *window,
+ XIEnterEvent *event,
+ unsigned long serial)
+{
+ 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_display_xwindow_is_a_no_focus_window (display, event->event))
+ window_type = "no_focus_window";
+ else if (event->event == display->screen->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\n",
+ 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),
+ event->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\n");
+ return;
+ }
+
+ if (event->evtype == XI_FocusIn)
+ {
+ display->server_focus_window = event->event;
+ 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\n");
+ return;
+ }
+
+ display->server_focus_window = None;
+ display->server_focus_serial = serial;
+ focus_window = NULL;
+ }
+ else
+ g_return_if_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 (display->server_focus_serial > display->focus_serial ||
+ (!display->focused_by_us &&
+ display->server_focus_serial == display->focus_serial))
+ {
+ meta_display_update_focus_window (display,
+ focus_window,
+ focus_window ? focus_window->xwindow : None,
+ display->server_focus_serial,
+ FALSE);
+ }
+}
+
+static gboolean
+crossing_serial_is_ignored (MetaDisplay *display,
+ unsigned long serial)
+{
+ int i;
+
+ i = 0;
+ while (i < N_IGNORED_CROSSING_SERIALS)
+ {
+ if (display->ignored_crossing_serials[i] == serial)
+ return TRUE;
+ ++i;
+ }
+ return FALSE;
+}
+
+static gboolean
+handle_input_xevent (MetaDisplay *display,
+ XIEvent *input_event,
+ gulong serial)
+{
+ XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
+ Window modified;
+ MetaWindow *window;
+ MetaScreen *screen = display->screen;
+
+ 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 (display, input_event);
+ window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
+
+ /* If this is an event for a GTK+ widget, let GTK+ handle it. */
+ if (meta_ui_window_is_widget (display->screen->ui, modified))
+ return FALSE;
+
+ switch (input_event->evtype)
+ {
+ case XI_Enter:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ /* Check if we've entered a window; do this even if window->has_focus to
+ * avoid races.
+ */
+ if (window && !crossing_serial_is_ignored (display, serial) &&
+ enter_event->mode != XINotifyGrab &&
+ enter_event->mode != XINotifyUngrab &&
+ enter_event->detail != XINotifyInferior &&
+ meta_display_focus_sentinel_clear (display))
+ {
+ meta_window_handle_enter (window,
+ enter_event->time,
+ enter_event->root_x,
+ enter_event->root_y);
+ }
+ break;
+ case XI_Leave:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ if (window != NULL &&
+ enter_event->mode != XINotifyGrab &&
+ enter_event->mode != XINotifyUngrab)
+ {
+ meta_window_handle_leave (window);
+ }
+ break;
+ case XI_FocusIn:
+ case XI_FocusOut:
+ handle_window_focus_event (display, window, enter_event, serial);
+ if (!window)
+ {
+ /* Check if the window is a root window. */
+ if (enter_event->root != enter_event->event)
+ break;
+
+ if (enter_event->evtype == XI_FocusIn &&
+ enter_event->mode == 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.\n");
+ meta_workspace_focus_default_window (screen->active_workspace,
+ NULL,
+ meta_display_get_current_time_roundtrip (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.\n");
+ meta_workspace_focus_default_window (screen->active_workspace,
+ NULL,
+ meta_display_get_current_time_roundtrip (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
+reload_xkb_rules (MetaScreen *screen)
+{
+ MetaWaylandCompositor *compositor;
+ char **names;
+ int n_names;
+ gboolean ok;
+ const char *rules, *model, *layout, *variant, *options;
+
+ compositor = meta_wayland_compositor_get_default ();
+
+ ok = meta_prop_get_latin1_list (screen->display, screen->xroot,
+ screen->display->atom__XKB_RULES_NAMES,
+ &names, &n_names);
+ if (!ok)
+ return;
+
+ if (n_names != 5)
+ goto out;
+
+ rules = names[0];
+ model = names[1];
+ layout = names[2];
+ variant = names[3];
+ options = names[4];
+
+ meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard,
+ rules, model, layout, variant, options,
+ META_WAYLAND_KEYBOARD_SKIP_XCLIENTS);
+
+ out:
+ g_strfreev (names);
+}
+
+static void
+process_request_frame_extents (MetaDisplay *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\n", xwindow);
+
+ /* See if the window is decorated. */
+ hints_set = meta_prop_get_motif_hints (display,
+ xwindow,
+ 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 (display->screen->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\n",
+ xwindow, data[0], data[1], data[2], data[3]);
+
+ meta_error_trap_push (display);
+ XChangeProperty (display->xdisplay, xwindow,
+ display->atom__NET_FRAME_EXTENTS,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) data, 4);
+ meta_error_trap_pop (display);
+
+ meta_XFree (hints);
+}
+
+/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
+static gboolean
+convert_property (MetaDisplay *display,
+ MetaScreen *screen,
+ Window w,
+ Atom target,
+ Atom property)
+{
+#define N_TARGETS 4
+ Atom conversion_targets[N_TARGETS];
+ long icccm_version[] = { 2, 0 };
+
+ conversion_targets[0] = display->atom_TARGETS;
+ conversion_targets[1] = display->atom_MULTIPLE;
+ conversion_targets[2] = display->atom_TIMESTAMP;
+ conversion_targets[3] = display->atom_VERSION;
+
+ meta_error_trap_push (display);
+ if (target == display->atom_TARGETS)
+ XChangeProperty (display->xdisplay, w, property,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)conversion_targets, N_TARGETS);
+ else if (target == display->atom_TIMESTAMP)
+ XChangeProperty (display->xdisplay, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *)&screen->wm_sn_timestamp, 1);
+ else if (target == display->atom_VERSION)
+ XChangeProperty (display->xdisplay, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *)icccm_version, 2);
+ else
+ {
+ meta_error_trap_pop_with_return (display);
+ return FALSE;
+ }
+
+ if (meta_error_trap_pop_with_return (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\n", G_STRFUNC);
+ XSync (display->xdisplay, False);
+
+ return TRUE;
+}
+
+/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
+static void
+process_selection_request (MetaDisplay *display,
+ XEvent *event)
+{
+ MetaScreen *screen = display->screen;
+ XSelectionEvent reply;
+
+ if (screen->wm_sn_selection_window != event->xselectionrequest.owner ||
+ screen->wm_sn_atom != event->xselectionrequest.selection)
+ {
+ char *str;
+
+ meta_error_trap_push (display);
+ str = XGetAtomName (display->xdisplay,
+ event->xselectionrequest.selection);
+ meta_error_trap_pop (display);
+
+ meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
+ str ? str : "(bad atom)", event->xselectionrequest.owner);
+
+ meta_XFree (str);
+
+ return;
+ }
+
+ reply.type = SelectionNotify;
+ reply.display = 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 == display->atom_MULTIPLE)
+ {
+ if (event->xselectionrequest.property != None)
+ {
+ Atom type, *adata;
+ int i, format;
+ unsigned long num, rest;
+ unsigned char *data;
+
+ meta_error_trap_push (display);
+ if (XGetWindowProperty (display->xdisplay,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property, 0, 256, False,
+ display->atom_ATOM_PAIR,
+ &type, &format, &num, &rest, &data) != Success)
+ {
+ meta_error_trap_pop_with_return (display);
+ return;
+ }
+
+ if (meta_error_trap_pop_with_return (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 (display, screen,
+ event->xselectionrequest.requestor,
+ adata[i], adata[i+1]))
+ adata[i+1] = None;
+ i += 2;
+ }
+
+ meta_error_trap_push (display);
+ XChangeProperty (display->xdisplay,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property,
+ display->atom_ATOM_PAIR,
+ 32, PropModeReplace, data, num);
+ meta_error_trap_pop (display);
+ meta_XFree (data);
+ }
+ }
+ }
+ else
+ {
+ if (event->xselectionrequest.property == None)
+ event->xselectionrequest.property = event->xselectionrequest.target;
+
+ if (convert_property (display, screen,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.target,
+ event->xselectionrequest.property))
+ reply.property = event->xselectionrequest.property;
+ }
+
+ XSendEvent (display->xdisplay,
+ event->xselectionrequest.requestor,
+ False, 0L, (XEvent*)&reply);
+
+ meta_verbose ("Handled selection request\n");
+}
+
+static void
+process_selection_clear (MetaDisplay *display,
+ XEvent *event)
+{
+ MetaScreen *screen = display->screen;
+
+ if (screen->wm_sn_selection_window != event->xselectionclear.window ||
+ screen->wm_sn_atom != event->xselectionclear.selection)
+ {
+ char *str;
+
+ meta_error_trap_push (display);
+ str = XGetAtomName (display->xdisplay,
+ event->xselectionclear.selection);
+ meta_error_trap_pop (display);
+
+ meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
+ str ? str : "(bad atom)", event->xselectionclear.window);
+
+ meta_XFree (str);
+
+ return;
+ }
+
+ meta_verbose ("Got selection clear for screen %d on display %s\n",
+ screen->number, display->name);
+
+ meta_display_unmanage_screen (display, display->screen,
+ event->xselectionclear.time);
+}
+
+static gboolean
+handle_other_xevent (MetaDisplay *display,
+ XEvent *event)
+{
+ Window modified;
+ MetaWindow *window;
+ MetaWindow *property_for_window;
+ gboolean frame_was_receiver;
+ gboolean bypass_gtk = FALSE;
+
+ modified = event_get_modified_window (display, event);
+ window = modified != None ? meta_display_lookup_x_window (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_DISPLAY_HAS_XSYNC (display) &&
+ event->type == (display->xsync_event_base + XSyncAlarmNotify))
+ {
+ MetaWindow *alarm_window = meta_display_lookup_sync_alarm (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 */
+ }
+
+ goto out;
+ }
+
+ if (META_DISPLAY_HAS_SHAPE (display) &&
+ event->type == (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)\n",
+ 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 == display->screen->xroot)
+ meta_stack_tracker_create_event (display->screen->stack_tracker,
+ &event->xcreatewindow);
+ }
+ break;
+
+ case DestroyNotify:
+ {
+ if (event->xdestroywindow.event == display->screen->xroot)
+ meta_stack_tracker_destroy_event (display->screen->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\n",
+ window->frame->xwindow);
+ meta_error_trap_push (display);
+ meta_window_destroy_frame (window->frame->window);
+ meta_error_trap_pop (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\n",
+ 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\n",
+ window->unmaps_pending);
+ }
+ }
+ }
+ break;
+ case MapNotify:
+ /* NB: override redirect windows wont 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 == display->screen->xroot)
+ {
+ window = meta_window_x11_new (display, event->xmap.window,
+ FALSE, META_COMP_EFFECT_CREATE);
+ }
+ break;
+ case MapRequest:
+ if (window == NULL)
+ {
+ window = meta_window_x11_new (display, event->xmaprequest.window,
+ FALSE, META_COMP_EFFECT_CREATE);
+ }
+ /* if frame was receiver it's some malicious send event or something */
+ else if (!frame_was_receiver && window)
+ {
+ meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n",
+ window->desc, window->mapped, window->minimized);
+ if (window->minimized)
+ {
+ meta_window_unminimize (window);
+ if (window->workspace != window->screen->active_workspace)
+ {
+ meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n",
+ window->mapped, window->minimized);
+ meta_window_change_workspace (window,
+ window->screen->active_workspace);
+ }
+ }
+ }
+ break;
+ case ReparentNotify:
+ {
+ if (event->xreparent.event == display->screen->xroot)
+ meta_stack_tracker_reparent_event (display->screen->stack_tracker,
+ &event->xreparent);
+ }
+ break;
+ case ConfigureNotify:
+ if (event->xconfigure.event != event->xconfigure.window)
+ {
+ if (event->xconfigure.event == display->screen->xroot)
+ meta_stack_tracker_configure_event (display->screen->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)\n",
+ xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
+ meta_error_trap_push (display);
+ XConfigureWindow (display->xdisplay, event->xconfigurerequest.window,
+ xwcm, &xwc);
+ meta_error_trap_pop (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_display_lookup_group (display,
+ event->xproperty.window);
+ if (group != NULL)
+ meta_group_property_notify (group, event);
+
+ if (event->xproperty.window == display->screen->xroot)
+ {
+ if (event->xproperty.atom ==
+ display->atom__NET_DESKTOP_LAYOUT)
+ meta_screen_update_workspace_layout (display->screen);
+ else if (event->xproperty.atom ==
+ display->atom__NET_DESKTOP_NAMES)
+ meta_screen_update_workspace_names (display->screen);
+ else if (meta_is_wayland_compositor () &&
+ event->xproperty.atom ==
+ display->atom__XKB_RULES_NAMES)
+ reload_xkb_rules (display->screen);
+
+ /* 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 ==
+ display->atom__MUTTER_SENTINEL)
+ {
+ meta_display_decrement_focus_sentinel (display);
+ }
+ }
+ }
+ break;
+ case SelectionRequest:
+ process_selection_request (display, event);
+ break;
+ case SelectionNotify:
+ break;
+ case ColormapNotify:
+ break;
+ case ClientMessage:
+ if (window)
+ {
+ if (event->xclient.message_type == display->atom_WL_SURFACE_ID)
+ {
+ guint32 surface_id = event->xclient.data.l[0];
+ meta_xwayland_handle_wl_surface_id (window, surface_id);
+ }
+ else if (!frame_was_receiver)
+ meta_window_x11_client_message (window, event);
+ }
+ else
+ {
+ if (event->xclient.window == display->screen->xroot)
+ {
+ if (event->xclient.message_type ==
+ 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\n",
+ space, time);
+
+ workspace = meta_screen_get_workspace_by_index (display->screen, space);
+
+ /* Handle clients using the older version of the spec... */
+ if (time == 0 && workspace)
+ {
+ meta_warning ("Received a NET_CURRENT_DESKTOP message "
+ "from a broken (outdated) client who sent "
+ "a 0 timestamp\n");
+ time = meta_display_get_current_time_roundtrip (display);
+ }
+
+ if (workspace)
+ meta_workspace_activate (workspace, time);
+ else
+ meta_verbose ("Don't know about workspace %d\n", space);
+ }
+ else if (event->xclient.message_type ==
+ 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\n",
+ num_spaces);
+
+ meta_prefs_set_num_workspaces (num_spaces);
+ }
+ else if (event->xclient.message_type ==
+ 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_display_get_current_time_roundtrip (display);
+ meta_verbose ("Request to %s desktop\n",
+ showing_desktop ? "show" : "hide");
+
+ if (showing_desktop)
+ meta_screen_show_desktop (display->screen, timestamp);
+ else
+ {
+ meta_screen_unshow_desktop (display->screen);
+ meta_workspace_focus_default_window (display->screen->active_workspace, NULL,
timestamp);
+ }
+ }
+ else if (event->xclient.message_type ==
+ display->atom_WM_PROTOCOLS)
+ {
+ meta_verbose ("Received WM_PROTOCOLS message\n");
+
+ if ((Atom)event->xclient.data.l[0] == 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 ==
+ display->atom__NET_REQUEST_FRAME_EXTENTS)
+ {
+ meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n");
+ process_request_frame_extents (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 (display->xdisplay))
+ {
+ XEvent next_event;
+
+ XPeekEvent (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);
+ meta_display_process_mapping_event (display, event);
+ }
+ }
+ break;
+ default:
+#ifdef HAVE_XKB
+ if (event->type == display->xkb_base_event_type)
+ {
+ XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
+
+ switch (xkb_ev->xkb_type)
+ {
+ case XkbBellNotify:
+ if (XSERVER_TIME_IS_BEFORE(display->last_bell_time,
+ xkb_ev->time - 100))
+ {
+ display->last_bell_time = xkb_ev->time;
+ meta_bell_notify (display, xkb_ev);
+ }
+ break;
+ case XkbNewKeyboardNotify:
+ case XkbMapNotify:
+ if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID)
+ meta_display_process_mapping_event (display, event);
+ break;
+ }
+ }
+#endif
+ 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;
+}
+
+/**
+ * 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_display_handle_xevent (MetaDisplay *display,
+ XEvent *event)
+{
+ Window modified;
+ gboolean bypass_compositor = FALSE, bypass_gtk = FALSE;
+ XIEvent *input_event;
+
+#if 0
+ meta_spew_event (display, event);
+#endif
+
+#ifdef HAVE_STARTUP_NOTIFICATION
+ if (sn_display_process_event (display->sn_display, event))
+ {
+ bypass_gtk = bypass_compositor = TRUE;
+ goto out;
+ }
+#endif
+
+ display->current_time = event_get_time (display, event);
+ display->monitor_cache_invalidated = TRUE;
+
+ if (display->focused_by_us &&
+ event->xany.serial > display->focus_serial &&
+ display->focus_window &&
+ !window_has_xwindow (display->focus_window, display->server_focus_window))
+ {
+ meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
+ display->focus_window->desc);
+ meta_display_update_focus_window (display,
+ meta_display_lookup_x_window (display, display->server_focus_window),
+ display->server_focus_window,
+ display->server_focus_serial,
+ FALSE);
+ }
+
+ if (event->xany.window == display->screen->xroot)
+ {
+ if (meta_screen_handle_xevent (display->screen, event))
+ {
+ bypass_gtk = bypass_compositor = TRUE;
+ goto out;
+ }
+ }
+
+ modified = event_get_modified_window (display, event);
+
+ input_event = get_input_event (display, event);
+
+ if (event->type == UnmapNotify)
+ {
+ if (meta_ui_window_should_not_cause_focus (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\n",
+ event->xany.serial);
+ }
+ }
+ else if (input_event &&
+ input_event->evtype == XI_Leave &&
+ ((XILeaveEvent *)input_event)->mode == XINotifyUngrab &&
+ modified == display->ungrab_should_not_cause_focus_window)
+ {
+ meta_display_add_ignored_crossing_serial (display, event->xany.serial);
+ meta_topic (META_DEBUG_FOCUS,
+ "Adding LeaveNotify serial %lu to ignored focus serials\n",
+ event->xany.serial);
+ }
+
+#ifdef HAVE_XI23
+ if (meta_display_process_barrier_event (display, input_event))
+ {
+ bypass_gtk = bypass_compositor = TRUE;
+ goto out;
+ }
+#endif /* HAVE_XI23 */
+
+ /* libXi does not properly copy the serial to XI2 events, so pull it
+ * from the parent XAnyEvent and pass it to handle_input_xevent.
+ * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687
+ */
+ if (handle_input_xevent (display, input_event, event->xany.serial))
+ {
+ bypass_gtk = bypass_compositor = TRUE;
+ goto out;
+ }
+
+ if (handle_other_xevent (display, event))
+ {
+ bypass_gtk = TRUE;
+ goto out;
+ }
+
+ if (event->type == SelectionClear)
+ {
+ /* Do this here so we can return without any further
+ * processing. */
+ process_selection_clear (display, event);
+ /* Note that processing that may have resulted in
+ * closing the display... */
+ bypass_gtk = bypass_compositor = TRUE;
+ goto out;
+ }
+
+ out:
+ if (!bypass_compositor)
+ {
+ MetaWindow *window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
+
+ if (meta_compositor_process_event (display->compositor, event, window))
+ bypass_gtk = TRUE;
+ }
+
+ display->current_time = CurrentTime;
+ return bypass_gtk;
+}
+
+
+static GdkFilterReturn
+xevent_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ MetaDisplay *display = data;
+
+ if (meta_display_handle_xevent (display, xevent))
+ return GDK_FILTER_REMOVE;
+ else
+ return GDK_FILTER_CONTINUE;
+}
+
+void
+meta_display_init_events_x11 (MetaDisplay *display)
+{
+ gdk_window_add_filter (NULL, xevent_filter, display);
+}
+
+void
+meta_display_free_events_x11 (MetaDisplay *display)
+{
+ gdk_window_remove_filter (NULL, xevent_filter, display);
+}
diff --git a/src/x11/events.h b/src/x11/events.h
new file mode 100644
index 0000000..6aa073b
--- /dev/null
+++ b/src/x11/events.h
@@ -0,0 +1,31 @@
+/* -*- 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 <meta/display.h>
+
+#ifndef META_EVENTS_X11_H
+#define META_EVENTS_X11_H
+
+void meta_display_init_events_x11 (MetaDisplay *display);
+void meta_display_free_events_x11 (MetaDisplay *display);
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]