diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index 5fbdcdf00..be11870cc 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -46,6 +46,10 @@ struct _MetaBackendX11Private int xsync_event_base; int xsync_error_base; + + int xinput_opcode; + int xinput_event_base; + int xinput_error_base; }; typedef struct _MetaBackendX11Private MetaBackendX11Private; @@ -62,6 +66,47 @@ handle_alarm_notify (MetaBackend *backend, meta_idle_monitor_xsync_handle_xevent (backend->device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); } +/* Clutter makes the assumption that there is only one X window + * per stage, which is a valid assumption to make for a generic + * application toolkit. As such, it will ignore any events sent + * to the a stage that isn't its X window. + * + * When running as an X window manager, we need to respond to + * events from lots of windows. Trick Clutter into translating + * these events by pretending we got an event on the stage window. + */ +static void +maybe_spoof_event_as_stage_event (MetaBackendX11 *x11, + XEvent *event) +{ + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + + if (event->type == GenericEvent && + event->xcookie.extension == priv->xinput_opcode) + { + XGetEventData (priv->xdisplay, &event->xcookie); + + XIEvent *input_event = (XIEvent *) event->xcookie.data; + XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); + + switch (input_event->evtype) + { + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_KeyPress: + case XI_KeyRelease: + { + ClutterStage *stage = CLUTTER_STAGE (clutter_stage_get_default ()); + device_event->event = clutter_x11_get_stage_window (stage); + break; + } + default: + break; + } + } +} + static void handle_host_xevent (MetaBackend *backend, XEvent *xevent) @@ -83,6 +128,8 @@ handle_host_xevent (MetaBackend *backend, } } + maybe_spoof_event_as_stage_event (x11, xevent); + out: if (!bypass_clutter) clutter_x11_handle_event (xevent); @@ -181,6 +228,28 @@ meta_backend_x11_post_init (MetaBackend *backend) !XSyncInitialize (priv->xdisplay, &major, &minor)) meta_fatal ("Could not initialize XSync"); + { + int major = 2, minor = 3; + gboolean has_xi = FALSE; + + if (XQueryExtension (priv->xdisplay, + "XInputExtension", + &priv->xinput_opcode, + &priv->xinput_error_base, + &priv->xinput_event_base)) + { + if (XIQueryVersion (priv->xdisplay, &major, &minor) == Success) + { + int version = (major * 10) + minor; + if (version >= 22) + has_xi = TRUE; + } + } + + if (!has_xi) + meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); + } + META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend); } diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 1475deb66..a1ee527b4 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -752,82 +752,6 @@ meta_compositor_window_surface_changed (MetaCompositor *compositor, meta_window_actor_update_surface (window_actor); } -static gboolean -event_is_passive_button_grab (MetaDisplay *display, - XIDeviceEvent *device_event) -{ - /* see display.c for which events are passive button - grabs (meta_display_grab_window_buttons() and - meta_display_handle_events()) - we need to filter them here because normally they - would be sent to gtk+ (they are on gtk+ frame xwindow), - but we want to redirect them to clutter - */ - - if (device_event->evtype != XI_ButtonPress) - return FALSE; - - if (display->window_grab_modifiers == 0) - return FALSE; - - if ((device_event->mods.effective & display->window_grab_modifiers) != - display->window_grab_modifiers) - return FALSE; - - return device_event->detail < 4; -} - -/* Clutter makes the assumption that there is only one X window - * per stage, which is a valid assumption to make for a generic - * application toolkit. As such, it will ignore any events sent - * to the a stage that isn't its X window. - * - * When running as an X window manager, we need to respond to - * events from lots of windows. Trick Clutter into translating - * these events by pretending we got an event on the stage window. - */ -static void -maybe_spoof_event_as_stage_event (MetaCompositor *compositor, - MetaWindow *window, - XEvent *event) -{ - MetaDisplay *display = compositor->display; - - if (event->type == GenericEvent && - event->xcookie.extension == display->xinput_opcode) - { - XIEvent *input_event = (XIEvent *) event->xcookie.data; - XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); - - switch (input_event->evtype) - { - case XI_Motion: - case XI_ButtonPress: - case XI_ButtonRelease: - /* If this is a window frame, and we think GTK+ needs to handle the event, - let GTK+ handle it without mangling */ - if (window && window->frame && device_event->event == window->frame->xwindow && - (meta_grab_op_is_clicking (display->grab_op) || - (display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event)))) - break; - - case XI_KeyPress: - case XI_KeyRelease: - /* If this is a GTK+ widget, like a window menu, let GTK+ handle - * it as-is without mangling. */ - if (meta_ui_window_is_widget (display->screen->ui, device_event->event)) - break; - - device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); - device_event->event_x = device_event->root_x; - device_event->event_y = device_event->root_y; - break; - default: - break; - } - } -} - /** * meta_compositor_process_event: (skip) * @compositor: @@ -840,11 +764,6 @@ meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window) { - MetaDisplay *display = compositor->display; - - if (!meta_is_wayland_compositor ()) - maybe_spoof_event_as_stage_event (compositor, window, event); - if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) return TRUE;