diff --git a/src/Makefile.am b/src/Makefile.am index b5c0d5a37..2e30596aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,6 +135,10 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \ backends/x11/meta-clutter-backend-x11.h \ backends/x11/meta-cursor-renderer-x11.c \ backends/x11/meta-cursor-renderer-x11.h \ + backends/x11/cm/meta-backend-x11-cm.c \ + backends/x11/cm/meta-backend-x11-cm.h \ + backends/x11/nested/meta-backend-x11-nested.c \ + backends/x11/nested/meta-backend-x11-nested.h \ backends/x11/nested/meta-cursor-renderer-x11-nested.c \ backends/x11/nested/meta-cursor-renderer-x11-nested.h \ backends/x11/meta-idle-monitor-xsync.c \ diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c new file mode 100644 index 000000000..ac9fc25fb --- /dev/null +++ b/src/backends/x11/cm/meta-backend-x11-cm.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2017 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/x11/cm/meta-backend-x11-cm.h" + +#include "backends/meta-backend-private.h" +#include "backends/x11/meta-cursor-renderer-x11.h" +#include "backends/x11/meta-monitor-manager-xrandr.h" + +struct _MetaBackendX11Cm +{ + MetaBackendX11 parent; +}; + +G_DEFINE_TYPE (MetaBackendX11Cm, meta_backend_x11_cm, META_TYPE_BACKEND_X11) + +static void +take_touch_grab (MetaBackend *backend) +{ + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { META_VIRTUAL_CORE_POINTER_ID, sizeof (mask_bits), mask_bits }; + XIGrabModifiers mods = { XIAnyModifier, 0 }; + + XISetMask (mask.mask, XI_TouchBegin); + XISetMask (mask.mask, XI_TouchUpdate); + XISetMask (mask.mask, XI_TouchEnd); + + XIGrabTouchBegin (xdisplay, META_VIRTUAL_CORE_POINTER_ID, + DefaultRootWindow (xdisplay), + False, &mask, 1, &mods); +} + +static void +meta_backend_x11_cm_post_init (MetaBackend *backend) +{ + MetaBackendClass *parent_backend_class = + META_BACKEND_CLASS (meta_backend_x11_cm_parent_class); + + parent_backend_class->post_init (backend); + + take_touch_grab (backend); +} + +static MetaMonitorManager * +meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend) +{ + return g_object_new (META_TYPE_MONITOR_MANAGER_XRANDR, NULL); +} + +static MetaCursorRenderer * +meta_backend_x11_cm_create_cursor_renderer (MetaBackend *backend) +{ + return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL); +} + +static void +meta_backend_x11_cm_update_screen_size (MetaBackend *backend, + int width, + int height) +{ + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + Window xwin = meta_backend_x11_get_xwindow (x11); + + XResizeWindow (xdisplay, xwin, width, height); +} + +static void +meta_backend_x11_cm_select_stage_events (MetaBackend *backend) +{ + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + Window xwin = meta_backend_x11_get_xwindow (x11); + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + + XISetMask (mask.mask, XI_KeyPress); + XISetMask (mask.mask, XI_KeyRelease); + XISetMask (mask.mask, XI_ButtonPress); + XISetMask (mask.mask, XI_ButtonRelease); + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + XISetMask (mask.mask, XI_Motion); + + XISelectEvents (xdisplay, xwin, &mask, 1); +} + +static gboolean +meta_backend_x11_cm_handle_host_xevent (MetaBackendX11 *backend_x11, + XEvent *event) +{ + MetaBackend *backend = META_BACKEND (backend_x11); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaMonitorManagerXrandr *monitor_manager_xrandr = + META_MONITOR_MANAGER_XRANDR (monitor_manager); + + return meta_monitor_manager_xrandr_handle_xevent (monitor_manager_xrandr, + event); +} + +static void +meta_backend_x11_cm_translate_device_event (MetaBackendX11 *x11, + XIDeviceEvent *device_event) +{ + Window stage_window = meta_backend_x11_get_xwindow (x11); + + if (device_event->event != stage_window) + { + device_event->event = stage_window; + + /* As an X11 compositor, the stage window is always at 0,0, so + * using root coordinates will give us correct stage coordinates + * as well... */ + device_event->event_x = device_event->root_x; + device_event->event_y = device_event->root_y; + } +} + +static void +meta_backend_x11_cm_translate_crossing_event (MetaBackendX11 *x11, + XIEnterEvent *enter_event) +{ + Window stage_window = meta_backend_x11_get_xwindow (x11); + + if (enter_event->event != stage_window) + { + enter_event->event = stage_window; + enter_event->event_x = enter_event->root_x; + enter_event->event_y = enter_event->root_y; + } +} + +static void +meta_backend_x11_cm_init (MetaBackendX11Cm *backend_x11_cm) +{ +} + +static void +meta_backend_x11_cm_class_init (MetaBackendX11CmClass *klass) +{ + MetaBackendClass *backend_class = META_BACKEND_CLASS (klass); + MetaBackendX11Class *backend_x11_class = META_BACKEND_X11_CLASS (klass); + + backend_class->post_init = meta_backend_x11_cm_post_init; + backend_class->create_monitor_manager = meta_backend_x11_cm_create_monitor_manager; + backend_class->create_cursor_renderer = meta_backend_x11_cm_create_cursor_renderer; + backend_class->update_screen_size = meta_backend_x11_cm_update_screen_size; + backend_class->select_stage_events = meta_backend_x11_cm_select_stage_events; + + backend_x11_class->handle_host_xevent = meta_backend_x11_cm_handle_host_xevent; + backend_x11_class->translate_device_event = meta_backend_x11_cm_translate_device_event; + backend_x11_class->translate_crossing_event = meta_backend_x11_cm_translate_crossing_event; +} + diff --git a/src/backends/x11/cm/meta-backend-x11-cm.h b/src/backends/x11/cm/meta-backend-x11-cm.h new file mode 100644 index 000000000..5332da13d --- /dev/null +++ b/src/backends/x11/cm/meta-backend-x11-cm.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_BACKEND_X11_CM_H +#define META_BACKEND_X11_CM_H + +#include + +#include "backends/x11/meta-backend-x11.h" + +#define META_TYPE_BACKEND_X11_CM (meta_backend_x11_cm_get_type ()) +G_DECLARE_FINAL_TYPE (MetaBackendX11Cm, meta_backend_x11_cm, + META, BACKEND_X11_CM, MetaBackendX11) + +#endif /* META_BACKEND_X11_CM_H */ diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index 9237f2703..92a13dcfa 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -39,30 +39,15 @@ #include #include "meta-idle-monitor-xsync.h" -#include "meta-monitor-manager-xrandr.h" -#include "backends/meta-monitor-manager-dummy.h" #include "backends/meta-stage.h" -#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h" #include "backends/x11/meta-clutter-backend-x11.h" #include "backends/x11/meta-renderer-x11.h" #include "meta/meta-cursor-tracker.h" -#include "meta-cursor-renderer-x11.h" -#ifdef HAVE_WAYLAND -#include "wayland/meta-wayland.h" -#endif #include #include "display-private.h" #include "compositor/compositor-private.h" -typedef enum { - /* We're a traditional CM running under the host. */ - META_BACKEND_X11_MODE_COMPOSITOR, - - /* We're a nested X11 client */ - META_BACKEND_X11_MODE_NESTED, -} MetaBackendX11Mode; - struct _MetaBackendX11Private { /* The host X11 display */ @@ -70,8 +55,6 @@ struct _MetaBackendX11Private xcb_connection_t *xcb; GSource *source; - MetaBackendX11Mode mode; - int xsync_event_base; int xsync_error_base; @@ -106,28 +89,23 @@ handle_alarm_notify (MetaBackend *backend, event); } +static void +meta_backend_x11_translate_device_event (MetaBackendX11 *x11, + XIDeviceEvent *device_event) +{ + MetaBackendX11Class *backend_x11_class = + META_BACKEND_X11_GET_CLASS (x11); + + backend_x11_class->translate_device_event (x11, device_event); +} + static void translate_device_event (MetaBackendX11 *x11, XIDeviceEvent *device_event) { MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - Window stage_window = meta_backend_x11_get_xwindow (x11); - if (device_event->event != stage_window) - { - /* This codepath should only ever trigger as an X11 compositor, - * and never under nested, as under nested all backend events - * should be reported with respect to the stage window. */ - g_assert (priv->mode == META_BACKEND_X11_MODE_COMPOSITOR); - - device_event->event = stage_window; - - /* As an X11 compositor, the stage window is always at 0,0, so - * using root coordinates will give us correct stage coordinates - * as well... */ - device_event->event_x = device_event->root_x; - device_event->event_y = device_event->root_y; - } + meta_backend_x11_translate_device_event (x11, device_event); if (!device_event->send_event && device_event->time != CurrentTime) { @@ -145,12 +123,21 @@ translate_device_event (MetaBackendX11 *x11, } } +static void +meta_backend_x11_translate_crossing_event (MetaBackendX11 *x11, + XIEnterEvent *enter_event) +{ + MetaBackendX11Class *backend_x11_class = + META_BACKEND_X11_GET_CLASS (x11); + + if (backend_x11_class->translate_crossing_event) + backend_x11_class->translate_crossing_event (x11, enter_event); +} + static void translate_crossing_event (MetaBackendX11 *x11, XIEnterEvent *enter_event) { - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - /* Throw out weird events generated by grabs. */ if (enter_event->mode == XINotifyGrab || enter_event->mode == XINotifyUngrab) @@ -159,14 +146,7 @@ translate_crossing_event (MetaBackendX11 *x11, return; } - Window stage_window = meta_backend_x11_get_xwindow (x11); - if (enter_event->event != stage_window && - priv->mode == META_BACKEND_X11_MODE_COMPOSITOR) - { - enter_event->event = meta_backend_x11_get_xwindow (x11); - enter_event->event_x = enter_event->root_x; - enter_event->event_y = enter_event->root_y; - } + meta_backend_x11_translate_crossing_event (x11, enter_event); } static void @@ -254,6 +234,16 @@ keymap_changed (MetaBackend *backend) g_signal_emit_by_name (backend, "keymap-changed", 0); } +static gboolean +meta_backend_x11_handle_host_xevent (MetaBackendX11 *backend_x11, + XEvent *event) +{ + MetaBackendX11Class *backend_x11_class = + META_BACKEND_X11_GET_CLASS (backend_x11); + + return backend_x11_class->handle_host_xevent (backend_x11, event); +} + static void handle_host_xevent (MetaBackend *backend, XEvent *event) @@ -275,24 +265,8 @@ handle_host_xevent (MetaBackend *backend, } } - if (priv->mode == META_BACKEND_X11_MODE_NESTED && event->type == FocusIn) - { -#ifdef HAVE_WAYLAND - Window xwin = meta_backend_x11_get_xwindow(x11); - XEvent xev; - - if (event->xfocus.window == xwin) - { - /* Since we've selected for KeymapStateMask, every FocusIn is followed immediately - * by a KeymapNotify event */ - XMaskEvent(priv->xdisplay, KeymapStateMask, &xev); - MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); - meta_wayland_compositor_update_key_state (compositor, xev.xkeymap.key_vector, 32, 8); - } -#else - g_assert_not_reached (); -#endif - } + bypass_clutter = (meta_backend_x11_handle_host_xevent (x11, event) || + bypass_clutter); if (event->type == (priv->xsync_event_base + XSyncAlarmNotify)) handle_alarm_notify (backend, event); @@ -322,13 +296,6 @@ handle_host_xevent (MetaBackend *backend, } } - { - MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend); - if (META_IS_MONITOR_MANAGER_XRANDR (manager) && - meta_monitor_manager_xrandr_handle_xevent (META_MONITOR_MANAGER_XRANDR (manager), event)) - bypass_clutter = TRUE; - } - if (!bypass_clutter) { handle_input_event (x11, event); @@ -416,24 +383,6 @@ x_event_source_new (MetaBackend *backend) return source; } -static void -take_touch_grab (MetaBackend *backend) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { META_VIRTUAL_CORE_POINTER_ID, sizeof (mask_bits), mask_bits }; - XIGrabModifiers mods = { XIAnyModifier, 0 }; - - XISetMask (mask.mask, XI_TouchBegin); - XISetMask (mask.mask, XI_TouchUpdate); - XISetMask (mask.mask, XI_TouchEnd); - - XIGrabTouchBegin (priv->xdisplay, META_VIRTUAL_CORE_POINTER_ID, - DefaultRootWindow (priv->xdisplay), - False, &mask, 1, &mods); -} - static void on_device_added (ClutterDeviceManager *device_manager, ClutterInputDevice *device, @@ -490,10 +439,6 @@ meta_backend_x11_post_init (MetaBackend *backend) if (!has_xi) meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); - /* We only take the passive touch grab if we are a X11 compositor */ - if (priv->mode == META_BACKEND_X11_MODE_COMPOSITOR) - take_touch_grab (backend); - priv->xcb = XGetXCBConnection (priv->xdisplay); if (!xkb_x11_setup_xkb_extension (priv->xcb, XKB_X11_MIN_MAJOR_XKB_VERSION, @@ -530,42 +475,6 @@ meta_backend_x11_create_idle_monitor (MetaBackend *backend, NULL); } -static MetaMonitorManager * -meta_backend_x11_create_monitor_manager (MetaBackend *backend) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - - switch (priv->mode) - { - case META_BACKEND_X11_MODE_COMPOSITOR: - return g_object_new (META_TYPE_MONITOR_MANAGER_XRANDR, NULL); - case META_BACKEND_X11_MODE_NESTED: - return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL); - default: - g_assert_not_reached (); - } -} - -static MetaCursorRenderer * -meta_backend_x11_create_cursor_renderer (MetaBackend *backend) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - - switch (priv->mode) - { - case META_BACKEND_X11_MODE_COMPOSITOR: - return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL); - break; - case META_BACKEND_X11_MODE_NESTED: - return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, NULL); - break; - default: - g_assert_not_reached (); - } -} - static MetaRenderer * meta_backend_x11_create_renderer (MetaBackend *backend) { @@ -856,79 +765,6 @@ meta_backend_x11_handle_event (MetaBackendX11 *x11, priv->cached_current_logical_monitor = NULL; } -static void -meta_backend_x11_update_screen_size (MetaBackend *backend, - int width, int height) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - - if (priv->mode == META_BACKEND_X11_MODE_NESTED) - { - ClutterActor *stage = meta_backend_get_stage (backend); - MetaRenderer *renderer = meta_backend_get_renderer (backend); - - if (meta_is_stage_views_enabled ()) - meta_renderer_rebuild_views (renderer); - clutter_actor_set_size (stage, width, height); - } - else - { - Window xwin = meta_backend_x11_get_xwindow (x11); - XResizeWindow (priv->xdisplay, xwin, width, height); - } -} - -static void -meta_backend_x11_select_stage_events (MetaBackend *backend) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - Window xwin = meta_backend_x11_get_xwindow (x11); - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - - XISetMask (mask.mask, XI_KeyPress); - XISetMask (mask.mask, XI_KeyRelease); - XISetMask (mask.mask, XI_ButtonPress); - XISetMask (mask.mask, XI_ButtonRelease); - XISetMask (mask.mask, XI_Enter); - XISetMask (mask.mask, XI_Leave); - XISetMask (mask.mask, XI_FocusIn); - XISetMask (mask.mask, XI_FocusOut); - XISetMask (mask.mask, XI_Motion); - - if (priv->mode == META_BACKEND_X11_MODE_NESTED) - { - /* When we're an X11 compositor, we can't take these events or else - * replaying events from our passive root window grab will cause - * them to come back to us. - * - * When we're a nested application, we want to behave like any other - * application, so select these events like normal apps do. - */ - XISetMask (mask.mask, XI_TouchBegin); - XISetMask (mask.mask, XI_TouchEnd); - XISetMask (mask.mask, XI_TouchUpdate); - } - - XISelectEvents (priv->xdisplay, xwin, &mask, 1); - - if (priv->mode == META_BACKEND_X11_MODE_NESTED) - { - /* We have no way of tracking key changes when the stage doesn't have - * focus, so we select for KeymapStateMask so that we get a complete - * dump of the keyboard state in a KeymapNotify event that immediately - * follows each FocusIn (and EnterNotify, but we ignore that.) - */ - XWindowAttributes xwa; - - XGetWindowAttributes(priv->xdisplay, xwin, &xwa); - XSelectInput(priv->xdisplay, xwin, - xwa.your_event_mask | FocusChangeMask | KeymapStateMask); - } -} - static void meta_backend_x11_class_init (MetaBackendX11Class *klass) { @@ -937,8 +773,6 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass) backend_class->create_clutter_backend = meta_backend_x11_create_clutter_backend; backend_class->post_init = meta_backend_x11_post_init; backend_class->create_idle_monitor = meta_backend_x11_create_idle_monitor; - backend_class->create_monitor_manager = meta_backend_x11_create_monitor_manager; - backend_class->create_cursor_renderer = meta_backend_x11_create_cursor_renderer; backend_class->create_renderer = meta_backend_x11_create_renderer; backend_class->grab_device = meta_backend_x11_grab_device; backend_class->ungrab_device = meta_backend_x11_ungrab_device; @@ -947,25 +781,16 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass) backend_class->set_keymap = meta_backend_x11_set_keymap; backend_class->get_keymap = meta_backend_x11_get_keymap; backend_class->lock_layout_group = meta_backend_x11_lock_layout_group; - backend_class->update_screen_size = meta_backend_x11_update_screen_size; - backend_class->select_stage_events = meta_backend_x11_select_stage_events; backend_class->set_numlock = meta_backend_x11_set_numlock; } static void meta_backend_x11_init (MetaBackendX11 *x11) { - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - clutter_x11_request_reset_on_video_memory_purge (); /* We do X11 event retrieval ourselves */ clutter_x11_disable_event_retrieval (); - - if (meta_is_wayland_compositor ()) - priv->mode = META_BACKEND_X11_MODE_NESTED; - else - priv->mode = META_BACKEND_X11_MODE_COMPOSITOR; } Display * diff --git a/src/backends/x11/meta-backend-x11.h b/src/backends/x11/meta-backend-x11.h index 8bb3388a0..9c163eb6b 100644 --- a/src/backends/x11/meta-backend-x11.h +++ b/src/backends/x11/meta-backend-x11.h @@ -38,6 +38,13 @@ G_DECLARE_DERIVABLE_TYPE (MetaBackendX11, meta_backend_x11, struct _MetaBackendX11Class { MetaBackendClass parent_class; + + gboolean (* handle_host_xevent) (MetaBackendX11 *x11, + XEvent *event); + void (* translate_device_event) (MetaBackendX11 *x11, + XIDeviceEvent *device_event); + void (* translate_crossing_event) (MetaBackendX11 *x11, + XIEnterEvent *enter_event); }; Display * meta_backend_x11_get_xdisplay (MetaBackendX11 *backend); diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c new file mode 100644 index 000000000..cf9cea747 --- /dev/null +++ b/src/backends/x11/nested/meta-backend-x11-nested.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/x11/nested/meta-backend-x11-nested.h" + +#include "backends/meta-monitor-manager-dummy.h" +#include "backends/x11/nested/meta-backend-x11-nested.h" +#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h" + +#include "wayland/meta-wayland.h" + +struct _MetaBackendX11Nested +{ + MetaBackendX11 parent; +}; + +G_DEFINE_TYPE (MetaBackendX11Nested, meta_backend_x11_nested, + META_TYPE_BACKEND_X11) + +static MetaMonitorManager * +meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend) +{ + return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL); +} + +static MetaCursorRenderer * +meta_backend_x11_nested_create_cursor_renderer (MetaBackend *backend) +{ + return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, NULL); +} + +static void +meta_backend_x11_nested_update_screen_size (MetaBackend *backend, + int width, + int height) +{ + ClutterActor *stage = meta_backend_get_stage (backend); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + + if (meta_is_stage_views_enabled ()) + meta_renderer_rebuild_views (renderer); + clutter_actor_set_size (stage, width, height); +} + +static void +meta_backend_x11_nested_select_stage_events (MetaBackend *backend) +{ + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + Window xwin = meta_backend_x11_get_xwindow (x11); + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + + XISetMask (mask.mask, XI_KeyPress); + XISetMask (mask.mask, XI_KeyRelease); + XISetMask (mask.mask, XI_ButtonPress); + XISetMask (mask.mask, XI_ButtonRelease); + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + XISetMask (mask.mask, XI_Motion); + + /* + * When we're an X11 compositor, we can't take these events or else replaying + * events from our passive root window grab will cause them to come back to + * us. + * + * When we're a nested application, we want to behave like any other + * application, so select these events like normal apps do. + */ + XISetMask (mask.mask, XI_TouchBegin); XISetMask (mask.mask, XI_TouchEnd); + XISetMask (mask.mask, XI_TouchUpdate); + + XISelectEvents (xdisplay, xwin, &mask, 1); + + /* + * We have no way of tracking key changes when the stage doesn't have focus, + * so we select for KeymapStateMask so that we get a complete dump of the + * keyboard state in a KeymapNotify event that immediately follows each + * FocusIn (and EnterNotify, but we ignore that.) + */ + XWindowAttributes xwa; + + XGetWindowAttributes(xdisplay, xwin, &xwa); + XSelectInput(xdisplay, xwin, + xwa.your_event_mask | FocusChangeMask | KeymapStateMask); +} + +static gboolean +meta_backend_x11_nested_handle_host_xevent (MetaBackendX11 *x11, + XEvent *event) +{ +#ifdef HAVE_WAYLAND + if (event->type == FocusIn) + { + Window xwin = meta_backend_x11_get_xwindow (x11); + XEvent xev; + + if (event->xfocus.window == xwin) + { + MetaWaylandCompositor *compositor = + meta_wayland_compositor_get_default (); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + + /* + * Since we've selected for KeymapStateMask, every FocusIn is + * followed immediately by a KeymapNotify event. + */ + XMaskEvent (xdisplay, KeymapStateMask, &xev); + meta_wayland_compositor_update_key_state (compositor, + xev.xkeymap.key_vector, + 32, 8); + } + } +#endif + + return FALSE; +} + +static void +meta_backend_x11_nested_translate_device_event (MetaBackendX11 *x11, + XIDeviceEvent *device_event) +{ + /* This codepath should only ever trigger as an X11 compositor, + * and never under nested, as under nested all backend events + * should be reported with respect to the stage window. + */ + g_assert (device_event->event == meta_backend_x11_get_xwindow (x11)); +} + +static void +meta_backend_x11_nested_init (MetaBackendX11Nested *backend_x11_nested) +{ +} + +static void +meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass) +{ + MetaBackendClass *backend_class = META_BACKEND_CLASS (klass); + MetaBackendX11Class *backend_x11_class = META_BACKEND_X11_CLASS (klass); + + backend_class->create_monitor_manager = meta_backend_x11_nested_create_monitor_manager; + backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer; + backend_class->update_screen_size = meta_backend_x11_nested_update_screen_size; + backend_class->select_stage_events = meta_backend_x11_nested_select_stage_events; + + backend_x11_class->handle_host_xevent = meta_backend_x11_nested_handle_host_xevent; + backend_x11_class->translate_device_event = meta_backend_x11_nested_translate_device_event; +} diff --git a/src/backends/x11/nested/meta-backend-x11-nested.h b/src/backends/x11/nested/meta-backend-x11-nested.h new file mode 100644 index 000000000..31ae96fa4 --- /dev/null +++ b/src/backends/x11/nested/meta-backend-x11-nested.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 Red Hat + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_BACKEND_X11_NESTED_H +#define META_BACKEND_X11_NESTED_H + +#include + +#include "backends/x11/meta-backend-x11.h" + +#define META_TYPE_BACKEND_X11_NESTED (meta_backend_x11_nested_get_type ()) +G_DECLARE_FINAL_TYPE (MetaBackendX11Nested, meta_backend_x11_nested, + META, BACKEND_X11_NESTED, MetaBackendX11) + +#endif /* META_BACKEND_X11_NESTED_H */ diff --git a/src/core/main.c b/src/core/main.c index dc40f6e0d..9b82ca7be 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -80,10 +80,12 @@ #ifdef HAVE_WAYLAND #include "wayland/meta-wayland.h" +#include "backends/x11/nested/meta-backend-x11-nested.h" # endif #include "backends/meta-backend-private.h" #include "backends/x11/meta-backend-x11.h" +#include "backends/x11/cm/meta-backend-x11-cm.h" #ifdef HAVE_NATIVE_BACKEND #include "backends/native/meta-backend-native.h" @@ -397,6 +399,26 @@ check_for_wayland_session_type (void) } #endif +/* + * Determine the compositor configuration, i.e. whether to run as a Wayland + * compositor, as well as what backend to use. + * + * There are various different flags affecting this: + * + * --nested always forces the use of the nested X11 backend + * --display-server always forces the use of the native backend + * --wayland always forces the compositor type to be a Wayland compositor + * + * If no flag is passed that forces the compositor type, the compositor type + * is determined first from the logind session type, or if that fails, from the + * XDG_SESSION_TYPE enviornment variable. + * + * If no flag is passed that forces the backend type, the backend type is + * determined given the compositor type. If the compositor is a Wayland + * compositor, then the native backend is used, or the nested backend, would + * the native backend not be enabled at build time. If the compositor is not a + * Wayland compositor, then the X11 Compositing Manager backend is used. + */ static void calculate_compositor_configuration (MetaCompositorType *compositor_type, GType *backend_gtype) @@ -413,22 +435,48 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, if (!run_as_wayland_compositor) run_as_wayland_compositor = check_for_wayland_session_type (); +#endif /* HAVE_NATIVE_BACKEND */ -#ifdef CLUTTER_WINDOWING_EGL - if (opt_display_server || (run_as_wayland_compositor && !opt_nested)) - *backend_gtype = META_TYPE_BACKEND_NATIVE; - else -#endif -#endif -#endif - *backend_gtype = META_TYPE_BACKEND_X11; - -#ifdef HAVE_WAYLAND if (run_as_wayland_compositor) *compositor_type = META_COMPOSITOR_TYPE_WAYLAND; else -#endif +#endif /* HAVE_WAYLAND */ *compositor_type = META_COMPOSITOR_TYPE_X11; + + if (opt_nested) + { + *backend_gtype = META_TYPE_BACKEND_X11_NESTED; + return; + } + +#ifdef HAVE_NATIVE_BACKEND + if (opt_display_server) + { + *backend_gtype = META_TYPE_BACKEND_NATIVE; + return; + } + +#ifdef HAVE_WAYLAND + if (run_as_wayland_compositor) + { + *backend_gtype = META_TYPE_BACKEND_NATIVE; + return; + } +#endif /* HAVE_WAYLAND */ +#endif /* HAVE_NATIVE_BACKEND */ + +#ifdef HAVE_WAYLAND + if (run_as_wayland_compositor) + { + *backend_gtype = META_TYPE_BACKEND_X11_NESTED; + return; + } + else +#endif /* HAVE_WAYLAND */ + { + *backend_gtype = META_TYPE_BACKEND_X11_CM; + return; + } } static gboolean _compositor_configuration_overridden = FALSE;