[mutter/wayland] Move event handling to a new file
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wayland] Move event handling to a new file
- Date: Thu, 20 Mar 2014 19:53:34 +0000 (UTC)
commit 24b08d1a3608c09aed271798d91de208132c3c6e
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Thu Mar 20 15:29:30 2014 -0400
Move event handling to a new file
display.c is getting a bit crowded. Move most of the handling
out to another file, events.c.
The long-term goal is to have generic event handling here, with
backend-specific handling for the types of windows and such.
src/Makefile.am | 2 +
src/core/display-private.h | 9 +
src/core/display.c | 2285 +-------------------------------------------
src/core/events.c | 2265 +++++++++++++++++++++++++++++++++++++++++++
src/core/events.h | 32 +
5 files changed, 2331 insertions(+), 2262 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 1d0c53c..3763746 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -116,6 +116,8 @@ libmutter_wayland_la_SOURCES = \
core/edge-resistance.h \
core/edid-parse.c \
core/edid.h \
+ core/events.c \
+ core/events.h \
core/errors.c \
meta/errors.h \
core/frame.c \
diff --git a/src/core/display-private.h b/src/core/display-private.h
index c4548fc..3194afc 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -456,6 +456,7 @@ gboolean meta_grab_op_is_resizing (MetaGrabOp op);
gboolean meta_grab_op_is_mouse (MetaGrabOp op);
gboolean meta_grab_op_is_clicking (MetaGrabOp op);
gboolean meta_grab_op_is_wayland (MetaGrabOp op);
+gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
void meta_display_devirtualize_modifiers (MetaDisplay *display,
MetaVirtualModifier modifiers,
@@ -489,5 +490,13 @@ void meta_display_set_input_focus_xwindow (MetaDisplay *display,
guint32 timestamp);
void meta_display_sync_wayland_input_focus (MetaDisplay *display);
+void meta_display_update_focus_window (MetaDisplay *display,
+ MetaWindow *window,
+ Window xwindow,
+ gulong serial,
+ gboolean focused_by_us);
+
+void meta_display_sanity_check_timestamps (MetaDisplay *display,
+ guint32 timestamp);
#endif
diff --git a/src/core/display.c b/src/core/display.c
index 287f1f5..2910c69 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -32,6 +32,7 @@
#include <config.h>
#include "display-private.h"
+#include "events.h"
#include "util-private.h"
#include <meta/main.h>
#include "screen-private.h"
@@ -56,9 +57,6 @@
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif
-#ifdef HAVE_XKB
-#include <X11/XKBlib.h>
-#endif
#include <X11/Xcursor/Xcursor.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xcomposite.h>
@@ -147,36 +145,10 @@ static MetaDisplay *the_display = NULL;
static const char *gnome_wm_keybindings = "Mutter";
static const char *net_wm_name = "Mutter";
-#ifdef WITH_VERBOSE_MODE
-static void meta_spew_event (MetaDisplay *display,
- XEvent *event);
-#endif
-
-static gboolean xevent_callback (XEvent *event,
- gpointer data);
-static gboolean event_callback (const ClutterEvent *event,
- gpointer data);
-static Window event_get_modified_window (MetaDisplay *display,
- XEvent *event);
-static Window xievent_get_modified_window (MetaDisplay *display,
- XIEvent *input_event);
-static guint32 event_get_time (MetaDisplay *display,
- XEvent *event);
-static void process_request_frame_extents (MetaDisplay *display,
- XEvent *event);
-static void process_selection_request (MetaDisplay *display,
- XEvent *event);
-static void process_selection_clear (MetaDisplay *display,
- XEvent *event);
-
static void update_window_grab_modifiers (MetaDisplay *display);
static void prefs_changed_callback (MetaPreference pref,
void *data);
-
-static void sanity_check_timestamps (MetaDisplay *display,
- guint32 known_good_timestamp);
-
static void
meta_display_get_property(GObject *object,
guint prop_id,
@@ -574,13 +546,7 @@ meta_display_open (void)
#endif
/* Get events */
- meta_ui_add_event_func (the_display->xdisplay,
- xevent_callback,
- the_display);
- the_display->clutter_event_filter = clutter_event_add_filter (NULL,
- event_callback,
- NULL,
- the_display);
+ meta_display_init_events (the_display);
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
@@ -1083,13 +1049,9 @@ meta_display_close (MetaDisplay *display,
if (display->grab_old_window_stacking)
g_list_free (display->grab_old_window_stacking);
-
+
/* Stop caring about events */
- meta_ui_remove_event_func (display->xdisplay,
- xevent_callback,
- display);
- clutter_event_remove_filter (display->clutter_event_filter);
- display->clutter_event_filter = 0;
+ meta_display_free_events (display);
/* Free all screens */
tmp = display->screens;
@@ -1344,8 +1306,8 @@ meta_grab_op_is_mouse (MetaGrabOp op)
}
}
-static gboolean
-grab_op_is_keyboard (MetaGrabOp op)
+gboolean
+meta_grab_op_is_keyboard (MetaGrabOp op)
{
switch (op)
{
@@ -1410,20 +1372,6 @@ meta_grab_op_is_moving (MetaGrabOp op)
}
}
-static gboolean
-grab_op_should_block_mouse_events (MetaGrabOp op)
-{
- switch (op)
- {
- case META_GRAB_OP_WAYLAND_CLIENT:
- case META_GRAB_OP_COMPOSITOR:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
gboolean
meta_grab_op_is_clicking (MetaGrabOp grab_op)
{
@@ -1529,7 +1477,7 @@ meta_display_get_current_time_roundtrip (MetaDisplay *display)
timestamp = property_event.xproperty.time;
}
- sanity_check_timestamps (display, timestamp);
+ meta_display_sanity_check_timestamps (display, timestamp);
return timestamp;
}
@@ -1579,22 +1527,6 @@ meta_display_add_ignored_crossing_serial (MetaDisplay *display,
display->ignored_crossing_serials[i] = serial;
}
-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
window_raise_with_delay_callback (void *data)
{
@@ -1693,84 +1625,6 @@ handle_net_restack_window (MetaDisplay* display,
}
#endif
-static MetaWindow *
-get_window_for_event (MetaDisplay *display,
- const ClutterEvent *event)
-{
- ClutterActor *source;
-
- if (display->grab_op != META_GRAB_OP_NONE)
- return display->grab_window;
-
- /* Always use the key focused window for key events. */
- switch (event->type)
- {
- case CLUTTER_KEY_PRESS:
- case CLUTTER_KEY_RELEASE:
- return display->focus_window;
- default:
- break;
- }
-
- source = clutter_event_get_source (event);
- if (META_IS_SURFACE_ACTOR (source))
- return meta_surface_actor_get_window (META_SURFACE_ACTOR (source));
-
- 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;
-}
-
void
meta_display_sync_wayland_input_focus (MetaDisplay *display)
{
@@ -1794,12 +1648,12 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display)
meta_wayland_seat_repick (compositor->seat, NULL);
}
-static void
-update_focus_window (MetaDisplay *display,
- MetaWindow *window,
- Window xwindow,
- gulong serial,
- gboolean focused_by_us)
+void
+meta_display_update_focus_window (MetaDisplay *display,
+ MetaWindow *window,
+ Window xwindow,
+ gulong serial,
+ gboolean focused_by_us)
{
display->focus_serial = serial;
display->focused_by_us = focused_by_us;
@@ -1912,11 +1766,11 @@ request_xserver_input_focus_change (MetaDisplay *display,
meta_display_ungrab (display);
- update_focus_window (display,
- meta_window,
- xwindow,
- serial,
- TRUE);
+ meta_display_update_focus_window (display,
+ meta_window,
+ xwindow,
+ serial,
+ TRUE);
meta_error_trap_pop (display);
@@ -1927,1823 +1781,6 @@ request_xserver_input_focus_change (MetaDisplay *display,
meta_display_remove_autoraise_callback (display);
}
-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 (meta_display_screen_for_root (display, event->event))
- 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))
- {
- update_focus_window (display,
- focus_window,
- focus_window ? focus_window->xwindow : None,
- display->server_focus_serial,
- FALSE);
- }
-}
-
-static gboolean
-window_has_xwindow (MetaWindow *window,
- Window xwindow)
-{
- if (window->xwindow == xwindow)
- return TRUE;
-
- if (window->frame && window->frame->xwindow == xwindow)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-meta_display_handle_event (MetaDisplay *display,
- const ClutterEvent *event)
-{
- MetaWindow *window;
- gboolean bypass_clutter = FALSE, bypass_wayland = FALSE;
- MetaWaylandCompositor *compositor = NULL;
-
- if (meta_is_wayland_compositor ())
- {
- compositor = meta_wayland_compositor_get_default ();
- meta_wayland_compositor_update (compositor, event);
- }
-
- window = get_window_for_event (display, event);
-
- display->current_time = event->any.time;
-
- if (window && !window->override_redirect &&
- (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS))
- {
- if (CurrentTime == display->current_time)
- {
- /* We can't use missing (i.e. invalid) timestamps to set user time,
- * nor do we want to use them to sanity check other timestamps.
- * See bug 313490 for more details.
- */
- meta_warning ("Event has no timestamp! You may be using a broken "
- "program such as xse. Please ask the authors of that "
- "program to fix it.\n");
- }
- else
- {
- meta_window_set_user_time (window, display->current_time);
- sanity_check_timestamps (display, display->current_time);
- }
- }
-
- switch (event->type)
- {
- case CLUTTER_BUTTON_PRESS:
- if (grab_op_should_block_mouse_events (display->grab_op))
- break;
-
- display->overlay_key_only_pressed = FALSE;
-
- if ((window &&
- meta_grab_op_is_mouse (display->grab_op) &&
- (event->button.modifier_state & display->window_grab_modifiers) &&
- display->grab_button != (int) event->button.button &&
- display->grab_window == window) ||
- grab_op_is_keyboard (display->grab_op))
- {
- meta_topic (META_DEBUG_WINDOW_OPS,
- "Ending grab op %u on window %s due to button press\n",
- display->grab_op,
- (display->grab_window ?
- display->grab_window->desc :
- "none"));
- meta_display_end_grab_op (display, event->any.time);
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- else if (window && display->grab_op == META_GRAB_OP_NONE)
- {
- ClutterModifierType grab_mask;
- gboolean unmodified;
- gboolean fully_modified;
-
- grab_mask = display->window_grab_modifiers;
- if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
- grab_mask |= CLUTTER_CONTROL_MASK;
-
- /* We have three passive button grabs:
- * - on any button, without modifiers => focuses and maybe raises the window
- * - on resize button, with modifiers => start an interactive resizing
- * (normally <Super>middle)
- * - on move button, with modifiers => start an interactive move
- * (normally <Super>left)
- * - on menu button, with modifiers => show the window menu
- * (normally <Super>right)
- *
- * We may get here because we actually have a button
- * grab on the window, or because we're a wayland
- * compositor and thus we see all the events, so we
- * need to check if the event is interesting.
- * We want an event that is not modified, for a window
- * that has (or would have, the wayland case) the
- * button grab active.
- *
- * We may have other events on the window, for example
- * a click on a frame button, but that's not for us to
- * care about. Just let the event through.
- */
- unmodified = (event->button.modifier_state & grab_mask) == 0;
- fully_modified = grab_mask && (event->button.modifier_state & grab_mask) == grab_mask;
-
- if (unmodified && window && window->have_focus_click_grab)
- {
- if (meta_prefs_get_raise_on_click ())
- meta_window_raise (window);
- else
- meta_topic (META_DEBUG_FOCUS,
- "Not raising window on click due to don't-raise-on-click option\n");
-
- /* Don't focus panels--they must explicitly request focus.
- * See bug 160470
- */
- if (window->type != META_WINDOW_DOCK)
- {
- meta_topic (META_DEBUG_FOCUS,
- "Focusing %s due to unmodified button %u press (display.c)\n",
- window->desc, event->button.button);
- meta_window_focus (window, event->any.time);
- }
- else
- /* However, do allow terminals to lose focus due to new
- * window mappings after the user clicks on a panel.
- */
- display->allow_terminal_deactivation = TRUE;
-
- meta_verbose ("Allowing events time %u\n",
- (unsigned int)event->button.time);
-
- XIAllowEvents (display->xdisplay, clutter_input_device_get_device_id (event->button.device),
- XIReplayDevice, event->button.time);
- bypass_clutter = TRUE;
- }
- else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_resize ())
- {
- if (window->has_resize_func)
- {
- gboolean north, south;
- gboolean west, east;
- MetaRectangle frame_rect;
- MetaGrabOp op;
-
- meta_window_get_frame_rect (window, &frame_rect);
-
- west = event->button.x < (frame_rect.x + 1 * frame_rect.width / 3);
- east = event->button.x > (frame_rect.x + 2 * frame_rect.width / 3);
- north = event->button.y < (frame_rect.y + 1 * frame_rect.height / 3);
- south = event->button.y > (frame_rect.y + 2 * frame_rect.height / 3);
-
- if (north && west)
- op = META_GRAB_OP_RESIZING_NW;
- else if (north && east)
- op = META_GRAB_OP_RESIZING_NE;
- else if (south && west)
- op = META_GRAB_OP_RESIZING_SW;
- else if (south && east)
- op = META_GRAB_OP_RESIZING_SE;
- else if (north)
- op = META_GRAB_OP_RESIZING_N;
- else if (west)
- op = META_GRAB_OP_RESIZING_W;
- else if (east)
- op = META_GRAB_OP_RESIZING_E;
- else if (south)
- op = META_GRAB_OP_RESIZING_S;
- else /* Middle region is no-op to avoid user triggering wrong action */
- op = META_GRAB_OP_NONE;
-
- if (op != META_GRAB_OP_NONE)
- meta_display_begin_grab_op (display,
- window->screen,
- window,
- op,
- TRUE,
- FALSE,
- event->button.button,
- 0,
- event->any.time,
- event->button.x,
- event->button.y);
- }
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_menu ())
- {
- if (meta_prefs_get_raise_on_click ())
- meta_window_raise (window);
- meta_window_show_menu (window,
- event->button.x,
- event->button.y,
- event->button.button,
- event->any.time);
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- else if (fully_modified && (int) event->button.button == 1)
- {
- if (window->has_move_func)
- {
- meta_display_begin_grab_op (display,
- window->screen,
- window,
- META_GRAB_OP_MOVING,
- TRUE,
- FALSE,
- event->button.button,
- 0,
- event->any.time,
- event->button.x,
- event->button.y);
- }
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- }
- break;
- case CLUTTER_BUTTON_RELEASE:
- if (grab_op_should_block_mouse_events (display->grab_op))
- break;
-
- display->overlay_key_only_pressed = FALSE;
-
- if (display->grab_window == window &&
- meta_grab_op_is_mouse (display->grab_op))
- {
- meta_window_handle_mouse_grab_op_event (window, event);
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- break;
- case CLUTTER_MOTION:
- if (grab_op_should_block_mouse_events (display->grab_op))
- break;
-
- if (display->grab_window == window &&
- meta_grab_op_is_mouse (display->grab_op))
- {
- meta_window_handle_mouse_grab_op_event (window, event);
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
- break;
-
- case CLUTTER_KEY_PRESS:
- case CLUTTER_KEY_RELEASE:
- /* For key events, it's important to enforce single-handling, or
- * we can get into a confused state. So if a keybinding is
- * handled (because it's one of our hot-keys, or because we are
- * in a keyboard-grabbed mode like moving a window, we don't
- * want to pass the key event to the compositor or Wayland at all.
- */
- if (meta_display_process_key_event (display, window, (ClutterKeyEvent *) event))
- {
- bypass_clutter = TRUE;
- bypass_wayland = TRUE;
- }
-
- default:
- break;
- }
-
- /* If the compositor has a grab, don't pass that through to Wayland */
- if (display->grab_op == META_GRAB_OP_COMPOSITOR)
- bypass_wayland = TRUE;
-
- /* If a Wayland client has a grab, don't pass that through to Clutter */
- if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT)
- bypass_clutter = TRUE;
-
- if (compositor && !bypass_wayland)
- {
- if (meta_wayland_compositor_handle_event (compositor, event))
- bypass_clutter = TRUE;
- }
-
- return bypass_clutter;
-}
-
-static gboolean
-handle_input_xevent (MetaDisplay *display,
- XIEvent *input_event,
- gulong serial)
-{
- XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
- Window modified;
- MetaWindow *window;
- MetaScreen *screen;
-
- if (input_event == NULL)
- return FALSE;
-
- modified = xievent_get_modified_window (display, input_event);
- window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
-
- switch (input_event->evtype)
- {
- case XI_Enter:
- if (display->grab_op == META_GRAB_OP_COMPOSITOR)
- break;
-
- /* If the mouse switches screens, active the default window on the new
- * screen; this will make keybindings and workspace-launched items
- * actually appear on the right screen.
- */
- {
- MetaScreen *new_screen =
- meta_display_screen_for_root (display, enter_event->root);
-
- if (new_screen != NULL && display->active_screen != new_screen)
- meta_workspace_focus_default_window (new_screen->active_workspace,
- NULL,
- enter_event->time);
- }
-
- /* 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);
-
- if (window->type == META_WINDOW_DOCK)
- meta_window_raise (window);
- }
- break;
- case XI_Leave:
- if (display->grab_op == META_GRAB_OP_COMPOSITOR)
- break;
-
- if (window != NULL)
- {
- if (window->type == META_WINDOW_DOCK &&
- enter_event->mode != XINotifyGrab &&
- enter_event->mode != XINotifyUngrab &&
- !window->has_focus)
- meta_window_lower (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;
-
- screen = meta_display_screen_for_root (display, enter_event->root);
-
- 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));
- }
-
- }
-
- /* Don't send FocusIn / FocusOut to Clutter */
- return TRUE;
- }
-
- return FALSE;
-}
-
-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 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;
- }
-
-#ifdef HAVE_XSYNC
- 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_update_sync_request_counter (alarm_window, new_counter_value);
- bypass_gtk = TRUE; /* GTK doesn't want to see this really */
- }
- else
- meta_idle_monitor_handle_xevent_all (event);
-
- goto out;
- }
-#endif /* HAVE_XSYNC */
-
-#ifdef HAVE_SHAPE
- 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;
- }
-#endif /* HAVE_SHAPE */
-
- switch (event->type)
- {
- case KeymapNotify:
- break;
- case Expose:
- break;
- case GraphicsExpose:
- break;
- case NoExpose:
- break;
- case VisibilityNotify:
- break;
- case CreateNotify:
- {
- MetaScreen *screen;
-
- screen = meta_display_screen_for_root (display,
- event->xcreatewindow.parent);
- if (screen)
- meta_stack_tracker_create_event (screen->stack_tracker,
- &event->xcreatewindow);
- }
- break;
-
- case DestroyNotify:
- {
- MetaScreen *screen;
-
- screen = meta_display_screen_for_root (display,
- event->xdestroywindow.event);
- if (screen)
- meta_stack_tracker_destroy_event (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
- && meta_display_screen_for_root (display, event->xmap.event))
- {
- 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:
- {
- MetaScreen *screen;
-
- screen = meta_display_screen_for_root (display,
- event->xconfigure.event);
- if (screen)
- meta_stack_tracker_reparent_event (screen->stack_tracker,
- &event->xreparent);
- }
- break;
- case ConfigureNotify:
- if (event->xconfigure.event != event->xconfigure.window)
- {
- MetaScreen *screen;
-
- screen = meta_display_screen_for_root (display,
- event->xconfigure.event);
- if (screen)
- meta_stack_tracker_configure_event (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;
- MetaScreen *screen;
-
- 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);
-
- screen = NULL;
- if (window == NULL &&
- group == NULL) /* window/group != NULL means it wasn't a root window */
- screen = meta_display_screen_for_root (display,
- event->xproperty.window);
-
- if (screen != NULL)
- {
- if (event->xproperty.atom ==
- display->atom__NET_DESKTOP_LAYOUT)
- meta_screen_update_workspace_layout (screen);
- else if (event->xproperty.atom ==
- display->atom__NET_DESKTOP_NAMES)
- meta_screen_update_workspace_names (screen);
- else if (meta_is_wayland_compositor () &&
- event->xproperty.atom ==
- display->atom__XKB_RULES_NAMES)
- reload_xkb_rules (screen);
-#if 0
- else if (event->xproperty.atom ==
- display->atom__NET_RESTACK_WINDOW)
- handle_net_restack_window (display, event);
-#endif
-
- /* 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 SelectionClear:
- /* do this here instead of at end of function
- * so we can return
- */
-
- /* FIXME: Clearing display->current_time here makes no sense to
- * me; who put this here and why?
- */
- display->current_time = CurrentTime;
-
- process_selection_clear (display, event);
- /* Note that processing that may have resulted in
- * closing the display... so return right away.
- */
- return FALSE;
- case SelectionRequest:
- process_selection_request (display, event);
- break;
- case SelectionNotify:
- break;
- case ColormapNotify:
- if (window && !frame_was_receiver)
- window->colormap = event->xcolormap.colormap;
- break;
- case ClientMessage:
- if (window)
- {
- if (!frame_was_receiver)
- meta_window_x11_client_message (window, event);
- }
- else
- {
- MetaScreen *screen;
-
- screen = meta_display_screen_for_root (display,
- event->xclient.window);
-
- if (screen)
- {
- 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 (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 (screen, timestamp);
- else
- {
- meta_screen_unshow_desktop (screen);
- meta_workspace_focus_default_window (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;
-}
-
-/**
- * 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;
- MetaMonitorManager *monitor;
- MetaScreen *screen;
-
-#if 0
- meta_spew_event (display, event);
-#endif
-
-#ifdef HAVE_STARTUP_NOTIFICATION
- sn_display_process_event (display->sn_display, event);
-#endif
-
- /* Intercept XRandR events early and don't attempt any
- processing for them. We still let them through to Gdk though,
- so it can update its own internal state.
- */
- monitor = meta_monitor_manager_get ();
- if (meta_monitor_manager_handle_xevent (monitor, event))
- {
- bypass_compositor = TRUE;
- goto out;
- }
-
- 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);
- update_focus_window (display,
- meta_display_lookup_x_window (display, display->server_focus_window),
- display->server_focus_window,
- display->server_focus_serial,
- FALSE);
- }
-
- screen = meta_display_screen_for_root (display, event->xany.window);
- if (screen)
- {
- if (meta_screen_handle_xevent (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;
- }
-
- 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 gboolean
-xevent_callback (XEvent *event,
- gpointer data)
-{
- MetaDisplay *display = data;
-
- return meta_display_handle_xevent (display, event);
-}
-
-static gboolean
-event_callback (const ClutterEvent *event,
- gpointer data)
-{
- MetaDisplay *display = data;
-
- return meta_display_handle_event (display, event);
-}
-
-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:
-#ifdef HAVE_SHAPE
- if (META_DISPLAY_HAS_SHAPE (display) &&
- event->type == (display->shape_event_base + ShapeNotify))
- {
- XShapeEvent *sev = (XShapeEvent*) event;
- return sev->window;
- }
-#endif
-
- 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";
-}
-
-#ifdef HAVE_XSYNC
-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)";
- }
-}
-#endif /* HAVE_XSYNC */
-
-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:
-#ifdef HAVE_XSYNC
- 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
-#endif /* HAVE_XSYNC */
-#ifdef HAVE_SHAPE
- 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
-#endif /* HAVE_SHAPE */
- {
- 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)
-{
- const char *name = NULL;
- char *extra = NULL;
- char *winname;
- MetaScreen *screen;
- 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);
-
- screen = meta_display_screen_for_root (display, event->xany.window);
-
- if (screen)
- 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);
-}
-
MetaWindow*
meta_display_lookup_x_window (MetaDisplay *display,
Window xwindow)
@@ -4020,7 +2057,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
meta_display_set_grab_op_cursor (display, screen, op, grab_xwindow, timestamp);
- if (!display->grab_have_pointer && !grab_op_is_keyboard (op))
+ if (!display->grab_have_pointer && !meta_grab_op_is_keyboard (op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"XIGrabDevice() failed\n");
@@ -4028,7 +2065,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
}
/* Grab keys for keyboard ops and mouse move/resizes; see #126497 */
- if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op))
+ if (meta_grab_op_is_keyboard (op) || grab_op_is_mouse_only (op))
{
if (grab_window)
display->grab_have_keyboard =
@@ -4704,66 +2741,6 @@ meta_display_ping_window (MetaWindow *window,
META_WINDOW_GET_CLASS (window)->ping (window, timestamp);
}
-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;
- MetaScreen *screen;
-
- screen = meta_display_screen_for_xwindow (display,
- event->xclient.window);
- if (screen == NULL)
- {
- meta_warning ("Received request to set _NET_FRAME_EXTENTS "
- "on 0x%lx which is on a screen we are not managing\n",
- event->xclient.window);
- meta_XFree (hints);
- return;
- }
-
- /* Return estimated frame extents for a normal window. */
- meta_ui_theme_get_frame_borders (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);
-}
-
/**
* meta_display_pong_for_serial:
* @display: the display we got the pong from
@@ -5145,222 +3122,6 @@ meta_resize_gravity_from_grab_op (MetaGrabOp op)
return gravity;
}
-static MetaScreen*
-find_screen_for_selection (MetaDisplay *display,
- Window owner,
- Atom selection)
-{
- GSList *tmp;
-
- tmp = display->screens;
- while (tmp != NULL)
- {
- MetaScreen *screen = tmp->data;
-
- if (screen->wm_sn_selection_window == owner &&
- screen->wm_sn_atom == selection)
- return screen;
-
- tmp = tmp->next;
- }
-
- return NULL;
-}
-
-/* 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_with_return (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)
-{
- XSelectionEvent reply;
- MetaScreen *screen;
-
- screen = find_screen_for_selection (display,
- event->xselectionrequest.owner,
- event->xselectionrequest.selection);
-
- if (screen == NULL)
- {
- 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_with_return (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)
-{
- /* We need to unmanage the screen on which we lost the selection */
- MetaScreen *screen;
-
- screen = find_screen_for_selection (display,
- event->xselectionclear.window,
- event->xselectionclear.selection);
-
-
- if (screen != NULL)
- {
- meta_verbose ("Got selection clear for screen %d on display %s\n",
- screen->number, display->name);
-
- meta_display_unmanage_screen (display,
- screen,
- event->xselectionclear.time);
-
- /* display and screen may both be invalid memory... */
-
- return;
- }
-
- {
- 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);
- }
-}
-
void
meta_display_unmanage_screen (MetaDisplay *display,
MetaScreen *screen,
@@ -5584,9 +3345,9 @@ meta_display_focus_sentinel_clear (MetaDisplay *display)
return (display->sentinel_counter == 0);
}
-static void
-sanity_check_timestamps (MetaDisplay *display,
- guint32 timestamp)
+void
+meta_display_sanity_check_timestamps (MetaDisplay *display,
+ guint32 timestamp)
{
if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time))
{
diff --git a/src/core/events.c b/src/core/events.c
new file mode 100644
index 0000000..b37c77a
--- /dev/null
+++ b/src/core/events.c
@@ -0,0 +1,2265 @@
+/* -*- 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 "events.h"
+
+#include <X11/Xatom.h>
+#include <X11/extensions/Xdamage.h>
+#ifdef HAVE_SHAPE
+#include <X11/extensions/shape.h>
+#endif
+
+#include <meta/errors.h>
+#include "display-private.h"
+#include "window-private.h"
+#include "bell.h"
+#include "workspace-private.h"
+#include "meta-idle-monitor-private.h"
+
+#include "x11/window-x11.h"
+#include "x11/xprops.h"
+#include "wayland/meta-wayland-private.h"
+#include "meta-surface-actor-wayland.h"
+
+static MetaWindow *
+get_window_for_event (MetaDisplay *display,
+ const ClutterEvent *event)
+{
+ ClutterActor *source;
+
+ if (display->grab_op != META_GRAB_OP_NONE)
+ return display->grab_window;
+
+ /* Always use the key focused window for key events. */
+ switch (event->type)
+ {
+ case CLUTTER_KEY_PRESS:
+ case CLUTTER_KEY_RELEASE:
+ return display->focus_window;
+ default:
+ break;
+ }
+
+ source = clutter_event_get_source (event);
+ if (META_IS_SURFACE_ACTOR (source))
+ return meta_surface_actor_get_window (META_SURFACE_ACTOR (source));
+
+ 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:
+#ifdef HAVE_SHAPE
+ if (META_DISPLAY_HAS_SHAPE (display) &&
+ event->type == (display->shape_event_base + ShapeNotify))
+ {
+ XShapeEvent *sev = (XShapeEvent*) event;
+ return sev->window;
+ }
+#endif
+
+ 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";
+}
+
+#ifdef HAVE_XSYNC
+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)";
+ }
+}
+#endif /* HAVE_XSYNC */
+
+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:
+#ifdef HAVE_XSYNC
+ 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
+#endif /* HAVE_XSYNC */
+#ifdef HAVE_SHAPE
+ 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
+#endif /* HAVE_SHAPE */
+ {
+ 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)
+{
+ const char *name = NULL;
+ char *extra = NULL;
+ char *winname;
+ MetaScreen *screen;
+ 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);
+
+ screen = meta_display_screen_for_root (display, event->xany.window);
+
+ if (screen)
+ 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 (meta_display_screen_for_root (display, event->event))
+ 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;
+
+ if (input_event == NULL)
+ return FALSE;
+
+ modified = xievent_get_modified_window (display, input_event);
+ window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
+
+ switch (input_event->evtype)
+ {
+ case XI_Enter:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ /* If the mouse switches screens, active the default window on the new
+ * screen; this will make keybindings and workspace-launched items
+ * actually appear on the right screen.
+ */
+ {
+ MetaScreen *new_screen =
+ meta_display_screen_for_root (display, enter_event->root);
+
+ if (new_screen != NULL && display->active_screen != new_screen)
+ meta_workspace_focus_default_window (new_screen->active_workspace,
+ NULL,
+ enter_event->time);
+ }
+
+ /* 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);
+
+ if (window->type == META_WINDOW_DOCK)
+ meta_window_raise (window);
+ }
+ break;
+ case XI_Leave:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ if (window != NULL)
+ {
+ if (window->type == META_WINDOW_DOCK &&
+ enter_event->mode != XINotifyGrab &&
+ enter_event->mode != XINotifyUngrab &&
+ !window->has_focus)
+ meta_window_lower (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;
+
+ screen = meta_display_screen_for_root (display, enter_event->root);
+
+ 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));
+ }
+
+ }
+
+ /* Don't send FocusIn / FocusOut to Clutter */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+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;
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_xwindow (display,
+ event->xclient.window);
+ if (screen == NULL)
+ {
+ meta_warning ("Received request to set _NET_FRAME_EXTENTS "
+ "on 0x%lx which is on a screen we are not managing\n",
+ event->xclient.window);
+ meta_XFree (hints);
+ return;
+ }
+
+ /* Return estimated frame extents for a normal window. */
+ meta_ui_theme_get_frame_borders (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);
+}
+
+static MetaScreen*
+find_screen_for_selection (MetaDisplay *display,
+ Window owner,
+ Atom selection)
+{
+ GSList *tmp;
+
+ tmp = display->screens;
+ while (tmp != NULL)
+ {
+ MetaScreen *screen = tmp->data;
+
+ if (screen->wm_sn_selection_window == owner &&
+ screen->wm_sn_atom == selection)
+ return screen;
+
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
+/* 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_with_return (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)
+{
+ XSelectionEvent reply;
+ MetaScreen *screen;
+
+ screen = find_screen_for_selection (display,
+ event->xselectionrequest.owner,
+ event->xselectionrequest.selection);
+
+ if (screen == NULL)
+ {
+ 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_with_return (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)
+{
+ /* We need to unmanage the screen on which we lost the selection */
+ MetaScreen *screen;
+
+ screen = find_screen_for_selection (display,
+ event->xselectionclear.window,
+ event->xselectionclear.selection);
+
+
+ if (screen != NULL)
+ {
+ meta_verbose ("Got selection clear for screen %d on display %s\n",
+ screen->number, display->name);
+
+ meta_display_unmanage_screen (display,
+ screen,
+ event->xselectionclear.time);
+
+ /* display and screen may both be invalid memory... */
+
+ return;
+ }
+
+ {
+ 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);
+ }
+}
+
+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;
+ }
+
+#ifdef HAVE_XSYNC
+ 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_update_sync_request_counter (alarm_window, new_counter_value);
+ bypass_gtk = TRUE; /* GTK doesn't want to see this really */
+ }
+ else
+ meta_idle_monitor_handle_xevent_all (event);
+
+ goto out;
+ }
+#endif /* HAVE_XSYNC */
+
+#ifdef HAVE_SHAPE
+ 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;
+ }
+#endif /* HAVE_SHAPE */
+
+ switch (event->type)
+ {
+ case KeymapNotify:
+ break;
+ case Expose:
+ break;
+ case GraphicsExpose:
+ break;
+ case NoExpose:
+ break;
+ case VisibilityNotify:
+ break;
+ case CreateNotify:
+ {
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_root (display,
+ event->xcreatewindow.parent);
+ if (screen)
+ meta_stack_tracker_create_event (screen->stack_tracker,
+ &event->xcreatewindow);
+ }
+ break;
+
+ case DestroyNotify:
+ {
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_root (display,
+ event->xdestroywindow.event);
+ if (screen)
+ meta_stack_tracker_destroy_event (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
+ && meta_display_screen_for_root (display, event->xmap.event))
+ {
+ 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:
+ {
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_root (display,
+ event->xconfigure.event);
+ if (screen)
+ meta_stack_tracker_reparent_event (screen->stack_tracker,
+ &event->xreparent);
+ }
+ break;
+ case ConfigureNotify:
+ if (event->xconfigure.event != event->xconfigure.window)
+ {
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_root (display,
+ event->xconfigure.event);
+ if (screen)
+ meta_stack_tracker_configure_event (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;
+ MetaScreen *screen;
+
+ 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);
+
+ screen = NULL;
+ if (window == NULL &&
+ group == NULL) /* window/group != NULL means it wasn't a root window */
+ screen = meta_display_screen_for_root (display,
+ event->xproperty.window);
+
+ if (screen != NULL)
+ {
+ if (event->xproperty.atom ==
+ display->atom__NET_DESKTOP_LAYOUT)
+ meta_screen_update_workspace_layout (screen);
+ else if (event->xproperty.atom ==
+ display->atom__NET_DESKTOP_NAMES)
+ meta_screen_update_workspace_names (screen);
+ else if (meta_is_wayland_compositor () &&
+ event->xproperty.atom ==
+ display->atom__XKB_RULES_NAMES)
+ reload_xkb_rules (screen);
+#if 0
+ else if (event->xproperty.atom ==
+ display->atom__NET_RESTACK_WINDOW)
+ handle_net_restack_window (display, event);
+#endif
+
+ /* 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 SelectionClear:
+ /* do this here instead of at end of function
+ * so we can return
+ */
+
+ /* FIXME: Clearing display->current_time here makes no sense to
+ * me; who put this here and why?
+ */
+ display->current_time = CurrentTime;
+
+ process_selection_clear (display, event);
+ /* Note that processing that may have resulted in
+ * closing the display... so return right away.
+ */
+ return FALSE;
+ case SelectionRequest:
+ process_selection_request (display, event);
+ break;
+ case SelectionNotify:
+ break;
+ case ColormapNotify:
+ if (window && !frame_was_receiver)
+ window->colormap = event->xcolormap.colormap;
+ break;
+ case ClientMessage:
+ if (window)
+ {
+ if (!frame_was_receiver)
+ meta_window_x11_client_message (window, event);
+ }
+ else
+ {
+ MetaScreen *screen;
+
+ screen = meta_display_screen_for_root (display,
+ event->xclient.window);
+
+ if (screen)
+ {
+ 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 (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 (screen, timestamp);
+ else
+ {
+ meta_screen_unshow_desktop (screen);
+ meta_workspace_focus_default_window (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
+grab_op_should_block_mouse_events (MetaGrabOp op)
+{
+ switch (op)
+ {
+ case META_GRAB_OP_WAYLAND_CLIENT:
+ case META_GRAB_OP_COMPOSITOR:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+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;
+ MetaMonitorManager *monitor;
+ MetaScreen *screen;
+
+#if 0
+ meta_spew_event (display, event);
+#endif
+
+#ifdef HAVE_STARTUP_NOTIFICATION
+ sn_display_process_event (display->sn_display, event);
+#endif
+
+ /* Intercept XRandR events early and don't attempt any
+ processing for them. We still let them through to Gdk though,
+ so it can update its own internal state.
+ */
+ monitor = meta_monitor_manager_get ();
+ if (meta_monitor_manager_handle_xevent (monitor, event))
+ {
+ bypass_compositor = TRUE;
+ goto out;
+ }
+
+ 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);
+ }
+
+ screen = meta_display_screen_for_root (display, event->xany.window);
+ if (screen)
+ {
+ if (meta_screen_handle_xevent (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;
+ }
+
+ 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 gboolean
+meta_display_handle_event (MetaDisplay *display,
+ const ClutterEvent *event)
+{
+ MetaWindow *window;
+ gboolean bypass_clutter = FALSE, bypass_wayland = FALSE;
+ MetaWaylandCompositor *compositor = NULL;
+
+ if (meta_is_wayland_compositor ())
+ {
+ compositor = meta_wayland_compositor_get_default ();
+ meta_wayland_compositor_update (compositor, event);
+ }
+
+ window = get_window_for_event (display, event);
+
+ display->current_time = event->any.time;
+
+ if (window && !window->override_redirect &&
+ (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS))
+ {
+ if (CurrentTime == display->current_time)
+ {
+ /* We can't use missing (i.e. invalid) timestamps to set user time,
+ * nor do we want to use them to sanity check other timestamps.
+ * See bug 313490 for more details.
+ */
+ meta_warning ("Event has no timestamp! You may be using a broken "
+ "program such as xse. Please ask the authors of that "
+ "program to fix it.\n");
+ }
+ else
+ {
+ meta_window_set_user_time (window, display->current_time);
+ meta_display_sanity_check_timestamps (display, display->current_time);
+ }
+ }
+
+ switch (event->type)
+ {
+ case CLUTTER_BUTTON_PRESS:
+ if (grab_op_should_block_mouse_events (display->grab_op))
+ break;
+
+ display->overlay_key_only_pressed = FALSE;
+
+ if ((window &&
+ meta_grab_op_is_mouse (display->grab_op) &&
+ (event->button.modifier_state & display->window_grab_modifiers) &&
+ display->grab_button != (int) event->button.button &&
+ display->grab_window == window) ||
+ meta_grab_op_is_keyboard (display->grab_op))
+ {
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Ending grab op %u on window %s due to button press\n",
+ display->grab_op,
+ (display->grab_window ?
+ display->grab_window->desc :
+ "none"));
+ meta_display_end_grab_op (display, event->any.time);
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ else if (window && display->grab_op == META_GRAB_OP_NONE)
+ {
+ ClutterModifierType grab_mask;
+ gboolean unmodified;
+ gboolean fully_modified;
+
+ grab_mask = display->window_grab_modifiers;
+ if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
+ grab_mask |= CLUTTER_CONTROL_MASK;
+
+ /* We have three passive button grabs:
+ * - on any button, without modifiers => focuses and maybe raises the window
+ * - on resize button, with modifiers => start an interactive resizing
+ * (normally <Super>middle)
+ * - on move button, with modifiers => start an interactive move
+ * (normally <Super>left)
+ * - on menu button, with modifiers => show the window menu
+ * (normally <Super>right)
+ *
+ * We may get here because we actually have a button
+ * grab on the window, or because we're a wayland
+ * compositor and thus we see all the events, so we
+ * need to check if the event is interesting.
+ * We want an event that is not modified, for a window
+ * that has (or would have, the wayland case) the
+ * button grab active.
+ *
+ * We may have other events on the window, for example
+ * a click on a frame button, but that's not for us to
+ * care about. Just let the event through.
+ */
+ unmodified = (event->button.modifier_state & grab_mask) == 0;
+ fully_modified = grab_mask && (event->button.modifier_state & grab_mask) == grab_mask;
+
+ if (unmodified && window && window->have_focus_click_grab)
+ {
+ if (meta_prefs_get_raise_on_click ())
+ meta_window_raise (window);
+ else
+ meta_topic (META_DEBUG_FOCUS,
+ "Not raising window on click due to don't-raise-on-click option\n");
+
+ /* Don't focus panels--they must explicitly request focus.
+ * See bug 160470
+ */
+ if (window->type != META_WINDOW_DOCK)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to unmodified button %u press (display.c)\n",
+ window->desc, event->button.button);
+ meta_window_focus (window, event->any.time);
+ }
+ else
+ /* However, do allow terminals to lose focus due to new
+ * window mappings after the user clicks on a panel.
+ */
+ display->allow_terminal_deactivation = TRUE;
+
+ meta_verbose ("Allowing events time %u\n",
+ (unsigned int)event->button.time);
+
+ XIAllowEvents (display->xdisplay, clutter_input_device_get_device_id (event->button.device),
+ XIReplayDevice, event->button.time);
+ bypass_clutter = TRUE;
+ }
+ else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_resize ())
+ {
+ if (window->has_resize_func)
+ {
+ gboolean north, south;
+ gboolean west, east;
+ MetaRectangle frame_rect;
+ MetaGrabOp op;
+
+ meta_window_get_frame_rect (window, &frame_rect);
+
+ west = event->button.x < (frame_rect.x + 1 * frame_rect.width / 3);
+ east = event->button.x > (frame_rect.x + 2 * frame_rect.width / 3);
+ north = event->button.y < (frame_rect.y + 1 * frame_rect.height / 3);
+ south = event->button.y > (frame_rect.y + 2 * frame_rect.height / 3);
+
+ if (north && west)
+ op = META_GRAB_OP_RESIZING_NW;
+ else if (north && east)
+ op = META_GRAB_OP_RESIZING_NE;
+ else if (south && west)
+ op = META_GRAB_OP_RESIZING_SW;
+ else if (south && east)
+ op = META_GRAB_OP_RESIZING_SE;
+ else if (north)
+ op = META_GRAB_OP_RESIZING_N;
+ else if (west)
+ op = META_GRAB_OP_RESIZING_W;
+ else if (east)
+ op = META_GRAB_OP_RESIZING_E;
+ else if (south)
+ op = META_GRAB_OP_RESIZING_S;
+ else /* Middle region is no-op to avoid user triggering wrong action */
+ op = META_GRAB_OP_NONE;
+
+ if (op != META_GRAB_OP_NONE)
+ meta_display_begin_grab_op (display,
+ window->screen,
+ window,
+ op,
+ TRUE,
+ FALSE,
+ event->button.button,
+ 0,
+ event->any.time,
+ event->button.x,
+ event->button.y);
+ }
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_menu ())
+ {
+ if (meta_prefs_get_raise_on_click ())
+ meta_window_raise (window);
+ meta_window_show_menu (window,
+ event->button.x,
+ event->button.y,
+ event->button.button,
+ event->any.time);
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ else if (fully_modified && (int) event->button.button == 1)
+ {
+ if (window->has_move_func)
+ {
+ meta_display_begin_grab_op (display,
+ window->screen,
+ window,
+ META_GRAB_OP_MOVING,
+ TRUE,
+ FALSE,
+ event->button.button,
+ 0,
+ event->any.time,
+ event->button.x,
+ event->button.y);
+ }
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ }
+ break;
+ case CLUTTER_BUTTON_RELEASE:
+ if (grab_op_should_block_mouse_events (display->grab_op))
+ break;
+
+ display->overlay_key_only_pressed = FALSE;
+
+ if (display->grab_window == window &&
+ meta_grab_op_is_mouse (display->grab_op))
+ {
+ meta_window_handle_mouse_grab_op_event (window, event);
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ break;
+ case CLUTTER_MOTION:
+ if (grab_op_should_block_mouse_events (display->grab_op))
+ break;
+
+ if (display->grab_window == window &&
+ meta_grab_op_is_mouse (display->grab_op))
+ {
+ meta_window_handle_mouse_grab_op_event (window, event);
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+ break;
+
+ case CLUTTER_KEY_PRESS:
+ case CLUTTER_KEY_RELEASE:
+ /* For key events, it's important to enforce single-handling, or
+ * we can get into a confused state. So if a keybinding is
+ * handled (because it's one of our hot-keys, or because we are
+ * in a keyboard-grabbed mode like moving a window, we don't
+ * want to pass the key event to the compositor or Wayland at all.
+ */
+ if (meta_display_process_key_event (display, window, (ClutterKeyEvent *) event))
+ {
+ bypass_clutter = TRUE;
+ bypass_wayland = TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ /* If the compositor has a grab, don't pass that through to Wayland */
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ bypass_wayland = TRUE;
+
+ /* If a Wayland client has a grab, don't pass that through to Clutter */
+ if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT)
+ bypass_clutter = TRUE;
+
+ if (compositor && !bypass_wayland)
+ {
+ if (meta_wayland_compositor_handle_event (compositor, event))
+ bypass_clutter = TRUE;
+ }
+
+ return bypass_clutter;
+}
+
+static gboolean
+xevent_callback (XEvent *event,
+ gpointer data)
+{
+ MetaDisplay *display = data;
+
+ return meta_display_handle_xevent (display, event);
+}
+
+static gboolean
+event_callback (const ClutterEvent *event,
+ gpointer data)
+{
+ MetaDisplay *display = data;
+
+ return meta_display_handle_event (display, event);
+}
+
+void
+meta_display_init_events (MetaDisplay *display)
+{
+ meta_ui_add_event_func (display->xdisplay,
+ xevent_callback,
+ display);
+ display->clutter_event_filter = clutter_event_add_filter (NULL,
+ event_callback,
+ NULL,
+ display);
+}
+
+void
+meta_display_free_events (MetaDisplay *display)
+{
+ meta_ui_remove_event_func (display->xdisplay,
+ xevent_callback,
+ 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
new file mode 100644
index 0000000..66a34ca
--- /dev/null
+++ b/src/core/events.h
@@ -0,0 +1,32 @@
+/* -*- 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_H
+#define META_EVENTS_H
+
+void meta_display_init_events (MetaDisplay *display);
+void meta_display_free_events (MetaDisplay *display);
+
+#endif
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]