From 984aad4b8624a65bcb2dba7aa794d5d31de0b267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 14 Aug 2019 23:25:54 +0200 Subject: [PATCH] compositor: Move out X11 compositing code into sub type Introduce MetaCompositorX11, dealing with being a X11 compositor, and MetaCompositorServer, being a compositor while also being the display server itself, e.g. a Wayland display server. https://gitlab.gnome.org/GNOME/mutter/merge_requests/727 --- src/backends/meta-dnd-private.h | 9 +- src/backends/x11/cm/meta-backend-x11-cm.c | 23 +- src/backends/x11/meta-backend-x11.c | 26 +- src/compositor/compositor-private.h | 11 +- src/compositor/compositor.c | 423 ++++------------------ src/compositor/meta-compositor-server.c | 54 +++ src/compositor/meta-compositor-server.h | 30 ++ src/compositor/meta-compositor-x11.c | 412 +++++++++++++++++++++ src/compositor/meta-compositor-x11.h | 36 ++ src/compositor/meta-dnd.c | 11 +- src/meson.build | 4 + src/meta/compositor.h | 6 - src/x11/events.c | 17 +- 13 files changed, 679 insertions(+), 383 deletions(-) create mode 100644 src/compositor/meta-compositor-server.c create mode 100644 src/compositor/meta-compositor-server.h create mode 100644 src/compositor/meta-compositor-x11.c create mode 100644 src/compositor/meta-compositor-x11.h diff --git a/src/backends/meta-dnd-private.h b/src/backends/meta-dnd-private.h index 6f39d43ad..0cfb3d788 100644 --- a/src/backends/meta-dnd-private.h +++ b/src/backends/meta-dnd-private.h @@ -24,11 +24,12 @@ #include #include "backends/meta-backend-private.h" +#include "compositor/meta-compositor-x11.h" -gboolean meta_dnd_handle_xdnd_event (MetaBackend *backend, - MetaCompositor *compositor, - Display *xdisplay, - XEvent *xev); +gboolean meta_dnd_handle_xdnd_event (MetaBackend *backend, + MetaCompositorX11 *compositor_x11, + Display *xdisplay, + XEvent *xev); void meta_dnd_init_xdnd (MetaX11Display *x11_display); diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c index 38840b37c..bb1ba4b06 100644 --- a/src/backends/x11/cm/meta-backend-x11-cm.c +++ b/src/backends/x11/cm/meta-backend-x11-cm.c @@ -27,11 +27,14 @@ #include #include "backends/meta-backend-private.h" +#include "backends/meta-dnd-private.h" #include "backends/x11/meta-cursor-renderer-x11.h" #include "backends/x11/meta-gpu-xrandr.h" #include "backends/x11/meta-input-settings-x11.h" #include "backends/x11/meta-monitor-manager-xrandr.h" #include "backends/x11/cm/meta-renderer-x11-cm.h" +#include "compositor/meta-compositor-x11.h" +#include "core/display-private.h" struct _MetaBackendX11Cm { @@ -328,6 +331,20 @@ meta_backend_x11_cm_handle_host_xevent (MetaBackendX11 *backend_x11, MetaMonitorManagerXrandr *monitor_manager_xrandr = META_MONITOR_MANAGER_XRANDR (monitor_manager); Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + gboolean bypass_clutter = FALSE; + MetaDisplay *display; + + display = meta_get_display (); + if (display) + { + MetaCompositor *compositor = display->compositor; + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); + Display *xdisplay = meta_backend_x11_get_xdisplay (x11); + + if (meta_dnd_handle_xdnd_event (backend, compositor_x11, + xdisplay, event)) + bypass_clutter = TRUE; + } if (event->type == meta_backend_x11_get_xkb_event_base (x11)) { @@ -351,8 +368,10 @@ meta_backend_x11_cm_handle_host_xevent (MetaBackendX11 *backend_x11, } } - return meta_monitor_manager_xrandr_handle_xevent (monitor_manager_xrandr, - event); + bypass_clutter |= + meta_monitor_manager_xrandr_handle_xevent (monitor_manager_xrandr, event); + + return bypass_clutter; } static void diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index dcdbadef3..75fb1341f 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -42,7 +42,6 @@ #include #include -#include "backends/meta-dnd-private.h" #include "backends/meta-idle-monitor-private.h" #include "backends/meta-stage-private.h" #include "backends/x11/meta-clutter-backend-x11.h" @@ -326,25 +325,20 @@ handle_host_xevent (MetaBackend *backend, MetaBackendX11 *x11 = META_BACKEND_X11 (backend); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); gboolean bypass_clutter = FALSE; + MetaDisplay *display; XGetEventData (priv->xdisplay, &event->xcookie); - { - MetaDisplay *display = meta_get_display (); + display = meta_get_display (); + if (display) + { + MetaCompositor *compositor = display->compositor; + MetaPluginManager *plugin_mgr = + meta_compositor_get_plugin_manager (compositor); - if (display) - { - MetaCompositor *compositor = display->compositor; - MetaPluginManager *plugin_mgr = - meta_compositor_get_plugin_manager (compositor); - - if (meta_plugin_manager_xevent_filter (plugin_mgr, event)) - bypass_clutter = TRUE; - - if (meta_dnd_handle_xdnd_event (backend, compositor, priv->xdisplay, event)) - bypass_clutter = TRUE; - } - } + if (meta_plugin_manager_xevent_filter (plugin_mgr, event)) + bypass_clutter = TRUE; + } bypass_clutter = (meta_backend_x11_handle_host_xevent (x11, event) || bypass_clutter); diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 6968469ba..8935732ba 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -17,6 +17,13 @@ struct _MetaCompositorClass { GObjectClass parent_class; + + void (* manage) (MetaCompositor *compositor); + void (* unmanage) (MetaCompositor *compositor); + void (* pre_paint) (MetaCompositor *compositor); + void (* post_paint) (MetaCompositor *compositor); + void (* remove_window) (MetaCompositor *compositor, + MetaWindow *window); }; void meta_compositor_remove_window_actor (MetaCompositor *compositor, @@ -50,9 +57,11 @@ void meta_compositor_locate_pointer (MetaCompositor *compositor); void meta_compositor_redirect_x11_windows (MetaCompositor *compositor); +gboolean meta_compositor_is_unredirect_inhibited (MetaCompositor *compositor); + MetaDisplay * meta_compositor_get_display (MetaCompositor *compositor); -Window meta_compositor_get_output_xwindow (MetaCompositor *compositor); +MetaWindowActor * meta_compositor_get_top_window_actor (MetaCompositor *compositor); ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor); diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index c787a00f4..c8b3e303d 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -54,14 +54,11 @@ #include "compositor/compositor-private.h" -#include #include #include "backends/meta-dnd-private.h" -#include "backends/x11/meta-backend-x11.h" #include "clutter/clutter-mutter.h" -#include "clutter/x11/clutter-x11.h" -#include "compositor/meta-sync-ring.h" +#include "compositor/meta-compositor-x11.h" #include "compositor/meta-window-actor-x11.h" #include "compositor/meta-window-actor-wayland.h" #include "compositor/meta-window-actor-private.h" @@ -83,6 +80,7 @@ #include "x11/meta-x11-display-private.h" #ifdef HAVE_WAYLAND +#include "compositor/meta-compositor-server.h" #include "wayland/meta-wayland-private.h" #endif @@ -110,26 +108,21 @@ typedef struct _MetaCompositorPrivate ClutterActor *feedback_group; GList *windows; - Window output; CoglContext *context; MetaWindowActor *top_window_actor; gulong top_window_actor_destroy_id; - /* Used for unredirecting fullscreen windows */ int disable_unredirect_count; - MetaWindow *unredirected_window; int switch_workspace_in_progress; MetaPluginManager *plugin_mgr; - - gboolean frame_has_updated_xsurfaces; - gboolean have_x11_sync_object; } MetaCompositorPrivate; -G_DEFINE_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, G_TYPE_OBJECT) +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor, + G_TYPE_OBJECT) static void on_presented (ClutterStage *stage, @@ -189,20 +182,6 @@ meta_compositor_destroy (MetaCompositor *compositor) g_object_unref (compositor); } -static void -process_damage (MetaCompositor *compositor, - XDamageNotifyEvent *event, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_process_x11_damage (window_actor, event); - - priv->frame_has_updated_xsurfaces = TRUE; -} - /* compat helper */ static MetaCompositor * get_compositor_for_display (MetaDisplay *display) @@ -290,50 +269,6 @@ meta_get_window_actors (MetaDisplay *display) return priv->windows; } -void -meta_set_stage_input_region (MetaDisplay *display, - XserverRegion region) -{ - /* As a wayland compositor we can simply ignore all this trickery - * for setting an input region on the stage for capturing events in - * clutter since all input comes to us first and we get to choose - * who else sees them. - */ - if (!meta_is_wayland_compositor ()) - { - MetaCompositor *compositor = display->compositor; - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - Display *xdpy = meta_x11_display_get_xdisplay (display->x11_display); - Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (priv->stage)); - - XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); - - /* It's generally a good heuristic that when a crossing event is generated because - * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - - * it's not the user doing something, it's the environment changing under the user. - */ - meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); - XFixesSetWindowShapeRegion (xdpy, priv->output, ShapeInput, 0, 0, region); - } -} - -void -meta_empty_stage_input_region (MetaDisplay *display) -{ - /* Using a static region here is a bit hacky, but Metacity never opens more than - * one XDisplay, so it works fine. */ - static XserverRegion region = None; - - if (region == None) - { - Display *xdpy = meta_x11_display_get_xdisplay (display->x11_display); - region = XFixesCreateRegion (xdpy, NULL, 0); - } - - meta_set_stage_input_region (display, region); -} - void meta_focus_stage_window (MetaDisplay *display, guint32 timestamp) @@ -584,14 +519,10 @@ meta_compositor_manage (MetaCompositor *compositor) MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); MetaDisplay *display = priv->display; - Display *xdisplay = NULL; MetaBackend *backend = meta_get_backend (); if (display->x11_display) - { - xdisplay = display->x11_display->xdisplay; - meta_x11_display_set_cm_selection (display->x11_display); - } + meta_x11_display_set_cm_selection (display->x11_display); priv->stage = meta_backend_get_stage (backend); @@ -622,42 +553,7 @@ meta_compositor_manage (MetaCompositor *compositor) clutter_actor_add_child (priv->stage, priv->top_window_group); clutter_actor_add_child (priv->stage, priv->feedback_group); - if (meta_is_wayland_compositor ()) - { - /* NB: When running as a wayland compositor we don't need an X - * composite overlay window, and we don't need to play any input - * region tricks to redirect events into clutter. */ - priv->output = None; - } - else - { - Window xwin; - - priv->output = display->x11_display->composite_overlay_window; - - xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); - - XReparentWindow (xdisplay, xwin, priv->output, 0, 0); - - meta_empty_stage_input_region (display); - - /* Make sure there isn't any left-over output shape on the - * overlay window by setting the whole screen to be an - * output region. - * - * Note: there doesn't seem to be any real chance of that - * because the X server will destroy the overlay window - * when the last client using it exits. - */ - XFixesSetWindowShapeRegion (xdisplay, priv->output, ShapeBounding, 0, 0, None); - - /* Map overlay window before redirecting windows offscreen so we catch their - * contents until we show the stage. - */ - XMapWindow (xdisplay, priv->output); - - priv->have_x11_sync_object = meta_sync_ring_init (xdisplay); - } + META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor); meta_compositor_redirect_x11_windows (compositor); @@ -667,103 +563,7 @@ meta_compositor_manage (MetaCompositor *compositor) void meta_compositor_unmanage (MetaCompositor *compositor) { - if (!meta_is_wayland_compositor ()) - { - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaX11Display *display = priv->display->x11_display; - Display *xdisplay = display->xdisplay; - Window xroot = display->xroot; - - /* This is the most important part of cleanup - we have to do this - * before giving up the window manager selection or the next - * window manager won't be able to redirect subwindows */ - XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); - } -} - -/** - * meta_shape_cow_for_window: - * @compositor: A #MetaCompositor - * @window: (nullable): A #MetaWindow to shape the COW for - * - * Sets an bounding shape on the COW so that the given window - * is exposed. If @window is %NULL it clears the shape again. - * - * Used so we can unredirect windows, by shaping away the part - * of the COW, letting the raw window be seen through below. - */ -static void -meta_shape_cow_for_window (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaDisplay *display = priv->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); - - if (window == NULL) - { - XFixesSetWindowShapeRegion (xdisplay, priv->output, - ShapeBounding, 0, 0, None); - } - else - { - XserverRegion output_region; - XRectangle screen_rect, window_bounds; - int width, height; - MetaRectangle rect; - - meta_window_get_frame_rect (window, &rect); - - window_bounds.x = rect.x; - window_bounds.y = rect.y; - window_bounds.width = rect.width; - window_bounds.height = rect.height; - - meta_display_get_size (display, &width, &height); - screen_rect.x = 0; - screen_rect.y = 0; - screen_rect.width = width; - screen_rect.height = height; - - output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); - - XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); - XFixesSetWindowShapeRegion (xdisplay, priv->output, - ShapeBounding, 0, 0, output_region); - XFixesDestroyRegion (xdisplay, output_region); - } -} - -static void -set_unredirected_window (MetaCompositor *compositor, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - if (priv->unredirected_window == window) - return; - - if (priv->unredirected_window != NULL) - { - MetaWindowActor *window_actor; - - window_actor = meta_window_actor_from_window (priv->unredirected_window); - meta_window_actor_set_unredirected (window_actor, FALSE); - } - - meta_shape_cow_for_window (compositor, window); - priv->unredirected_window = window; - - if (priv->unredirected_window != NULL) - { - MetaWindowActor *window_actor; - - window_actor = meta_window_actor_from_window (priv->unredirected_window); - meta_window_actor_set_unredirected (window_actor, TRUE); - } + META_COMPOSITOR_GET_CLASS (compositor)->unmanage (compositor); } void @@ -805,18 +605,20 @@ meta_compositor_add_window (MetaCompositor *compositor, sync_actor_stacking (compositor); } +static void +meta_compositor_real_remove_window (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaWindowActor *window_actor = meta_window_actor_from_window (window); + + meta_window_actor_queue_destroy (window_actor); +} + void meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window) { - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - if (priv->unredirected_window == window) - set_unredirected_window (compositor, NULL); - - meta_window_actor_queue_destroy (window_actor); + META_COMPOSITOR_GET_CLASS (compositor)->remove_window (compositor, window); } void @@ -874,53 +676,6 @@ meta_compositor_window_opacity_changed (MetaCompositor *compositor, meta_window_actor_update_opacity (window_actor); } -/** - * meta_compositor_process_event: (skip) - * @compositor: - * @event: - * @window: - * - */ -gboolean -meta_compositor_process_event (MetaCompositor *compositor, - XEvent *event, - MetaWindow *window) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - MetaX11Display *x11_display = priv->display->x11_display; - - if (!meta_is_wayland_compositor () && - event->type == meta_x11_display_get_damage_event_base (x11_display) + XDamageNotify) - { - /* Core code doesn't handle damage events, so we need to extract the MetaWindow - * ourselves - */ - if (window == NULL) - { - Window xwin = ((XDamageNotifyEvent *) event)->drawable; - window = meta_x11_display_lookup_x_window (x11_display, xwin); - } - - if (window) - process_damage (compositor, (XDamageNotifyEvent *) event, window); - } - - if (priv->have_x11_sync_object) - meta_sync_ring_handle_event (event); - - /* Clutter needs to know about MapNotify events otherwise it will - think the stage is invisible */ - if (!meta_is_wayland_compositor () && event->type == MapNotify) - clutter_x11_handle_event (event); - - /* The above handling is basically just "observing" the events, so we return - * FALSE to indicate that the event should not be filtered out; if we have - * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example. - */ - return FALSE; -} - gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, MetaKeyBinding *binding) @@ -1299,85 +1054,40 @@ on_presented (ClutterStage *stage, } } +static void +meta_compositor_real_pre_paint (MetaCompositor *compositor) +{ + MetaCompositorPrivate *priv = + meta_compositor_get_instance_private (compositor); + GList *l; + + for (l = priv->windows; l; l = l->next) + meta_window_actor_pre_paint (l->data); +} + +static void +meta_compositor_pre_paint (MetaCompositor *compositor) +{ + META_COMPOSITOR_GET_CLASS (compositor)->pre_paint (compositor); +} + static gboolean meta_pre_paint_func (gpointer data) { MetaCompositor *compositor = data; - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - GList *l; - MetaWindowActor *top_window_actor; - if (priv->windows == NULL) - return TRUE; - - top_window_actor = priv->top_window_actor; - if (top_window_actor && - meta_window_actor_should_unredirect (top_window_actor) && - priv->disable_unredirect_count == 0) - { - MetaWindow *top_window; - - top_window = meta_window_actor_get_meta_window (top_window_actor); - set_unredirected_window (compositor, top_window); - } - else - { - set_unredirected_window (compositor, NULL); - } - - for (l = priv->windows; l; l = l->next) - meta_window_actor_pre_paint (l->data); - - if (priv->frame_has_updated_xsurfaces) - { - /* We need to make sure that any X drawing that happens before - * the XDamageSubtract() for each window above is visible to - * subsequent GL rendering; the standardized way to do this is - * GL_EXT_X11_sync_object. Since this isn't implemented yet in - * mesa, we also have a path that relies on the implementation - * of the open source drivers. - * - * Anything else, we just hope for the best. - * - * Xorg and open source driver specifics: - * - * The X server makes sure to flush drawing to the kernel before - * sending out damage events, but since we use - * DamageReportBoundingBox there may be drawing between the last - * damage event and the XDamageSubtract() that needs to be - * flushed as well. - * - * Xorg always makes sure that drawing is flushed to the kernel - * before writing events or responses to the client, so any - * round trip request at this point is sufficient to flush the - * GLX buffers. - */ - if (priv->have_x11_sync_object) - priv->have_x11_sync_object = meta_sync_ring_insert_wait (); - else - XSync (priv->display->x11_display->xdisplay, False); - } + meta_compositor_pre_paint (compositor); return TRUE; } -static gboolean -meta_post_paint_func (gpointer data) +static void +meta_compositor_real_post_paint (MetaCompositor *compositor) { - MetaCompositor *compositor = data; MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); CoglGraphicsResetStatus status; - if (priv->frame_has_updated_xsurfaces) - { - if (priv->have_x11_sync_object) - priv->have_x11_sync_object = meta_sync_ring_after_frame (); - - priv->frame_has_updated_xsurfaces = FALSE; - } - status = cogl_get_graphics_reset_status (priv->context); switch (status) { @@ -1400,6 +1110,20 @@ meta_post_paint_func (gpointer data) meta_restart (NULL); break; } +} + +static void +meta_compositor_post_paint (MetaCompositor *compositor) +{ + META_COMPOSITOR_GET_CLASS (compositor)->post_paint (compositor); +} + +static gboolean +meta_post_paint_func (gpointer data) +{ + MetaCompositor *compositor = data; + + meta_compositor_post_paint (compositor); return TRUE; } @@ -1427,7 +1151,13 @@ meta_compositor_new (MetaDisplay *display) MetaCompositor *compositor; MetaCompositorPrivate *priv; - compositor = g_object_new (META_TYPE_COMPOSITOR, NULL); +#ifdef HAVE_WAYLAND + if (meta_is_wayland_compositor ()) + compositor = g_object_new (META_TYPE_COMPOSITOR_SERVER, NULL); + else +#endif + compositor = g_object_new (META_TYPE_COMPOSITOR_X11, NULL); + priv = meta_compositor_get_instance_private (compositor); priv->display = display; @@ -1484,12 +1214,6 @@ meta_compositor_dispose (GObject *object) g_clear_pointer (&priv->feedback_group, clutter_actor_destroy); g_clear_pointer (&priv->windows, g_list_free); - if (priv->have_x11_sync_object) - { - meta_sync_ring_destroy (); - priv->have_x11_sync_object = FALSE; - } - G_OBJECT_CLASS (meta_compositor_parent_class)->dispose (object); } @@ -1499,6 +1223,10 @@ meta_compositor_class_init (MetaCompositorClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = meta_compositor_dispose; + + klass->remove_window = meta_compositor_real_remove_window; + klass->pre_paint = meta_compositor_real_pre_paint; + klass->post_paint = meta_compositor_real_post_paint; } /** @@ -1539,6 +1267,15 @@ meta_enable_unredirect_for_display (MetaDisplay *display) priv->disable_unredirect_count--; } +gboolean +meta_compositor_is_unredirect_inhibited (MetaCompositor *compositor) +{ + MetaCompositorPrivate *priv = + meta_compositor_get_instance_private (compositor); + + return priv->disable_unredirect_count > 0; +} + #define FLASH_TIME_MS 50 static void @@ -1771,15 +1508,6 @@ meta_compositor_get_display (MetaCompositor *compositor) return priv->display; } -Window -meta_compositor_get_output_xwindow (MetaCompositor *compositor) -{ - MetaCompositorPrivate *priv = - meta_compositor_get_instance_private (compositor); - - return priv->output; -} - ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor) { @@ -1789,6 +1517,15 @@ meta_compositor_get_stage (MetaCompositor *compositor) return CLUTTER_STAGE (priv->stage); } +MetaWindowActor * +meta_compositor_get_top_window_actor (MetaCompositor *compositor) +{ + MetaCompositorPrivate *priv = + meta_compositor_get_instance_private (compositor); + + return priv->top_window_actor; +} + gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor) { diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c new file mode 100644 index 000000000..206586c06 --- /dev/null +++ b/src/compositor/meta-compositor-server.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * 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 "compositor/meta-compositor-server.h" + +struct _MetaCompositorServer +{ + MetaCompositor parent; +}; + +G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR) + +static void +meta_compositor_server_manage (MetaCompositor *compositor) +{ +} + +static void +meta_compositor_server_unmanage (MetaCompositor *compositor) +{ +} + +static void +meta_compositor_server_init (MetaCompositorServer *compositor_server) +{ +} + +static void +meta_compositor_server_class_init (MetaCompositorServerClass *klass) +{ + MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + + compositor_class->manage = meta_compositor_server_manage; + compositor_class->unmanage = meta_compositor_server_unmanage; +} diff --git a/src/compositor/meta-compositor-server.h b/src/compositor/meta-compositor-server.h new file mode 100644 index 000000000..b16971ae3 --- /dev/null +++ b/src/compositor/meta-compositor-server.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * 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_COMPOSITOR_SERVER_H +#define META_COMPOSITOR_SERVER_H + +#include "compositor/compositor-private.h" + +#define META_TYPE_COMPOSITOR_SERVER (meta_compositor_server_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCompositorServer, meta_compositor_server, + META, COMPOSITOR_SERVER, MetaCompositor) + +#endif /* META_COMPOSITOR_SERVER_H */ diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c new file mode 100644 index 000000000..de10628d1 --- /dev/null +++ b/src/compositor/meta-compositor-x11.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * 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 "compositor/meta-compositor-x11.h" + +#include +#include + +#include "backends/x11/meta-backend-x11.h" +#include "clutter/x11/clutter-x11.h" +#include "compositor/meta-sync-ring.h" +#include "core/display-private.h" +#include "x11/meta-x11-display-private.h" + +struct _MetaCompositorX11 +{ + MetaCompositor parent; + + Window output; + + gboolean frame_has_updated_xsurfaces; + gboolean have_x11_sync_object; + + MetaWindow *unredirected_window; +}; + +G_DEFINE_TYPE (MetaCompositorX11, meta_compositor_x11, META_TYPE_COMPOSITOR) + +static void +process_damage (MetaCompositorX11 *compositor_x11, + XDamageNotifyEvent *damage_xevent, + MetaWindow *window) +{ + MetaWindowActor *window_actor = meta_window_actor_from_window (window); + + meta_window_actor_process_x11_damage (window_actor, damage_xevent); + + compositor_x11->frame_has_updated_xsurfaces = TRUE; +} + +void +meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + XEvent *xevent, + MetaWindow *window) +{ + MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); + MetaDisplay *display = meta_compositor_get_display (compositor); + MetaX11Display *x11_display = display->x11_display; + int damage_event_base; + + damage_event_base = meta_x11_display_get_damage_event_base (x11_display); + if (xevent->type == damage_event_base + XDamageNotify) + { + /* + * Core code doesn't handle damage events, so we need to extract the + * MetaWindow ourselves. + */ + if (!window) + { + Window xwindow; + + xwindow = ((XDamageNotifyEvent *) xevent)->drawable; + window = meta_x11_display_lookup_x_window (x11_display, xwindow); + } + + if (window) + process_damage (compositor_x11, (XDamageNotifyEvent *) xevent, window); + } + + if (compositor_x11->have_x11_sync_object) + meta_sync_ring_handle_event (xevent); + + /* + * Clutter needs to know about MapNotify events otherwise it will think the + * stage is invisible + */ + if (xevent->type == MapNotify) + clutter_x11_handle_event (xevent); +} + +void +meta_set_stage_input_region (MetaDisplay *display, + XserverRegion region) +{ + MetaCompositor *compositor = display->compositor; + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (display->compositor); + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + ClutterStage *stage = meta_compositor_get_stage (compositor); + Window xstage; + + /* + * As a wayland compositor we can simply ignore all this trickery + * for setting an input region on the stage for capturing events in + * clutter since all input comes to us first and we get to choose + * who else sees them. + */ + if (meta_is_wayland_compositor ()) + return; + + xstage = clutter_x11_get_stage_window (stage); + XFixesSetWindowShapeRegion (xdisplay, xstage, ShapeInput, 0, 0, region); + + /* + * It's generally a good heuristic that when a crossing event is generated + * because we reshape the overlay, we don't want it to affect + * focus-follows-mouse focus - it's not the user doing something, it's the + * environment changing under the user. + */ + meta_display_add_ignored_crossing_serial (display, XNextRequest (xdisplay)); + XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, + ShapeInput, 0, 0, region); +} + +void +meta_empty_stage_input_region (MetaDisplay *display) +{ + /* + * Using a static region here is a bit hacky, but when running as X11 + * compositing manager we only ever open a single XDisplay. + */ + static XserverRegion region = None; + + if (meta_is_wayland_compositor ()) + return; + + if (region == None) + { + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + + region = XFixesCreateRegion (xdisplay, NULL, 0); + } + + meta_set_stage_input_region (display, region); +} + +static void +meta_compositor_x11_manage (MetaCompositor *compositor) +{ + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); + MetaDisplay *display = meta_compositor_get_display (compositor); + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + MetaBackend *backend = meta_get_backend (); + Window xwindow; + + compositor_x11->output = display->x11_display->composite_overlay_window; + + xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); + + XReparentWindow (xdisplay, xwindow, compositor_x11->output, 0, 0); + + meta_empty_stage_input_region (display); + + /* + * Make sure there isn't any left-over output shape on the overlay window by + * setting the whole screen to be an output region. + * + * Note: there doesn't seem to be any real chance of that because the X + * server will destroy the overlay window when the last client using it + * exits. + */ + XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, + ShapeBounding, 0, 0, None); + + /* + * Map overlay window before redirecting windows offscreen so we catch their + * contents until we show the stage. + */ + XMapWindow (xdisplay, compositor_x11->output); + + compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay); +} + +static void +meta_compositor_x11_unmanage (MetaCompositor *compositor) +{ + MetaDisplay *display = meta_compositor_get_display (compositor); + MetaX11Display *x11_display = display->x11_display; + Display *xdisplay = x11_display->xdisplay; + Window xroot = x11_display->xroot; + + /* + * This is the most important part of cleanup - we have to do this before + * giving up the window manager selection or the next window manager won't be + * able to redirect subwindows + */ + XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); +} + +/* + * Sets an bounding shape on the COW so that the given window + * is exposed. If window is %NULL it clears the shape again. + * + * Used so we can unredirect windows, by shaping away the part + * of the COW, letting the raw window be seen through below. + */ +static void +shape_cow_for_window (MetaCompositorX11 *compositor_x11, + MetaWindow *window) +{ + MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); + MetaDisplay *display = meta_compositor_get_display (compositor); + Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + + if (!window) + { + XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, + ShapeBounding, 0, 0, None); + } + else + { + XserverRegion output_region; + XRectangle screen_rect, window_bounds; + int width, height; + MetaRectangle rect; + + meta_window_get_frame_rect (window, &rect); + + window_bounds.x = rect.x; + window_bounds.y = rect.y; + window_bounds.width = rect.width; + window_bounds.height = rect.height; + + meta_display_get_size (display, &width, &height); + screen_rect.x = 0; + screen_rect.y = 0; + screen_rect.width = width; + screen_rect.height = height; + + output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); + + XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); + XFixesSetWindowShapeRegion (xdisplay, compositor_x11->output, + ShapeBounding, 0, 0, output_region); + XFixesDestroyRegion (xdisplay, output_region); + } +} + +static void +set_unredirected_window (MetaCompositorX11 *compositor_x11, + MetaWindow *window) +{ + MetaWindow *prev_unredirected_window = compositor_x11->unredirected_window; + + if (prev_unredirected_window == window) + return; + + if (prev_unredirected_window) + { + MetaWindowActor *window_actor; + + window_actor = meta_window_actor_from_window (prev_unredirected_window); + meta_window_actor_set_unredirected (window_actor, FALSE); + } + + shape_cow_for_window (compositor_x11, window); + compositor_x11->unredirected_window = window; + + if (window) + { + MetaWindowActor *window_actor; + + window_actor = meta_window_actor_from_window (window); + meta_window_actor_set_unredirected (window_actor, TRUE); + } +} + +static void +meta_compositor_x11_pre_paint (MetaCompositor *compositor) +{ + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); + MetaWindowActor *top_window_actor; + MetaCompositorClass *parent_class; + + top_window_actor = meta_compositor_get_top_window_actor (compositor); + if (!meta_compositor_is_unredirect_inhibited (compositor) && + top_window_actor && + meta_window_actor_should_unredirect (top_window_actor)) + { + MetaWindow *top_window; + + top_window = meta_window_actor_get_meta_window (top_window_actor); + set_unredirected_window (compositor_x11, top_window); + } + else + { + set_unredirected_window (compositor_x11, NULL); + } + + parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); + parent_class->pre_paint (compositor); + + if (compositor_x11->frame_has_updated_xsurfaces) + { + MetaDisplay *display = meta_compositor_get_display (compositor); + + /* + * We need to make sure that any X drawing that happens before the + * XDamageSubtract() for each window above is visible to subsequent GL + * rendering; the standardized way to do this is GL_EXT_X11_sync_object. + * Since this isn't implemented yet in mesa, we also have a path that + * relies on the implementation of the open source drivers. + * + * Anything else, we just hope for the best. + * + * Xorg and open source driver specifics: + * + * The X server makes sure to flush drawing to the kernel before sending + * out damage events, but since we use DamageReportBoundingBox there may + * be drawing between the last damage event and the XDamageSubtract() + * that needs to be flushed as well. + * + * Xorg always makes sure that drawing is flushed to the kernel before + * writing events or responses to the client, so any round trip request + * at this point is sufficient to flush the GLX buffers. + */ + if (compositor_x11->have_x11_sync_object) + compositor_x11->have_x11_sync_object = meta_sync_ring_insert_wait (); + else + XSync (display->x11_display->xdisplay, False); + } +} + +static void +meta_compositor_x11_post_paint (MetaCompositor *compositor) +{ + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); + MetaCompositorClass *parent_class; + + if (compositor_x11->frame_has_updated_xsurfaces) + { + if (compositor_x11->have_x11_sync_object) + compositor_x11->have_x11_sync_object = meta_sync_ring_after_frame (); + + compositor_x11->frame_has_updated_xsurfaces = FALSE; + } + + parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); + parent_class->post_paint (compositor); +} + +static void +meta_compositor_x11_remove_window (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor); + MetaCompositorClass *parent_class; + + if (compositor_x11->unredirected_window == window) + set_unredirected_window (compositor_x11, NULL); + + parent_class = META_COMPOSITOR_CLASS (meta_compositor_x11_parent_class); + parent_class->remove_window (compositor, window); +} + +Window +meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11) +{ + return compositor_x11->output; +} + +static void +meta_compositor_x11_dispose (GObject *object) +{ + MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (object); + + if (compositor_x11->have_x11_sync_object) + { + meta_sync_ring_destroy (); + compositor_x11->have_x11_sync_object = FALSE; + } + + G_OBJECT_CLASS (meta_compositor_x11_parent_class)->dispose (object); +} + +static void +meta_compositor_x11_init (MetaCompositorX11 *compositor_x11) +{ +} + +static void +meta_compositor_x11_class_init (MetaCompositorX11Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + + object_class->dispose = meta_compositor_x11_dispose; + + compositor_class->manage = meta_compositor_x11_manage; + compositor_class->unmanage = meta_compositor_x11_unmanage; + compositor_class->pre_paint = meta_compositor_x11_pre_paint; + compositor_class->post_paint = meta_compositor_x11_post_paint; + compositor_class->remove_window = meta_compositor_x11_remove_window; +} diff --git a/src/compositor/meta-compositor-x11.h b/src/compositor/meta-compositor-x11.h new file mode 100644 index 000000000..f577f73e0 --- /dev/null +++ b/src/compositor/meta-compositor-x11.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Red Hat Inc. + * + * 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_COMPOSITOR_X11_H +#define META_COMPOSITOR_X11_H + +#include "compositor/compositor-private.h" + +#define META_TYPE_COMPOSITOR_X11 (meta_compositor_x11_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCompositorX11, meta_compositor_x11, + META, COMPOSITOR_X11, MetaCompositor) + +void meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + XEvent *xevent, + MetaWindow *window); + +Window meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11); + +#endif /* META_COMPOSITOR_X11_H */ diff --git a/src/compositor/meta-dnd.c b/src/compositor/meta-dnd.c index 456a17dad..4139d9504 100644 --- a/src/compositor/meta-dnd.c +++ b/src/compositor/meta-dnd.c @@ -168,19 +168,20 @@ meta_dnd_notify_dnd_leave (MetaDnd *dnd) * http://www.freedesktop.org/wiki/Specifications/XDND */ gboolean -meta_dnd_handle_xdnd_event (MetaBackend *backend, - MetaCompositor *compositor, - Display *xdisplay, - XEvent *xev) +meta_dnd_handle_xdnd_event (MetaBackend *backend, + MetaCompositorX11 *compositor_x11, + Display *xdisplay, + XEvent *xev) { MetaDnd *dnd = meta_backend_get_dnd (backend); + MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); Window output_window; ClutterStage *stage; if (xev->xany.type != ClientMessage) return FALSE; - output_window = meta_compositor_get_output_xwindow (compositor); + output_window = meta_compositor_x11_get_output_xwindow (compositor_x11); stage = meta_compositor_get_stage (compositor); if (xev->xany.window != output_window && xev->xany.window != clutter_x11_get_stage_window (stage)) diff --git a/src/meson.build b/src/meson.build index e682aa4fd..c6c360169 100644 --- a/src/meson.build +++ b/src/meson.build @@ -271,6 +271,8 @@ mutter_sources = [ 'compositor/meta-background-group.c', 'compositor/meta-background-image.c', 'compositor/meta-background-private.h', + 'compositor/meta-compositor-x11.c', + 'compositor/meta-compositor-x11.h', 'compositor/meta-cullable.c', 'compositor/meta-cullable.h', 'compositor/meta-dnd-actor.c', @@ -454,6 +456,8 @@ if have_wayland mutter_sources += [ 'compositor/meta-surface-actor-wayland.c', 'compositor/meta-surface-actor-wayland.h', + 'compositor/meta-compositor-server.c', + 'compositor/meta-compositor-server.h', 'wayland/meta-cursor-sprite-wayland.c', 'wayland/meta-cursor-sprite-wayland.h', 'wayland/meta-pointer-confinement-wayland.c', diff --git a/src/meta/compositor.h b/src/meta/compositor.h index 0b4df93f7..1a028b90e 100644 --- a/src/meta/compositor.h +++ b/src/meta/compositor.h @@ -21,7 +21,6 @@ #define META_COMPOSITOR_H #include -#include #include #include @@ -87,11 +86,6 @@ META_EXPORT void meta_compositor_window_opacity_changed (MetaCompositor *compositor, MetaWindow *window); -META_EXPORT -gboolean meta_compositor_process_event (MetaCompositor *compositor, - XEvent *event, - MetaWindow *window); - META_EXPORT gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, MetaKeyBinding *binding); diff --git a/src/x11/events.c b/src/x11/events.c index cc4bde684..31a9b7151 100644 --- a/src/x11/events.c +++ b/src/x11/events.c @@ -31,6 +31,7 @@ #include "backends/meta-cursor-tracker-private.h" #include "backends/x11/meta-backend-x11.h" +#include "compositor/meta-compositor-x11.h" #include "core/bell.h" #include "core/display-private.h" #include "core/meta-workspace-manager-private.h" @@ -1862,14 +1863,18 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, } out: - if (!bypass_compositor) + if (!bypass_compositor && META_IS_COMPOSITOR_X11 (display->compositor)) { - MetaWindow *window = modified != None ? - meta_x11_display_lookup_x_window (x11_display, modified) : - NULL; + MetaCompositorX11 *compositor_x11 = + META_COMPOSITOR_X11 (display->compositor); + MetaWindow *window; - if (meta_compositor_process_event (display->compositor, event, window)) - bypass_gtk = TRUE; + if (modified != None) + window = meta_x11_display_lookup_x_window (x11_display, modified); + else + window = NULL; + + meta_compositor_x11_process_xevent (compositor_x11, event, window); } display->current_time = META_CURRENT_TIME;