diff --git a/0001-constraints-Enforce-X11-size-limits.patch b/0001-constraints-Enforce-X11-size-limits.patch new file mode 100644 index 0000000..a09a40b --- /dev/null +++ b/0001-constraints-Enforce-X11-size-limits.patch @@ -0,0 +1,85 @@ +From 1ab51efc968d7d3c6244d9b7efcdf4bae4fc0a9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 12 Mar 2014 02:04:13 +0100 +Subject: [PATCH] constraints: Enforce X11 size limits + +X11 limits windows to a maximum of 32767x32767, enforce that restriction +to keep insanely huge windows from crashing the WM. +--- + src/core/constraints.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/src/core/constraints.c b/src/core/constraints.c +index 4b1d95338a..eee16dc48f 100644 +--- a/src/core/constraints.c ++++ b/src/core/constraints.c +@@ -109,6 +109,7 @@ typedef enum + PRIORITY_TITLEBAR_VISIBLE = 4, + PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4, + PRIORITY_CUSTOM_RULE = 4, ++ PRIORITY_XLIMITS = 4, + PRIORITY_MAXIMUM = 4 /* Dummy value used for loop end = max(all priorities) */ + } ConstraintPriority; + +@@ -204,6 +205,10 @@ static gboolean constrain_partially_onscreen (MetaWindow *window, + ConstraintInfo *info, + ConstraintPriority priority, + gboolean check_only); ++static gboolean constrain_xlimits (MetaWindow *window, ++ ConstraintInfo *info, ++ ConstraintPriority priority, ++ gboolean check_only); + + static void setup_constraint_info (ConstraintInfo *info, + MetaWindow *window, +@@ -239,6 +244,7 @@ static const Constraint all_constraints[] = { + {constrain_fully_onscreen, "constrain_fully_onscreen"}, + {constrain_titlebar_visible, "constrain_titlebar_visible"}, + {constrain_partially_onscreen, "constrain_partially_onscreen"}, ++ {constrain_xlimits, "constrain_xlimits"}, + {NULL, NULL} + }; + +@@ -1876,3 +1882,39 @@ constrain_partially_onscreen (MetaWindow *window, + + return retval; + } ++ ++ ++#define MAX_WINDOW_SIZE 32767 ++ ++static gboolean ++constrain_xlimits (MetaWindow *window, ++ ConstraintInfo *info, ++ ConstraintPriority priority, ++ gboolean check_only) ++{ ++ int max_w, max_h; ++ gboolean constraint_already_satisfied; ++ ++ if (priority > PRIORITY_XLIMITS) ++ return TRUE; ++ ++ max_w = max_h = MAX_WINDOW_SIZE; ++ ++ if (window->frame) ++ { ++ MetaFrameBorders borders; ++ meta_frame_calc_borders (window->frame, &borders); ++ ++ max_w -= (borders.total.left + borders.total.right); ++ max_h -= (borders.total.top + borders.total.bottom); ++ } ++ ++ constraint_already_satisfied = info->current.width < max_w && info->current.height < max_h; ++ if (check_only || constraint_already_satisfied) ++ return constraint_already_satisfied; ++ ++ info->current.width = MIN (info->current.width, max_w); ++ info->current.height = MIN (info->current.height, max_h); ++ ++ return TRUE; ++} +-- +2.31.1 + diff --git a/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch b/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch new file mode 100644 index 0000000..2ff5f1b --- /dev/null +++ b/0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch @@ -0,0 +1,42 @@ +From 7ac5b7bad8f2d0e61700610f68282f6687cc9d2e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 21 Jul 2016 15:43:12 +0200 +Subject: [PATCH] events: Don't move (sloppy) focus while buttons are pressed + +(https://bugzilla.redhat.com/show_bug.cgi?id=1358535) +--- + src/x11/events.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/x11/events.c b/src/x11/events.c +index efa8f9856b..388eff0ac7 100644 +--- a/src/x11/events.c ++++ b/src/x11/events.c +@@ -839,6 +839,16 @@ crossing_serial_is_ignored (MetaX11Display *x11_display, + return FALSE; + } + ++static gboolean ++event_has_button_mask (XIEnterEvent *enter_event) ++{ ++ int i; ++ for (i = 0; i < enter_event->buttons.mask_len; i++) ++ if (enter_event->buttons.mask[i] != '\0') ++ return TRUE; ++ return FALSE; ++} ++ + static gboolean + handle_input_xevent (MetaX11Display *x11_display, + XIEvent *input_event, +@@ -883,6 +893,7 @@ handle_input_xevent (MetaX11Display *x11_display, + * avoid races. + */ + if (window && !crossing_serial_is_ignored (x11_display, serial) && ++ !event_has_button_mask (enter_event) && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + enter_event->detail != XINotifyInferior && +-- +2.31.1 + diff --git a/0001-main-be-more-aggressive-in-assuming-X11-backend.patch b/0001-main-be-more-aggressive-in-assuming-X11-backend.patch new file mode 100644 index 0000000..806ad38 --- /dev/null +++ b/0001-main-be-more-aggressive-in-assuming-X11-backend.patch @@ -0,0 +1,49 @@ +From 99c74360451a85fca9dacad531ed22adbc1b0805 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 13 Feb 2018 09:44:50 -0500 +Subject: [PATCH] main: be more aggressive in assuming X11 backend + +If the session is started by vncserver right now, the +XDG_SESSION_TYPE won't be X11. Ideally that would be +fixed, but for backward compatibility we should default +to X11 if the session type isn't set to wayland explicitly. +--- + src/core/main.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index a07dda9ecc..0d241f952b 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -407,7 +407,6 @@ find_session_type (void) + char *session_id; + char *session_type; + const char *session_type_env; +- gboolean is_tty = FALSE; + int ret, i; + + ret = sd_pid_get_session (0, &session_id); +@@ -420,8 +419,7 @@ find_session_type (void) + { + if (session_type_is_supported (session_type)) + goto out; +- else +- is_tty = g_strcmp0 (session_type, "tty") == 0; ++ + free (session_type); + } + } +@@ -453,8 +451,8 @@ find_session_type (void) + goto out; + } + +- /* Legacy support for starting through xinit */ +- if (is_tty && (g_getenv ("MUTTER_DISPLAY") || g_getenv ("DISPLAY"))) ++ /* Legacy support for starting through xinit or vncserver */ ++ if (g_getenv ("MUTTER_DISPLAY") || g_getenv ("DISPLAY")) + { + session_type = strdup ("x11"); + goto out; +-- +2.31.1 + diff --git a/0001-wayland-Allow-Xwayland-grabs-on-selected-apps.patch b/0001-wayland-Allow-Xwayland-grabs-on-selected-apps.patch new file mode 100644 index 0000000..14c9f10 --- /dev/null +++ b/0001-wayland-Allow-Xwayland-grabs-on-selected-apps.patch @@ -0,0 +1,35 @@ +From 6e2ef652cd58136aa668d0c1bd843fe83f11a0ab Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Fri, 26 Oct 2018 08:49:39 +0200 +Subject: [PATCH] wayland: Allow Xwayland grabs on selected apps + +Allow Xwayland grabs on a selected set of X11 applications. +--- + data/org.gnome.mutter.wayland.gschema.xml.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/data/org.gnome.mutter.wayland.gschema.xml.in b/data/org.gnome.mutter.wayland.gschema.xml.in +index 8a1878e105..5527a46bc6 100644 +--- a/data/org.gnome.mutter.wayland.gschema.xml.in ++++ b/data/org.gnome.mutter.wayland.gschema.xml.in +@@ -66,7 +66,7 @@ + gettext-domain="@GETTEXT_DOMAIN@"> + + +- false ++ true + Allow X11 grabs to lock keyboard focus with Xwayland + + Allow all keyboard events to be routed to X11 “override redirect” +@@ -86,7 +86,7 @@ + + + +- [] ++ ['@XWAYLAND_GRAB_DEFAULT_ACCESS_RULES@'] + Xwayland applications allowed to issue keyboard grabs + + List the resource names or resource class of X11 windows either +-- +2.31.1 + diff --git a/glx-stereo-support.patch b/glx-stereo-support.patch new file mode 100644 index 0000000..8083db4 --- /dev/null +++ b/glx-stereo-support.patch @@ -0,0 +1,1242 @@ +From 768818c8d071f066a2ab68f83381829838b5bf29 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 8 May 2014 18:44:15 -0400 +Subject: [PATCH 1/2] Add support for quad-buffer stereo + +Track the stereo status of windows using the new EXT_stereo_tree +GLX extension. + +When stereo is enabled or disabled, a restart is triggered via +meta_restart() after a timeout, setting a _META_ENABLE_STEREO +property on the root window to indicate whether we should +turn on a stereo stage for clutter. The property avoids a loop, +since we need to enable stereo *before* initializing Clutter and GL, +but we need GL to figure out whether we have stereo windows. + +Stereo windows are drawn to the stage using new functionality +in Cogl to setup a stereo context, select which buffer to draw +to, and draw either the left or right buffer of a stereo +texture_from_pixmap. +--- + clutter/clutter/clutter-paint-nodes.c | 103 +++++++++++ + clutter/clutter/clutter-paint-nodes.h | 13 ++ + src/compositor/compositor.c | 8 + + src/compositor/meta-compositor-x11.c | 127 +++++++++++++ + src/compositor/meta-compositor-x11.h | 6 + + src/compositor/meta-shaped-texture-private.h | 5 +- + src/compositor/meta-shaped-texture.c | 176 +++++++++++++++---- + src/compositor/meta-surface-actor-wayland.c | 2 +- + src/compositor/meta-surface-actor-x11.c | 55 +++++- + src/compositor/meta-surface-actor-x11.h | 5 + + src/compositor/meta-window-actor-private.h | 5 + + src/compositor/meta-window-actor.c | 22 +++ + src/core/main.c | 4 + + src/core/stereo.c | 154 ++++++++++++++++ + src/core/stereo.h | 28 +++ + src/meson.build | 2 + + src/wayland/meta-wayland-actor-surface.c | 4 +- + 17 files changed, 667 insertions(+), 52 deletions(-) + create mode 100644 src/core/stereo.c + create mode 100644 src/core/stereo.h + +diff --git a/clutter/clutter/clutter-paint-nodes.c b/clutter/clutter/clutter-paint-nodes.c +index f1f7fce318..29a673e9c7 100644 +--- a/clutter/clutter/clutter-paint-nodes.c ++++ b/clutter/clutter/clutter-paint-nodes.c +@@ -1970,3 +1970,106 @@ clutter_blur_node_new (unsigned int width, + out: + return (ClutterPaintNode *) blur_node; + } ++ ++/* ++ * ClutterStereoNode ++ */ ++ ++struct _ClutterStereoNode ++{ ++ ClutterPaintNode parent_instance; ++ ++ CoglStereoMode stereo_mode; ++}; ++ ++struct _ClutterStereoNodeClass ++{ ++ ClutterPaintNodeClass parent_class; ++}; ++ ++G_DEFINE_TYPE (ClutterStereoNode, clutter_stereo_node, CLUTTER_TYPE_PAINT_NODE) ++ ++static gboolean ++clutter_stereo_node_pre_draw (ClutterPaintNode *node, ++ ClutterPaintContext *paint_context) ++{ ++ ClutterStereoNode *stereo_node = CLUTTER_STEREO_NODE (node); ++ CoglFramebuffer *fb = ++ clutter_paint_context_get_framebuffer (paint_context); ++ ++ g_warn_if_fail (cogl_framebuffer_get_is_stereo (fb)); ++ ++ cogl_framebuffer_set_stereo_mode (fb, stereo_node->stereo_mode); ++ ++ return TRUE; ++} ++ ++static void ++clutter_stereo_node_post_draw (ClutterPaintNode *node, ++ ClutterPaintContext *paint_context) ++{ ++ CoglFramebuffer *fb = ++ clutter_paint_context_get_framebuffer (paint_context); ++ ++ cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH); ++} ++ ++static const char * ++stereo_mode_to_string (CoglStereoMode stereo_mode) ++{ ++ switch (stereo_mode) ++ { ++ case COGL_STEREO_BOTH: ++ return "both"; ++ case COGL_STEREO_LEFT: ++ return "left"; ++ case COGL_STEREO_RIGHT: ++ return "right"; ++ } ++ ++ g_assert_not_reached (); ++} ++ ++static JsonNode * ++clutter_stereo_node_serialize (ClutterPaintNode *node) ++{ ++ ClutterStereoNode *stereo_node = CLUTTER_STEREO_NODE (node); ++ g_autoptr (JsonBuilder) builder = NULL; ++ const char *stereo_mode_str; ++ ++ builder = json_builder_new (); ++ json_builder_begin_object (builder); ++ json_builder_set_member_name (builder, "stereo-mode"); ++ stereo_mode_str = stereo_mode_to_string (stereo_node->stereo_mode); ++ json_builder_add_string_value (builder, stereo_mode_str); ++ json_builder_end_object (builder); ++ ++ return json_builder_get_root (builder); ++} ++ ++static void ++clutter_stereo_node_class_init (ClutterStereoNodeClass *klass) ++{ ++ ClutterPaintNodeClass *node_class; ++ ++ node_class = CLUTTER_PAINT_NODE_CLASS (klass); ++ node_class->pre_draw = clutter_stereo_node_pre_draw; ++ node_class->post_draw = clutter_stereo_node_post_draw; ++ node_class->serialize = clutter_stereo_node_serialize; ++} ++ ++static void ++clutter_stereo_node_init (ClutterStereoNode *stereo_node) ++{ ++} ++ ++ClutterPaintNode * ++clutter_stereo_node_new (CoglStereoMode stereo_mode) ++{ ++ ClutterStereoNode *stereo_node; ++ ++ stereo_node = _clutter_paint_node_create (CLUTTER_TYPE_STEREO_NODE); ++ stereo_node->stereo_mode = stereo_mode; ++ ++ return CLUTTER_PAINT_NODE (stereo_node); ++} +diff --git a/clutter/clutter/clutter-paint-nodes.h b/clutter/clutter/clutter-paint-nodes.h +index 7f0d12857a..77d1ab05b6 100644 +--- a/clutter/clutter/clutter-paint-nodes.h ++++ b/clutter/clutter/clutter-paint-nodes.h +@@ -284,6 +284,19 @@ ClutterPaintNode * clutter_blur_node_new (unsigned int width, + unsigned int height, + float sigma); + ++#define CLUTTER_TYPE_STEREO_NODE (clutter_stereo_node_get_type ()) ++#define CLUTTER_STEREO_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STEREO_NODE, ClutterStereoNode)) ++#define CLUTTER_IS_STEREO_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STEREO_NODE)) ++ ++typedef struct _ClutterStereoNode ClutterStereoNode; ++typedef struct _ClutterStereoNodeClass ClutterStereoNodeClass; ++ ++CLUTTER_EXPORT ++GType clutter_stereo_node_get_type (void) G_GNUC_CONST; ++ ++CLUTTER_EXPORT ++ClutterPaintNode * clutter_stereo_node_new (CoglStereoMode stereo_mode); ++ + G_END_DECLS + + #endif /* __CLUTTER_PAINT_NODES_H__ */ +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index 1770550d4c..a4bd1252ae 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -66,6 +66,7 @@ + #include "compositor/meta-window-actor-private.h" + #include "compositor/meta-window-group-private.h" + #include "core/frame.h" ++#include "core/stereo.h" + #include "core/util-private.h" + #include "core/window-private.h" + #include "meta/compositor-mutter.h" +@@ -910,6 +911,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + meta_compositor_get_instance_private (compositor); + MetaWindowActor *top_window_actor; + GList *old_stack; ++ int stereo_window_count = 0; + + /* This is painful because hidden windows that we are in the process + * of animating out of existence. They'll be at the bottom of the +@@ -986,12 +988,18 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + */ + priv->windows = g_list_prepend (priv->windows, actor); + ++ if (meta_window_actor_is_stereo (actor)) ++ stereo_window_count++; ++ + stack = g_list_remove (stack, window); + old_stack = g_list_remove (old_stack, actor); + } + + sync_actor_stacking (compositor); + ++ if (!meta_is_wayland_compositor ()) ++ meta_stereo_set_have_stereo_windows (stereo_window_count > 0); ++ + top_window_actor = get_top_visible_window_actor (compositor); + + if (priv->top_window_actor == top_window_actor) +diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c +index 1d0ba4c8d8..afbe3f57e2 100644 +--- a/src/compositor/meta-compositor-x11.c ++++ b/src/compositor/meta-compositor-x11.c +@@ -31,6 +31,8 @@ + #include "compositor/meta-sync-ring.h" + #include "compositor/meta-window-actor-x11.h" + #include "core/display-private.h" ++#include "core/stack-tracker.h" ++#include "core/stereo.h" + #include "x11/meta-x11-display-private.h" + + struct _MetaCompositorX11 +@@ -50,8 +52,24 @@ struct _MetaCompositorX11 + gboolean xserver_uses_monotonic_clock; + int64_t xserver_time_query_time_us; + int64_t xserver_time_offset_us; ++ ++ int glx_opcode; ++ gboolean stereo_tree_ext; ++ gboolean have_stereo_windows; + }; + ++typedef struct ++{ ++ int type; ++ unsigned long serial; ++ Bool send_event; ++ Display *display; ++ int extension; ++ int evtype; ++ Drawable window; ++ Bool stereo_tree; ++} StereoNotifyEvent; ++ + G_DEFINE_TYPE (MetaCompositorX11, meta_compositor_x11, META_TYPE_COMPOSITOR) + + static void +@@ -95,6 +113,27 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + if (window) + process_damage (compositor_x11, (XDamageNotifyEvent *) xevent, window); + } ++ else if (xevent->type == GenericEvent && ++ xevent->xcookie.extension == compositor_x11->glx_opcode) ++ { ++ if (xevent->xcookie.evtype == GLX_STEREO_NOTIFY_EXT) ++ { ++ StereoNotifyEvent *stereo_event = ++ (StereoNotifyEvent *) (xevent->xcookie.data); ++ ++ window = meta_x11_display_lookup_x_window (x11_display, ++ stereo_event->window); ++ if (window) ++ { ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ MetaDisplay *display = meta_window_get_display (window); ++ ++ meta_window_actor_stereo_notify (window_actor, ++ stereo_event->stereo_tree); ++ meta_stack_tracker_queue_sync_stack (display->stack_tracker); ++ } ++ } ++ } + + if (compositor_x11->have_x11_sync_object) + meta_sync_ring_handle_event (xevent); +@@ -107,6 +146,85 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + meta_x11_handle_event (xevent); + } + ++#define GLX_STEREO_TREE_EXT 0x20F5 ++#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001 ++#define GLX_STEREO_NOTIFY_EXT 0x00000000 ++ ++static gboolean ++display_has_stereo_tree_ext (MetaX11Display *x11_display) ++{ ++ Display *xdisplay = x11_display->xdisplay; ++ const char *extensions_string; ++ ++ static const char * (*query_extensions_string) (Display *display, ++ int screen); ++ ++ if (query_extensions_string == NULL) ++ query_extensions_string = ++ (const char * (*) (Display *, int)) ++ cogl_get_proc_address ("glXQueryExtensionsString"); ++ ++ extensions_string = query_extensions_string (xdisplay, ++ meta_x11_display_get_screen_number (x11_display)); ++ ++ return extensions_string && strstr (extensions_string, "EXT_stereo_tree") != 0; ++} ++ ++#include ++ ++gboolean ++meta_compositor_x11_window_is_stereo (MetaCompositorX11 *compositor_x11, ++ Window xwindow) ++{ ++ MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); ++ MetaDisplay *display = meta_compositor_get_display (compositor); ++ Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); ++ ++ static int (*query_drawable) (Display *dpy, ++ Drawable draw, ++ int attribute, ++ unsigned int *value); ++ ++ if (compositor_x11->stereo_tree_ext) ++ { ++ unsigned int stereo_tree = 0; ++ ++ if (query_drawable == NULL) ++ query_drawable = ++ (int (*) (Display *, Drawable, int, unsigned int *)) ++ cogl_get_proc_address ("glXQueryDrawable"); ++ ++ query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree); ++ ++ return stereo_tree != 0; ++ } ++ else ++ return FALSE; ++} ++ ++void ++meta_compositor_x11_select_stereo_notify (MetaCompositorX11 *compositor_x11, ++ Window xwindow) ++{ ++ MetaCompositor *compositor = META_COMPOSITOR (compositor_x11); ++ MetaDisplay *display = meta_compositor_get_display (compositor); ++ Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); ++ ++ static void (*select_event) (Display *dpy, ++ Drawable draw, ++ unsigned long event_mask); ++ ++ if (compositor_x11->stereo_tree_ext) ++ { ++ if (select_event == NULL) ++ select_event = ++ (void (*) (Display *, Drawable, unsigned long)) ++ cogl_get_proc_address ("glXSelectEvent"); ++ ++ select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT); ++ } ++} ++ + static void + determine_server_clock_source (MetaCompositorX11 *compositor_x11) + { +@@ -142,6 +260,7 @@ meta_compositor_x11_manage (MetaCompositor *compositor, + MetaX11Display *x11_display = display->x11_display; + Display *xdisplay = meta_x11_display_get_xdisplay (x11_display); + int composite_version; ++ int glx_major_opcode, glx_first_event, glx_first_error; + MetaBackend *backend = meta_get_backend (); + Window xwindow; + +@@ -166,10 +285,18 @@ meta_compositor_x11_manage (MetaCompositor *compositor, + return FALSE; + } + ++ if (XQueryExtension (xdisplay, ++ "GLX", ++ &glx_major_opcode, &glx_first_event, &glx_first_error)) ++ compositor_x11->glx_opcode = glx_major_opcode; ++ + determine_server_clock_source (compositor_x11); + + meta_x11_display_set_cm_selection (display->x11_display); + ++ compositor_x11->stereo_tree_ext = ++ display_has_stereo_tree_ext (display->x11_display); ++ + compositor_x11->output = display->x11_display->composite_overlay_window; + + xwindow = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend)); +diff --git a/src/compositor/meta-compositor-x11.h b/src/compositor/meta-compositor-x11.h +index 42554feb39..61f3cd5950 100644 +--- a/src/compositor/meta-compositor-x11.h ++++ b/src/compositor/meta-compositor-x11.h +@@ -36,4 +36,10 @@ void meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + + Window meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11); + ++gboolean meta_compositor_x11_window_is_stereo (MetaCompositorX11 *compositor_x11, ++ Window xwindow); ++ ++void meta_compositor_x11_select_stereo_notify (MetaCompositorX11 *compositor_x11, ++ Window xwindow); ++ + #endif /* META_COMPOSITOR_X11_H */ +diff --git a/src/compositor/meta-shaped-texture-private.h b/src/compositor/meta-shaped-texture-private.h +index 2fe1b8ea48..fadad07d69 100644 +--- a/src/compositor/meta-shaped-texture-private.h ++++ b/src/compositor/meta-shaped-texture-private.h +@@ -31,8 +31,9 @@ + #include "meta/meta-shaped-texture.h" + + MetaShapedTexture *meta_shaped_texture_new (void); +-void meta_shaped_texture_set_texture (MetaShapedTexture *stex, +- CoglTexture *texture); ++void meta_shaped_texture_set_textures (MetaShapedTexture *stex, ++ CoglTexture *texture, ++ CoglTexture *texture_right); + void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex, + gboolean is_y_inverted); + void meta_shaped_texture_set_snippet (MetaShapedTexture *stex, +diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c +index 6a8af828f0..43170a195d 100644 +--- a/src/compositor/meta-shaped-texture.c ++++ b/src/compositor/meta-shaped-texture.c +@@ -83,8 +83,10 @@ struct _MetaShapedTexture + GObject parent; + + MetaTextureTower *paint_tower; ++ MetaTextureTower *paint_tower_right; + + CoglTexture *texture; ++ CoglTexture *texture_right; + CoglTexture *mask_texture; + CoglSnippet *snippet; + +@@ -151,6 +153,7 @@ static void + meta_shaped_texture_init (MetaShapedTexture *stex) + { + stex->paint_tower = meta_texture_tower_new (); ++ stex->paint_tower_right = NULL; + + stex->buffer_scale = 1; + stex->texture = NULL; +@@ -251,11 +254,11 @@ meta_shaped_texture_dispose (GObject *object) + + g_clear_handle_id (&stex->remipmap_timeout_id, g_source_remove); + +- if (stex->paint_tower) +- meta_texture_tower_free (stex->paint_tower); +- stex->paint_tower = NULL; ++ g_clear_pointer (&stex->paint_tower, meta_texture_tower_free); ++ g_clear_pointer (&stex->paint_tower_right, meta_texture_tower_free); + + g_clear_pointer (&stex->texture, cogl_object_unref); ++ g_clear_pointer (&stex->texture_right, cogl_object_unref); + + meta_shaped_texture_set_mask_texture (stex, NULL); + meta_shaped_texture_reset_pipelines (stex); +@@ -521,14 +524,19 @@ paint_clipped_rectangle_node (MetaShapedTexture *stex, + } + + static void +-set_cogl_texture (MetaShapedTexture *stex, +- CoglTexture *cogl_tex) ++set_cogl_textures (MetaShapedTexture *stex, ++ CoglTexture *cogl_tex, ++ CoglTexture *cogl_tex_right) + { + int width, height; + + cogl_clear_object (&stex->texture); ++ cogl_clear_object (&stex->texture_right); + +- if (cogl_tex != NULL) ++ stex->texture = cogl_tex; ++ stex->texture_right = cogl_tex_right; ++ ++ if (cogl_tex) + { + stex->texture = cogl_object_ref (cogl_tex); + width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); +@@ -540,6 +548,9 @@ set_cogl_texture (MetaShapedTexture *stex, + height = 0; + } + ++ if (cogl_tex_right) ++ cogl_object_ref (cogl_tex_right); ++ + if (stex->tex_width != width || + stex->tex_height != height) + { +@@ -553,8 +564,23 @@ set_cogl_texture (MetaShapedTexture *stex, + * previous buffer. We only queue a redraw in response to surface + * damage. */ + ++ if (cogl_tex_right) ++ { ++ if (!stex->paint_tower_right) ++ stex->paint_tower_right = meta_texture_tower_new (); ++ } ++ else ++ { ++ g_clear_pointer (&stex->paint_tower_right, meta_texture_tower_free); ++ } ++ + if (stex->create_mipmaps) +- meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex); ++ { ++ meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex); ++ ++ if (stex->paint_tower_right) ++ meta_texture_tower_set_base_texture (stex->paint_tower_right, cogl_tex_right); ++ } + } + + static gboolean +@@ -582,6 +608,19 @@ flip_ints (int *x, + *y = tmp; + } + ++static CoglFramebuffer * ++get_target_framebuffer (ClutterPaintNode *root_node, ++ ClutterPaintContext *paint_context) ++{ ++ CoglFramebuffer *framebuffer; ++ ++ framebuffer = clutter_paint_node_get_framebuffer (root_node); ++ if (!framebuffer) ++ framebuffer = clutter_paint_context_get_framebuffer (paint_context); ++ ++ return framebuffer; ++} ++ + static void + do_paint_content (MetaShapedTexture *stex, + ClutterPaintNode *root_node, +@@ -622,9 +661,7 @@ do_paint_content (MetaShapedTexture *stex, + * improves performance, especially with software rendering. + */ + +- framebuffer = clutter_paint_node_get_framebuffer (root_node); +- if (!framebuffer) +- framebuffer = clutter_paint_context_get_framebuffer (paint_context); ++ framebuffer = get_target_framebuffer (root_node, paint_context); + + if (stex->has_viewport_src_rect) + { +@@ -826,13 +863,27 @@ do_paint_content (MetaShapedTexture *stex, + + static CoglTexture * + select_texture_for_paint (MetaShapedTexture *stex, +- ClutterPaintContext *paint_context) ++ ClutterPaintContext *paint_context, ++ CoglStereoMode stereo_mode) + { + CoglTexture *texture = NULL; + int64_t now; ++ gboolean use_right_texture = FALSE; + +- if (!stex->texture) +- return NULL; ++ switch (stereo_mode) ++ { ++ case COGL_STEREO_LEFT: ++ case COGL_STEREO_BOTH: ++ if (!stex->texture) ++ return NULL; ++ use_right_texture = FALSE; ++ break; ++ case COGL_STEREO_RIGHT: ++ if (!stex->texture_right) ++ return NULL; ++ use_right_texture = TRUE; ++ break; ++ } + + now = g_get_monotonic_time (); + +@@ -843,14 +894,24 @@ select_texture_for_paint (MetaShapedTexture *stex, + if (age >= MIN_MIPMAP_AGE_USEC || + stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP) + { +- texture = meta_texture_tower_get_paint_texture (stex->paint_tower, ++ MetaTextureTower *paint_tower; ++ ++ if (use_right_texture) ++ paint_tower = stex->paint_tower_right; ++ else ++ paint_tower = stex->paint_tower; ++ ++ texture = meta_texture_tower_get_paint_texture (paint_tower, + paint_context); + } + } + + if (!texture) + { +- texture = stex->texture; ++ if (use_right_texture) ++ texture = stex->texture_right; ++ else ++ texture = stex->texture; + + if (stex->create_mipmaps) + { +@@ -876,35 +937,57 @@ meta_shaped_texture_paint_content (ClutterContent *content, + { + MetaShapedTexture *stex = META_SHAPED_TEXTURE (content); + ClutterActorBox alloc; +- CoglTexture *paint_tex = NULL; + uint8_t opacity; ++ CoglFramebuffer *framebuffer; ++ gboolean is_stereo; + + if (stex->clip_region && cairo_region_is_empty (stex->clip_region)) + return; + +- /* The GL EXT_texture_from_pixmap extension does allow for it to be +- * used together with SGIS_generate_mipmap, however this is very +- * rarely supported. Also, even when it is supported there +- * are distinct performance implications from: +- * +- * - Updating mipmaps that we don't need +- * - Having to reallocate pixmaps on the server into larger buffers +- * +- * So, we just unconditionally use our mipmap emulation code. If we +- * wanted to use SGIS_generate_mipmap, we'd have to query COGL to +- * see if it was supported (no API currently), and then if and only +- * if that was the case, set the clutter texture quality to HIGH. +- * Setting the texture quality to high without SGIS_generate_mipmap +- * support for TFP textures will result in fallbacks to XGetImage. +- */ +- paint_tex = select_texture_for_paint (stex, paint_context); +- if (!paint_tex) ++ if (!stex->texture) + return; + + opacity = clutter_actor_get_paint_opacity (actor); + clutter_actor_get_content_box (actor, &alloc); + +- do_paint_content (stex, root_node, paint_context, paint_tex, &alloc, opacity); ++ framebuffer = get_target_framebuffer (root_node, paint_context); ++ is_stereo = (stex->texture_right && ++ cogl_framebuffer_get_is_stereo (framebuffer)); ++ ++ if (is_stereo) ++ { ++ CoglTexture *texture_left; ++ CoglTexture *texture_right; ++ g_autoptr (ClutterPaintNode) left_node = NULL; ++ g_autoptr (ClutterPaintNode) right_node = NULL; ++ ++ texture_left = select_texture_for_paint (stex, paint_context, ++ COGL_STEREO_LEFT); ++ texture_right = select_texture_for_paint (stex, paint_context, ++ COGL_STEREO_RIGHT); ++ ++ left_node = clutter_stereo_node_new (COGL_STEREO_LEFT); ++ clutter_paint_node_set_static_name (left_node, "MetaShapedTexture (left)"); ++ right_node = clutter_stereo_node_new (COGL_STEREO_RIGHT); ++ clutter_paint_node_set_static_name (right_node, "MetaShapedTexture (right)"); ++ ++ clutter_paint_node_add_child (root_node, left_node); ++ clutter_paint_node_add_child (root_node, right_node); ++ ++ do_paint_content (stex, left_node, paint_context, ++ texture_left, &alloc, opacity); ++ do_paint_content (stex, right_node, paint_context, ++ texture_right, &alloc, opacity); ++ } ++ else ++ { ++ CoglTexture *texture; ++ ++ texture = select_texture_for_paint (stex, paint_context, ++ COGL_STEREO_BOTH); ++ do_paint_content (stex, root_node, paint_context, ++ texture, &alloc, opacity); ++ } + } + + static gboolean +@@ -946,6 +1029,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, + stex->create_mipmaps = create_mipmaps; + base_texture = create_mipmaps ? stex->texture : NULL; + meta_texture_tower_set_base_texture (stex->paint_tower, base_texture); ++ ++ if (stex->paint_tower_right) ++ { ++ base_texture = create_mipmaps ? stex->texture_right : NULL; ++ meta_texture_tower_set_base_texture (stex->paint_tower_right, base_texture); ++ } + } + } + +@@ -1079,6 +1168,14 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, + y, + width, + height); ++ if (stex->paint_tower_right) ++ { ++ meta_texture_tower_update_area (stex->paint_tower_right, ++ x, ++ y, ++ width, ++ height); ++ } + + stex->prev_invalidation = stex->last_invalidation; + stex->last_invalidation = g_get_monotonic_time (); +@@ -1098,20 +1195,21 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, + } + + /** +- * meta_shaped_texture_set_texture: ++ * meta_shaped_texture_set_textures: + * @stex: The #MetaShapedTexture + * @pixmap: The #CoglTexture to display + */ + void +-meta_shaped_texture_set_texture (MetaShapedTexture *stex, +- CoglTexture *texture) ++meta_shaped_texture_set_textures (MetaShapedTexture *stex, ++ CoglTexture *texture, ++ CoglTexture *texture_right) + { + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); + +- if (stex->texture == texture) ++ if (stex->texture == texture && stex->texture_right == texture_right) + return; + +- set_cogl_texture (stex, texture); ++ set_cogl_textures (stex, texture, texture_right); + } + + /** +diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c +index a182ad8513..1ddc83db2b 100644 +--- a/src/compositor/meta-surface-actor-wayland.c ++++ b/src/compositor/meta-surface-actor-wayland.c +@@ -148,7 +148,7 @@ meta_surface_actor_wayland_dispose (GObject *object) + + stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + if (stex) +- meta_shaped_texture_set_texture (stex, NULL); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); + + if (self->surface) + { +diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c +index 41ae2dffbc..c7c3d08c36 100644 +--- a/src/compositor/meta-surface-actor-x11.c ++++ b/src/compositor/meta-surface-actor-x11.c +@@ -30,6 +30,7 @@ + #include + + #include "cogl/winsys/cogl-texture-pixmap-x11.h" ++#include "compositor/meta-compositor-x11.h" + #include "compositor/meta-cullable.h" + #include "compositor/meta-shaped-texture-private.h" + #include "compositor/meta-window-actor-private.h" +@@ -47,6 +48,7 @@ struct _MetaSurfaceActorX11 + MetaDisplay *display; + + CoglTexture *texture; ++ CoglTexture *texture_right; + Pixmap pixmap; + Damage damage; + +@@ -62,6 +64,8 @@ struct _MetaSurfaceActorX11 + guint size_changed : 1; + + guint unredirected : 1; ++ ++ guint stereo : 1; + }; + + G_DEFINE_TYPE (MetaSurfaceActorX11, +@@ -101,7 +105,7 @@ detach_pixmap (MetaSurfaceActorX11 *self) + * you are supposed to be able to free a GLXPixmap after freeing the underlying + * pixmap, but it certainly doesn't work with current DRI/Mesa + */ +- meta_shaped_texture_set_texture (stex, NULL); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); + cogl_flush (); + + meta_x11_error_trap_push (display->x11_display); +@@ -110,6 +114,7 @@ detach_pixmap (MetaSurfaceActorX11 *self) + meta_x11_error_trap_pop (display->x11_display); + + g_clear_pointer (&self->texture, cogl_object_unref); ++ g_clear_pointer (&self->texture_right, cogl_object_unref); + } + + static void +@@ -119,23 +124,37 @@ set_pixmap (MetaSurfaceActorX11 *self, + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + GError *error = NULL; +- CoglTexture *texture; ++ CoglTexturePixmapX11 *texture; ++ CoglTexturePixmapX11 *texture_right; + + g_assert (self->pixmap == None); + self->pixmap = pixmap; + +- texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, self->pixmap, FALSE, &error)); ++ if (self->stereo) ++ texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error); ++ else ++ texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error); ++ ++ if (self->stereo) ++ texture_right = cogl_texture_pixmap_x11_new_right (texture); ++ else ++ texture_right = NULL; + + if (error != NULL) + { + g_warning ("Failed to allocate stex texture: %s", error->message); + g_error_free (error); + } +- else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) ++ else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture))) + g_warning ("NOTE: Not using GLX TFP!"); + +- self->texture = texture; +- meta_shaped_texture_set_texture (stex, texture); ++ self->texture = COGL_TEXTURE (texture); ++ if (self->stereo) ++ self->texture_right = COGL_TEXTURE (texture_right); ++ ++ meta_shaped_texture_set_textures (stex, ++ COGL_TEXTURE (texture), ++ COGL_TEXTURE (texture_right));; + } + + static void +@@ -372,8 +391,8 @@ reset_texture (MetaSurfaceActorX11 *self) + /* Setting the texture to NULL will cause all the FBO's cached by the + * shaped texture's MetaTextureTower to be discarded and recreated. + */ +- meta_shaped_texture_set_texture (stex, NULL); +- meta_shaped_texture_set_texture (stex, self->texture); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); ++ meta_shaped_texture_set_textures (stex, self->texture, self->texture_right); + } + + MetaSurfaceActor * +@@ -381,12 +400,18 @@ meta_surface_actor_x11_new (MetaWindow *window) + { + MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL); + MetaDisplay *display = meta_window_get_display (window); ++ MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (display->compositor); ++ Window xwindow; + + g_assert (!meta_is_wayland_compositor ()); + + self->window = window; + self->display = display; + ++ xwindow = meta_window_x11_get_toplevel_xwindow (window); ++ self->stereo = meta_compositor_x11_window_is_stereo (compositor_x11, xwindow); ++ meta_compositor_x11_select_stereo_notify (compositor_x11, xwindow); ++ + g_signal_connect_object (self->display, "gl-video-memory-purged", + G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED); + +@@ -420,3 +445,17 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + self->last_height = height; + meta_shaped_texture_set_fallback_size (stex, width, height); + } ++ ++void ++meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self, ++ gboolean stereo_tree) ++{ ++ self->stereo = stereo_tree != FALSE; ++ detach_pixmap (self); ++} ++ ++gboolean ++meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self) ++{ ++ return self->stereo; ++} +diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h +index 0a8517236a..369f631ae0 100644 +--- a/src/compositor/meta-surface-actor-x11.h ++++ b/src/compositor/meta-surface-actor-x11.h +@@ -57,6 +57,11 @@ gboolean meta_surface_actor_x11_is_visible (MetaSurfaceActorX11 *self); + + void meta_surface_actor_x11_handle_updates (MetaSurfaceActorX11 *self); + ++void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self, ++ gboolean stereo_tree); ++ ++gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self); ++ + G_END_DECLS + + #endif /* __META_SURFACE_ACTOR_X11_H__ */ +diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h +index 64741e4167..d498879902 100644 +--- a/src/compositor/meta-window-actor-private.h ++++ b/src/compositor/meta-window-actor-private.h +@@ -99,4 +99,9 @@ void meta_window_actor_update_regions (MetaWindowActor *self); + + gboolean meta_window_actor_can_freeze_commits (MetaWindowActor *self); + ++void meta_window_actor_stereo_notify (MetaWindowActor *actor, ++ gboolean stereo_tree); ++ ++gboolean meta_window_actor_is_stereo (MetaWindowActor *actor); ++ + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index d4fc9a43a0..56c85e1788 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -1557,3 +1557,25 @@ out: + clutter_actor_uninhibit_culling (actor); + return surface; + } ++ ++void ++meta_window_actor_stereo_notify (MetaWindowActor *self, ++ gboolean stereo_tree) ++{ ++ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); ++ ++ if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) ++ meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface), ++ stereo_tree); ++} ++ ++gboolean ++meta_window_actor_is_stereo (MetaWindowActor *self) ++{ ++ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); ++ ++ if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) ++ return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface)); ++ else ++ return FALSE; ++} +diff --git a/src/core/main.c b/src/core/main.c +index 6dabcfe73e..a07dda9ecc 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -88,6 +88,7 @@ + #include "meta/meta-backend.h" + #include "meta/meta-x11-errors.h" + #include "meta/prefs.h" ++#include "stereo.h" + #include "ui/ui.h" + #include "x11/session.h" + +@@ -848,6 +849,9 @@ meta_init (void) + if (!meta_is_wayland_compositor ()) + meta_select_display (opt_display_name); + ++ if (!meta_is_wayland_compositor ()) ++ meta_stereo_init (); ++ + meta_init_backend (backend_gtype, n_properties, prop_names, prop_values); + + for (i = 0; i < n_properties; i++) +diff --git a/src/core/stereo.c b/src/core/stereo.c +new file mode 100644 +index 0000000000..817056527f +--- /dev/null ++++ b/src/core/stereo.c +@@ -0,0 +1,154 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++ ++/* ++ * Copyright (C) 2014 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, see . ++ */ ++ ++/* ++ * SECTION:stereo ++ * @short_description: Keep track of whether we are a stereo compositor ++ * ++ * With GLX, we need to use a different GL context for stereo and ++ * non-stereo support. Support for multiple GL contexts is unfinished ++ * in Cogl and entirely lacking in Clutter, so it's by far easier ++ * to just restart Mutter when we detect a stereo window. ++ * ++ * A property _MUTTER_ENABLE_STEREO is maintained on the root window ++ * to know whether we should initialize clutter for stereo or not. ++ * When the presence or absence of stereo windows mismatches the ++ * stereo-enabled state for a sufficiently long period of time, ++ * we restart Mutter. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "display-private.h" ++#include ++#include ++#include ++#include "stereo.h" ++#include "ui/ui.h" ++#include "util-private.h" ++ ++static guint stereo_switch_id = 0; ++static gboolean stereo_enabled = FALSE; ++/* -1 so the first time meta_stereo_set_have_stereo_windows() is called ++ * we avoid the short-circuit and set up a timeout to restart ++ * if necessary */ ++static gboolean stereo_have_windows = (gboolean)-1; ++static gboolean stereo_restart = FALSE; ++ ++#define STEREO_ENABLE_WAIT 1000 ++#define STEREO_DISABLE_WAIT 5000 ++ ++void ++meta_stereo_init (void) ++{ ++ Display *xdisplay; ++ Window root; ++ Atom atom_enable_stereo; ++ Atom type; ++ int format; ++ unsigned long n_items, bytes_after; ++ guchar *data; ++ ++ xdisplay = XOpenDisplay (NULL); ++ if (xdisplay == NULL) ++ meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL)); ++ ++ root = DefaultRootWindow (xdisplay); ++ atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False); ++ ++ XGetWindowProperty (xdisplay, root, atom_enable_stereo, ++ 0, 1, False, XA_INTEGER, ++ &type, &format, &n_items, &bytes_after, &data); ++ if (type == XA_INTEGER) ++ { ++ if (format == 32 && n_items == 1 && bytes_after == 0) ++ { ++ stereo_enabled = *(long *)data; ++ } ++ else ++ { ++ meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n"); ++ } ++ ++ XFree (data); ++ } ++ else if (type != None) ++ { ++ meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n"); ++ } ++ ++ meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s", ++ stereo_enabled ? "yes" : "no"); ++ clutter_x11_set_use_stereo_stage (stereo_enabled); ++ XCloseDisplay (xdisplay); ++} ++ ++static gboolean ++meta_stereo_switch (gpointer data) ++{ ++ stereo_switch_id = 0; ++ stereo_restart = TRUE; ++ ++ meta_restart (stereo_have_windows ? ++ _("Enabling stereo...") : ++ _("Disabling stereo...")); ++ ++ return FALSE; ++} ++ ++void ++meta_stereo_set_have_stereo_windows (gboolean have_windows) ++{ ++ have_windows = have_windows != FALSE; ++ ++ if (!stereo_restart && have_windows != stereo_have_windows) ++ { ++ MetaDisplay *display = meta_get_display (); ++ Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); ++ Window root = DefaultRootWindow (xdisplay); ++ Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False); ++ long value; ++ ++ stereo_have_windows = have_windows; ++ ++ if (stereo_have_windows) ++ meta_verbose ("Detected stereo windows\n"); ++ else ++ meta_verbose ("No stereo windows detected\n"); ++ ++ value = stereo_have_windows; ++ XChangeProperty (xdisplay, root, ++ atom_enable_stereo, XA_INTEGER, 32, ++ PropModeReplace, (guchar *)&value, 1); ++ ++ if (stereo_switch_id != 0) ++ { ++ g_source_remove (stereo_switch_id); ++ stereo_switch_id = 0; ++ } ++ ++ if (stereo_have_windows != stereo_enabled) ++ stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT, ++ meta_stereo_switch, NULL); ++ } ++} +diff --git a/src/core/stereo.h b/src/core/stereo.h +new file mode 100644 +index 0000000000..ccd1d702a1 +--- /dev/null ++++ b/src/core/stereo.h +@@ -0,0 +1,28 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++ ++/* ++ * Copyright (C) 2014 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, see . ++ */ ++ ++#ifndef META_STEREO_H ++#define META_STEREO_H ++ ++void meta_stereo_init (void); ++void meta_stereo_set_have_stereo_windows (gboolean have_windows); ++gboolean meta_stereo_is_restart (void); ++void meta_stereo_finish_restart (void); ++ ++#endif +diff --git a/src/meson.build b/src/meson.build +index 284bdf5220..c56438fbbe 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -394,6 +394,8 @@ mutter_sources = [ + 'core/stack.h', + 'core/stack-tracker.c', + 'core/stack-tracker.h', ++ 'core/stereo.c', ++ 'core/stereo.h', + 'core/startup-notification.c', + 'core/startup-notification-private.h', + 'core/util.c', +diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c +index 797795f861..d8d1f3ce16 100644 +--- a/src/wayland/meta-wayland-actor-surface.c ++++ b/src/wayland/meta-wayland-actor-surface.c +@@ -193,7 +193,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor + snippet = meta_wayland_buffer_create_snippet (buffer); + is_y_inverted = meta_wayland_buffer_is_y_inverted (buffer); + +- meta_shaped_texture_set_texture (stex, surface->texture); ++ meta_shaped_texture_set_textures (stex, surface->texture, NULL); + meta_shaped_texture_set_snippet (stex, snippet); + meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted); + meta_shaped_texture_set_buffer_scale (stex, surface->scale); +@@ -201,7 +201,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor + } + else + { +- meta_shaped_texture_set_texture (stex, NULL); ++ meta_shaped_texture_set_textures (stex, NULL, NULL); + } + + surface_rect = (cairo_rectangle_int_t) { +-- +2.31.1 + + +From 36517cd245584c5bcd3b730efaf6c3d2e7c9472d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 2 Jun 2021 16:55:45 +0200 +Subject: [PATCH 2/2] compositor: Only check for stereo when using GLX + +If EGL Xlib is used, we'll get bogus return value and crash. +--- + src/compositor/meta-compositor-x11.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c +index afbe3f57e2..4345f38b6f 100644 +--- a/src/compositor/meta-compositor-x11.c ++++ b/src/compositor/meta-compositor-x11.c +@@ -153,9 +153,17 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11, + static gboolean + display_has_stereo_tree_ext (MetaX11Display *x11_display) + { ++ MetaBackend *backend = meta_get_backend (); ++ ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); ++ CoglContext *cogl_context = ++ clutter_backend_get_cogl_context (clutter_backend); ++ CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context); + Display *xdisplay = x11_display->xdisplay; + const char *extensions_string; + ++ if (cogl_renderer_get_winsys_id (cogl_renderer) != COGL_WINSYS_ID_GLX) ++ return FALSE; ++ + static const char * (*query_extensions_string) (Display *display, + int screen); + +-- +2.31.1 + diff --git a/legacy-x11-input-configuration.patch b/legacy-x11-input-configuration.patch new file mode 100644 index 0000000..597e0d7 --- /dev/null +++ b/legacy-x11-input-configuration.patch @@ -0,0 +1,819 @@ +From 705818340dec181335b48ab73d6411e639daaeae Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Tue, 1 Jun 2021 11:44:20 +0200 +Subject: [PATCH 1/6] backends/x11: Support synaptics configuration + +The code is taken mostly as-is from g-s-d, so we can drag the +dead horse a bit longer. +--- + src/backends/x11/meta-input-settings-x11.c | 275 +++++++++++++++++++++ + 1 file changed, 275 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 96390285a6..0631fd2fee 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -26,6 +26,7 @@ + #include "backends/x11/meta-input-settings-x11.h" + + #include ++#include + #include + #include + #include +@@ -165,6 +166,184 @@ change_property (ClutterInputDevice *device, + meta_XFree (data_ret); + } + ++static gboolean ++is_device_synaptics (ClutterInputDevice *device) ++{ ++ guchar *has_setting; ++ ++ /* We just need looking for a synaptics-specific property */ ++ has_setting = get_property (device, "Synaptics Off", XA_INTEGER, 8, 1); ++ if (!has_setting) ++ return FALSE; ++ ++ meta_XFree (has_setting); ++ return TRUE; ++} ++ ++static void ++change_synaptics_tap_left_handed (ClutterInputDevice *device, ++ gboolean tap_enabled, ++ gboolean left_handed) ++{ ++ MetaDisplay *display = meta_get_display (); ++ MetaX11Display *x11_display = display ? display->x11_display : NULL; ++ MetaBackend *backend = meta_get_backend (); ++ Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); ++ int device_id; ++ XDevice *xdevice; ++ guchar *tap_action, *buttons; ++ guint buttons_capacity = 16, n_buttons; ++ ++ device_id = meta_input_device_x11_get_device_id (device); ++ xdevice = XOpenDevice (xdisplay, device_id); ++ if (!xdevice) ++ return; ++ ++ tap_action = get_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, 7); ++ if (!tap_action) ++ goto out; ++ ++ tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; ++ tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; ++ tap_action[6] = tap_enabled ? 2 : 0; ++ ++ change_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, tap_action, 7); ++ meta_XFree (tap_action); ++ ++ if (x11_display) ++ meta_x11_error_trap_push (x11_display); ++ buttons = g_new (guchar, buttons_capacity); ++ n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice, ++ buttons, buttons_capacity); ++ ++ while (n_buttons > buttons_capacity) ++ { ++ buttons_capacity = n_buttons; ++ buttons = (guchar *) g_realloc (buttons, ++ buttons_capacity * sizeof (guchar)); ++ ++ n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice, ++ buttons, buttons_capacity); ++ } ++ ++ buttons[0] = left_handed ? 3 : 1; ++ buttons[2] = left_handed ? 1 : 3; ++ XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons); ++ g_free (buttons); ++ ++ if (x11_display && meta_x11_error_trap_pop_with_return (x11_display)) ++ { ++ g_warning ("Could not set synaptics touchpad left-handed for %s", ++ clutter_input_device_get_device_name (device)); ++ } ++ ++ out: ++ XCloseDevice (xdisplay, xdevice); ++} ++ ++static void ++change_synaptics_speed (ClutterInputDevice *device, ++ gdouble speed) ++{ ++ MetaDisplay *display = meta_get_display (); ++ MetaX11Display *x11_display = display ? display->x11_display : NULL; ++ MetaBackend *backend = meta_get_backend (); ++ Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); ++ int device_id; ++ XDevice *xdevice; ++ XPtrFeedbackControl feedback; ++ XFeedbackState *states, *state; ++ int i, num_feedbacks, motion_threshold, numerator, denominator; ++ gfloat motion_acceleration; ++ ++ device_id = meta_input_device_x11_get_device_id (device); ++ xdevice = XOpenDevice (xdisplay, device_id); ++ if (!xdevice) ++ return; ++ /* Get the list of feedbacks for the device */ ++ states = XGetFeedbackControl (xdisplay, xdevice, &num_feedbacks); ++ if (!states) ++ return; ++ ++ /* Calculate acceleration and threshold */ ++ motion_acceleration = (speed + 1) * 5; /* speed is [-1..1], map to [0..10] */ ++ motion_threshold = CLAMP (10 - floor (motion_acceleration), 1, 10); ++ ++ if (motion_acceleration >= 1.0) ++ { ++ /* we want to get the acceleration, with a resolution of 0.5 ++ */ ++ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) ++ { ++ numerator = floor (motion_acceleration); ++ denominator = 1; ++ } ++ else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) ++ { ++ numerator = ceil (2.0 * motion_acceleration); ++ denominator = 2; ++ } ++ else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) ++ { ++ numerator = floor (2.0 *motion_acceleration); ++ denominator = 2; ++ } ++ else ++ { ++ numerator = ceil (motion_acceleration); ++ denominator = 1; ++ } ++ } ++ else if (motion_acceleration < 1.0 && motion_acceleration > 0) ++ { ++ /* This we do to 1/10ths */ ++ numerator = floor (motion_acceleration * 10) + 1; ++ denominator= 10; ++ } ++ else ++ { ++ numerator = -1; ++ denominator = -1; ++ } ++ ++ if (x11_display) ++ meta_x11_error_trap_push (x11_display); ++ ++ state = (XFeedbackState *) states; ++ ++ for (i = 0; i < num_feedbacks; i++) ++ { ++ if (state->class == PtrFeedbackClass) ++ { ++ /* And tell the device */ ++ feedback.class = PtrFeedbackClass; ++ feedback.length = sizeof (XPtrFeedbackControl); ++ feedback.id = state->id; ++ feedback.threshold = motion_threshold; ++ feedback.accelNum = numerator; ++ feedback.accelDenom = denominator; ++ ++ XChangeFeedbackControl (xdisplay, xdevice, ++ DvAccelNum | DvAccelDenom | DvThreshold, ++ (XFeedbackControl *) &feedback); ++ break; ++ } ++ ++ state = (XFeedbackState *) ((char *) state + state->length); ++ } ++ ++ if (x11_display && meta_x11_error_trap_pop_with_return (x11_display)) ++ { ++ g_warning ("Could not set synaptics touchpad acceleration for %s", ++ clutter_input_device_get_device_name (device)); ++ } ++ ++ XFreeFeedbackList (states); ++ XCloseDevice (xdisplay, xdevice); ++} ++ + static void + meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + ClutterInputDevice *device, +@@ -173,6 +352,13 @@ meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + guchar values[2] = { 0 }; /* disabled, disabled-on-external-mouse */ + guchar *available; + ++ if (is_device_synaptics (device)) ++ { ++ values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED; ++ change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1); ++ return; ++ } ++ + available = get_property (device, "libinput Send Events Modes Available", + XA_INTEGER, 8, 2); + if (!available) +@@ -225,6 +411,12 @@ meta_input_settings_x11_set_speed (MetaInputSettings *settings, + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + gfloat value = speed; + ++ if (is_device_synaptics (device)) ++ { ++ change_synaptics_speed (device, speed); ++ return; ++ } ++ + change_property (device, "libinput Accel Speed", + XInternAtom (xdisplay, "FLOAT", False), + 32, &value, 1); +@@ -251,6 +443,19 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings, + else + { + value = enabled ? 1 : 0; ++ ++ if (is_device_synaptics (device)) ++ { ++ GSettings *settings; ++ ++ settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad"); ++ change_synaptics_tap_left_handed (device, ++ g_settings_get_boolean (settings, "tap-to-click"), ++ enabled); ++ g_object_unref (settings); ++ return; ++ } ++ + change_property (device, "libinput Left Handed Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -274,6 +479,20 @@ meta_input_settings_x11_set_tap_enabled (MetaInputSettings *settings, + { + guchar value = (enabled) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ GDesktopTouchpadHandedness handedness; ++ GSettings *settings; ++ ++ settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad"); ++ handedness = g_settings_get_enum (settings, "left-handed"); ++ g_object_unref (settings); ++ ++ change_synaptics_tap_left_handed (device, enabled, ++ handedness == G_DESKTOP_TOUCHPAD_HANDEDNESS_LEFT); ++ return; ++ } ++ + change_property (device, "libinput Tapping Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -307,6 +526,27 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings *settings, + { + guchar value = (inverted) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ gint32 *scrolling_distance; ++ ++ scrolling_distance = get_property (device, "Synaptics Scrolling Distance", ++ XA_INTEGER, 32, 2); ++ if (scrolling_distance) ++ { ++ scrolling_distance[0] = inverted ? ++ -abs (scrolling_distance[0]) : abs (scrolling_distance[0]); ++ scrolling_distance[1] = inverted ? ++ -abs (scrolling_distance[1]) : abs (scrolling_distance[1]); ++ ++ change_property (device, "Synaptics Scrolling Distance", ++ XA_INTEGER, 32, scrolling_distance, 2); ++ meta_XFree (scrolling_distance); ++ } ++ ++ return; ++ } ++ + change_property (device, "libinput Natural Scrolling Enabled", + XA_INTEGER, 8, &value, 1); + } +@@ -320,6 +560,41 @@ change_scroll_method (ClutterInputDevice *device, + guchar *current = NULL; + guchar *available = NULL; + ++ if (is_device_synaptics (device)) ++ { ++ switch (method) ++ { ++ case SCROLL_METHOD_FIELD_EDGE: ++ current = get_property (device, "Synaptics Edge Scrolling", ++ XA_INTEGER, 8, 3); ++ if (current) ++ { ++ current[0] = enabled; ++ current[1] = enabled; ++ change_property (device, "Synaptics Edge Scrolling", ++ XA_INTEGER, 8, current, 3); ++ meta_XFree (current); ++ } ++ break; ++ case SCROLL_METHOD_FIELD_2FG: ++ current = get_property (device, "Synaptics Two-Finger Scrolling", ++ XA_INTEGER, 8, 2); ++ if (current) ++ { ++ current[0] = enabled; ++ current[1] = enabled; ++ change_property (device, "Synaptics Two-Finger Scrolling", ++ XA_INTEGER, 8, current, 2); ++ meta_XFree (current); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return; ++ } ++ + available = get_property (device, "libinput Scroll Methods Available", + XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS); + if (!available || !available[method]) +-- +2.31.1 + + +From 50c4733acf56b3b67a2706d32f5c455cb51f9458 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Tue, 13 Feb 2018 11:44:40 +0100 +Subject: [PATCH 2/6] clutter: Extend touchpad device property check for + Synaptics + +So we reliably get CLUTTER_TOUCHPAD_DEVICE for those. The other heuristics +to get the device type may fall short. +--- + src/backends/x11/meta-seat-x11.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/src/backends/x11/meta-seat-x11.c b/src/backends/x11/meta-seat-x11.c +index d43834bd7b..73938e22e0 100644 +--- a/src/backends/x11/meta-seat-x11.c ++++ b/src/backends/x11/meta-seat-x11.c +@@ -246,7 +246,8 @@ is_touch_device (XIAnyClassInfo **classes, + } + + static gboolean +-is_touchpad_device (XIDeviceInfo *info) ++query_exists_device_property (XIDeviceInfo *info, ++ const char *property) + { + gulong nitems, bytes_after; + uint32_t *data = NULL; +@@ -254,7 +255,7 @@ is_touchpad_device (XIDeviceInfo *info) + Atom type; + Atom prop; + +- prop = XInternAtom (clutter_x11_get_default_display (), "libinput Tapping Enabled", True); ++ prop = XInternAtom (clutter_x11_get_default_display (), property, True); + if (prop == None) + return FALSE; + +@@ -275,6 +276,18 @@ is_touchpad_device (XIDeviceInfo *info) + return TRUE; + } + ++static gboolean ++is_touchpad_device (XIDeviceInfo *info) ++{ ++ if (query_exists_device_property (info, "libinput Tapping Enabled")) ++ return TRUE; ++ ++ if (query_exists_device_property (info, "Synaptics Off")) ++ return TRUE; ++ ++ return FALSE; ++} ++ + static gboolean + get_device_ids (XIDeviceInfo *info, + char **vendor_id, +-- +2.31.1 + + +From 307970305d11cdca1b97c53c85bda8b809ff4f0f Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 9 Oct 2017 18:39:52 +0200 +Subject: [PATCH 3/6] backends/x11: Add a synaptics check for two finger scroll + availability + +Commit "backends/x11: Support synaptics configuration" added support +for synaptics two finger scrolling but didn't add the code to check +that it is available resulting in the upper layer always assuming it +isn't. +--- + src/backends/x11/meta-input-settings-x11.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 0631fd2fee..2ac080127c 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -638,6 +638,17 @@ meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings *settings, + guchar *available = NULL; + gboolean has_two_finger = TRUE; + ++ if (is_device_synaptics (device)) ++ { ++ available = get_property (device, "Synaptics Capabilities", ++ XA_INTEGER, 8, 4); ++ if (!available || !available[3]) ++ has_two_finger = FALSE; ++ ++ meta_XFree (available); ++ return has_two_finger; ++ } ++ + available = get_property (device, "libinput Scroll Methods Available", + XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS); + if (!available || !available[SCROLL_METHOD_FIELD_2FG]) +-- +2.31.1 + + +From cba31f88ddbfb7355de1daa34397aba8e8607765 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 9 Oct 2017 18:55:56 +0200 +Subject: [PATCH 4/6] backends/x11: Add disable while typing support for + synaptics + +This is basically a copy of the old g-s-d mouse plugin code to manage +syndaemon when the synaptics driver is being used. +--- + src/backends/x11/meta-input-settings-x11.c | 112 +++++++++++++++++++++ + 1 file changed, 112 insertions(+) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 2ac080127c..2658b82172 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -35,6 +35,9 @@ + #ifdef HAVE_LIBGUDEV + #include + #endif ++#ifdef __linux ++#include ++#endif + + #include "backends/x11/meta-backend-x11.h" + #include "backends/x11/meta-input-device-x11.h" +@@ -46,6 +49,8 @@ typedef struct _MetaInputSettingsX11Private + #ifdef HAVE_LIBGUDEV + GUdevClient *udev_client; + #endif ++ gboolean syndaemon_spawned; ++ GPid syndaemon_pid; + } MetaInputSettingsX11Private; + + G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11, +@@ -344,6 +349,107 @@ change_synaptics_speed (ClutterInputDevice *device, + XCloseDevice (xdisplay, xdevice); + } + ++/* Ensure that syndaemon dies together with us, to avoid running several of ++ * them */ ++static void ++setup_syndaemon (gpointer user_data) ++{ ++#ifdef __linux ++ prctl (PR_SET_PDEATHSIG, SIGHUP); ++#endif ++} ++ ++static gboolean ++have_program_in_path (const char *name) ++{ ++ gchar *path; ++ gboolean result; ++ ++ path = g_find_program_in_path (name); ++ result = (path != NULL); ++ g_free (path); ++ return result; ++} ++ ++static void ++syndaemon_died (GPid pid, ++ gint status, ++ gpointer user_data) ++{ ++ MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (user_data); ++ MetaInputSettingsX11Private *priv = ++ meta_input_settings_x11_get_instance_private (settings_x11); ++ GError *error = NULL; ++ ++ if (!g_spawn_check_exit_status (status, &error)) ++ { ++ if ((WIFSIGNALED (status) && WTERMSIG (status) != SIGHUP) || ++ error->domain == G_SPAWN_EXIT_ERROR) ++ g_warning ("Syndaemon exited unexpectedly: %s", error->message); ++ g_error_free (error); ++ } ++ ++ g_spawn_close_pid (pid); ++ priv->syndaemon_spawned = FALSE; ++} ++ ++static void ++set_synaptics_disable_w_typing (MetaInputSettings *settings, ++ gboolean state) ++{ ++ MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings); ++ MetaInputSettingsX11Private *priv = ++ meta_input_settings_x11_get_instance_private (settings_x11); ++ ++ if (state) ++ { ++ GError *error = NULL; ++ GPtrArray *args; ++ ++ if (priv->syndaemon_spawned) ++ return; ++ ++ if (!have_program_in_path ("syndaemon")) ++ return; ++ ++ args = g_ptr_array_new (); ++ ++ g_ptr_array_add (args, (gpointer)"syndaemon"); ++ g_ptr_array_add (args, (gpointer)"-i"); ++ g_ptr_array_add (args, (gpointer)"1.0"); ++ g_ptr_array_add (args, (gpointer)"-t"); ++ g_ptr_array_add (args, (gpointer)"-K"); ++ g_ptr_array_add (args, (gpointer)"-R"); ++ g_ptr_array_add (args, NULL); ++ ++ /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid ++ * double-forking, otherwise syndaemon will immediately get ++ * killed again through (PR_SET_PDEATHSIG when the intermediate ++ * process dies */ ++ g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL, ++ G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL, ++ &priv->syndaemon_pid, &error); ++ ++ priv->syndaemon_spawned = (error == NULL); ++ g_ptr_array_free (args, TRUE); ++ ++ if (error) ++ { ++ g_warning ("Failed to launch syndaemon: %s", error->message); ++ g_error_free (error); ++ } ++ else ++ { ++ g_child_watch_add (priv->syndaemon_pid, syndaemon_died, settings); ++ } ++ } ++ else if (priv->syndaemon_spawned) ++ { ++ kill (priv->syndaemon_pid, SIGHUP); ++ priv->syndaemon_spawned = FALSE; ++ } ++} ++ + static void + meta_input_settings_x11_set_send_events (MetaInputSettings *settings, + ClutterInputDevice *device, +@@ -468,6 +574,12 @@ meta_input_settings_x11_set_disable_while_typing (MetaInputSettings *settings, + { + guchar value = (enabled) ? 1 : 0; + ++ if (is_device_synaptics (device)) ++ { ++ set_synaptics_disable_w_typing (settings, enabled); ++ return; ++ } ++ + change_property (device, "libinput Disable While Typing Enabled", + XA_INTEGER, 8, &value, 1); + } +-- +2.31.1 + + +From 354d34263534d0c7a5c7f7169d8b4a3dba79491c Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho +Date: Wed, 13 Jun 2018 13:48:24 +0200 +Subject: [PATCH 5/6] clutter: Only reset scroll axes on slave devices + +As a plus, unknown source device IDs will just warn instead of crash. +--- + src/backends/x11/meta-seat-x11.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/backends/x11/meta-seat-x11.c b/src/backends/x11/meta-seat-x11.c +index 73938e22e0..6d2c7d3740 100644 +--- a/src/backends/x11/meta-seat-x11.c ++++ b/src/backends/x11/meta-seat-x11.c +@@ -2362,7 +2362,9 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, + seat->has_pointer_focus = FALSE; + } + +- meta_input_device_x11_reset_scroll_info (source_device); ++ if (clutter_input_device_get_device_mode (source_device) == ++ CLUTTER_INPUT_MODE_PHYSICAL) ++ meta_input_device_x11_reset_scroll_info (source_device); + + clutter_event_set_device (event, device); + clutter_event_set_source_device (event, source_device); +-- +2.31.1 + + +From b7f94b5dd09953d5a4c8aee1b79491d71f8c1e0e Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Tue, 10 Oct 2017 19:07:27 +0200 +Subject: [PATCH 6/6] backends/x11: Support plain old X device configuration + +We re-use part of the code added to support synaptics and add a few +bits specific for xorg-x11-drv-evdev devices. +--- + src/backends/x11/meta-input-settings-x11.c | 98 +++++++++++++++++----- + 1 file changed, 75 insertions(+), 23 deletions(-) + +diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c +index 2658b82172..80bc33c6b5 100644 +--- a/src/backends/x11/meta-input-settings-x11.c ++++ b/src/backends/x11/meta-input-settings-x11.c +@@ -185,10 +185,23 @@ is_device_synaptics (ClutterInputDevice *device) + return TRUE; + } + ++static gboolean ++is_device_libinput (ClutterInputDevice *device) ++{ ++ guchar *has_setting; ++ ++ /* We just need looking for a synaptics-specific property */ ++ has_setting = get_property (device, "libinput Send Events Modes Available", XA_INTEGER, 8, 2); ++ if (!has_setting) ++ return FALSE; ++ ++ meta_XFree (has_setting); ++ return TRUE; ++} ++ + static void +-change_synaptics_tap_left_handed (ClutterInputDevice *device, +- gboolean tap_enabled, +- gboolean left_handed) ++change_x_device_left_handed (ClutterInputDevice *device, ++ gboolean left_handed) + { + MetaDisplay *display = meta_get_display (); + MetaX11Display *x11_display = display ? display->x11_display : NULL; +@@ -196,7 +209,7 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device, + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + int device_id; + XDevice *xdevice; +- guchar *tap_action, *buttons; ++ guchar *buttons; + guint buttons_capacity = 16, n_buttons; + + device_id = meta_input_device_x11_get_device_id (device); +@@ -204,19 +217,6 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device, + if (!xdevice) + return; + +- tap_action = get_property (device, "Synaptics Tap Action", +- XA_INTEGER, 8, 7); +- if (!tap_action) +- goto out; +- +- tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; +- tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; +- tap_action[6] = tap_enabled ? 2 : 0; +- +- change_property (device, "Synaptics Tap Action", +- XA_INTEGER, 8, tap_action, 7); +- meta_XFree (tap_action); +- + if (x11_display) + meta_x11_error_trap_push (x11_display); + buttons = g_new (guchar, buttons_capacity); +@@ -240,17 +240,39 @@ change_synaptics_tap_left_handed (ClutterInputDevice *device, + + if (x11_display && meta_x11_error_trap_pop_with_return (x11_display)) + { +- g_warning ("Could not set synaptics touchpad left-handed for %s", ++ g_warning ("Could not set left-handed for %s", + clutter_input_device_get_device_name (device)); + } + +- out: + XCloseDevice (xdisplay, xdevice); + } + + static void +-change_synaptics_speed (ClutterInputDevice *device, +- gdouble speed) ++change_synaptics_tap_left_handed (ClutterInputDevice *device, ++ gboolean tap_enabled, ++ gboolean left_handed) ++{ ++ guchar *tap_action; ++ ++ tap_action = get_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, 7); ++ if (!tap_action) ++ return; ++ ++ tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0; ++ tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0; ++ tap_action[6] = tap_enabled ? 2 : 0; ++ ++ change_property (device, "Synaptics Tap Action", ++ XA_INTEGER, 8, tap_action, 7); ++ meta_XFree (tap_action); ++ ++ change_x_device_left_handed (device, left_handed); ++} ++ ++static void ++change_x_device_speed (ClutterInputDevice *device, ++ gdouble speed) + { + MetaDisplay *display = meta_get_display (); + MetaX11Display *x11_display = display ? display->x11_display : NULL; +@@ -349,6 +371,23 @@ change_synaptics_speed (ClutterInputDevice *device, + XCloseDevice (xdisplay, xdevice); + } + ++static void ++change_x_device_scroll_button (ClutterInputDevice *device, ++ guint button) ++{ ++ guchar value; ++ ++ value = button > 0 ? 1 : 0; ++ change_property (device, "Evdev Wheel Emulation", ++ XA_INTEGER, 8, &value, 1); ++ if (button > 0) ++ { ++ value = button; ++ change_property (device, "Evdev Wheel Emulation Button", ++ XA_INTEGER, 8, &value, 1); ++ } ++} ++ + /* Ensure that syndaemon dies together with us, to avoid running several of + * them */ + static void +@@ -517,9 +556,10 @@ meta_input_settings_x11_set_speed (MetaInputSettings *settings, + Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); + gfloat value = speed; + +- if (is_device_synaptics (device)) ++ if (is_device_synaptics (device) || ++ !is_device_libinput (device)) + { +- change_synaptics_speed (device, speed); ++ change_x_device_speed (device, speed); + return; + } + +@@ -561,6 +601,11 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings, + g_object_unref (settings); + return; + } ++ else if (!is_device_libinput (device) && device_type != CLUTTER_PAD_DEVICE) ++ { ++ change_x_device_left_handed (device, enabled); ++ return; ++ } + + change_property (device, "libinput Left Handed Enabled", + XA_INTEGER, 8, &value, 1); +@@ -778,7 +823,14 @@ meta_input_settings_x11_set_scroll_button (MetaInputSettings *settings, + { + gchar lock = button_lock; + ++ if (!is_device_libinput (device)) ++ { ++ change_x_device_scroll_button (device, button); ++ return; ++ } ++ + change_scroll_method (device, SCROLL_METHOD_FIELD_BUTTON, button != 0); ++ + change_property (device, "libinput Button Scrolling Button", + XA_CARDINAL, 32, &button, 1); + change_property (device, "libinput Button Scrolling Button Lock Enabled", +-- +2.31.1 + diff --git a/mutter.spec b/mutter.spec index fe227ec..eef09ab 100644 --- a/mutter.spec +++ b/mutter.spec @@ -10,7 +10,7 @@ Name: mutter Version: 40.1 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -29,6 +29,28 @@ Patch2: 0001-Test-deny-atomic-KMS-for-tegra-RHBZ-1936991.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1964386 Patch3: 0001-clutter-actor-Don-t-emit-focus-signals-during-destru.patch +# Allow Xwayland grabs by default, on a selected set of X11 apps (rhbz#1500399) +Patch4: 0001-wayland-Allow-Xwayland-grabs-on-selected-apps.patch + +# X11 window management work arounds +Patch5: 0001-constraints-Enforce-X11-size-limits.patch + +# X11/VM monitor configuration patches (rhbz#1265511, rhbz#1618632, +# rhbz#1497303, rhbz#1690506, rhbz#1776530, rhbz#1365717, rhbz#1690170) +Patch6: x11-monitor-configuration-patches.patch + +# Sloppy focus fix (rhbz#1358535) +Patch7: 0001-events-Don-t-move-sloppy-focus-while-buttons-are-pre.patch + +# Legacy X11 configuration support (synaptics/plain) +Patch8: legacy-x11-input-configuration.patch + +# GLX Stereo (nvidia) +Patch9: glx-stereo-support.patch + +# Work around vncserver not setting the right XDG_SESSION_TYPE +Patch10: 0001-main-be-more-aggressive-in-assuming-X11-backend.patch + BuildRequires: chrpath BuildRequires: pango-devel BuildRequires: startup-notification-devel @@ -171,6 +193,10 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop %{_datadir}/mutter-%{mutter_api_version}/tests %changelog +* Thu Jun 03 2021 Jonas Ådahl - 40.1-3 +- Forward port downstream patches from RHEL8 + Resolves: #1965949 + * Wed Jun 02 2021 Florian Müllner - 40.1-2 - Don't emit ::key-focus-out on destroyed actors Resolves: #1964386 diff --git a/x11-monitor-configuration-patches.patch b/x11-monitor-configuration-patches.patch new file mode 100644 index 0000000..d0402be --- /dev/null +++ b/x11-monitor-configuration-patches.patch @@ -0,0 +1,1375 @@ +From 9c7c46384ec5e64fbfad84366c93ece52aabd26a Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Tue, 6 Oct 2015 21:16:18 +0200 +Subject: [PATCH 1/9] monitor-manager-xrandr: Work around spurious hotplugs on + Xvnc + +Xvnc turns its outputs off/on on every mode set which makes us believe +there was an hotplug when there actually wasn't. Work around this by +requiring new randr configuration timestamps to be ahead of the last +set timestamp by at least 100 ms for us to consider them an actual +hotplug. +--- + .../x11/meta-monitor-manager-xrandr.c | 21 ++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 489a9b4241..1ddc2a7870 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -1100,6 +1100,20 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) + g_quark_from_static_string ("-meta-monitor-xrandr-data"); + } + ++static gboolean ++is_xvnc (MetaMonitorManager *manager) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); ++ MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr); ++ GList *l; ++ ++ for (l = meta_gpu_get_outputs (gpu); l; l = l->next) ++ if (g_str_has_prefix (meta_output_get_name (l->data), "VNC-")) ++ return TRUE; ++ ++ return FALSE; ++} ++ + gboolean + meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, + XEvent *event) +@@ -1110,6 +1124,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra + XRRScreenResources *resources; + gboolean is_hotplug; + gboolean is_our_configuration; ++ unsigned int timestamp; + + if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) + return FALSE; +@@ -1121,7 +1136,11 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra + gpu_xrandr = META_GPU_XRANDR (gpu); + resources = meta_gpu_xrandr_get_resources (gpu_xrandr); + +- is_hotplug = resources->timestamp < resources->configTimestamp; ++ timestamp = resources->timestamp; ++ if (is_xvnc (manager)) ++ timestamp += 100; ++ ++ is_hotplug = (timestamp < resources->configTimestamp); + is_our_configuration = (resources->timestamp == + manager_xrandr->last_xrandr_set_timestamp); + if (is_hotplug) +-- +2.31.1 + + +From 17d9494cc08e833a6e896daa4f85a15b81df1554 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Mon, 4 Jun 2018 16:35:04 -0400 +Subject: [PATCH 2/9] monitor-manager-xrandr: Force an update when resuming + from suspend + +The stack below us isn't as reliable as we'd like and in some cases +doesn't generate RRScreenChangeNotify events when e.g. resuming a +laptop on a dock, meaning that we'd miss newly attached outputs. +--- + src/backends/meta-gpu.c | 7 ++ + src/backends/meta-gpu.h | 4 + + src/backends/x11/meta-gpu-xrandr.c | 26 ++++- + .../x11/meta-monitor-manager-xrandr.c | 98 +++++++++++++++++-- + 4 files changed, 125 insertions(+), 10 deletions(-) + +diff --git a/src/backends/meta-gpu.c b/src/backends/meta-gpu.c +index ce4353bf01..6b3086e747 100644 +--- a/src/backends/meta-gpu.c ++++ b/src/backends/meta-gpu.c +@@ -66,6 +66,13 @@ meta_gpu_has_hotplug_mode_update (MetaGpu *gpu) + return FALSE; + } + ++void ++meta_gpu_poll_hardware (MetaGpu *gpu) ++{ ++ if (META_GPU_GET_CLASS (gpu)->poll_hardware) ++ META_GPU_GET_CLASS (gpu)->poll_hardware (gpu); ++} ++ + gboolean + meta_gpu_read_current (MetaGpu *gpu, + GError **error) +diff --git a/src/backends/meta-gpu.h b/src/backends/meta-gpu.h +index 9d12f95a72..37b76bd0fa 100644 +--- a/src/backends/meta-gpu.h ++++ b/src/backends/meta-gpu.h +@@ -36,8 +36,12 @@ struct _MetaGpuClass + + gboolean (* read_current) (MetaGpu *gpu, + GError **error); ++ void (* poll_hardware) (MetaGpu *gpu); + }; + ++META_EXPORT_TEST ++void meta_gpu_poll_hardware (MetaGpu *gpu); ++ + META_EXPORT_TEST + gboolean meta_gpu_read_current (MetaGpu *gpu, + GError **error); +diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c +index bc3292d368..6a96e53979 100644 +--- a/src/backends/x11/meta-gpu-xrandr.c ++++ b/src/backends/x11/meta-gpu-xrandr.c +@@ -46,6 +46,8 @@ struct _MetaGpuXrandr + + int max_screen_width; + int max_screen_height; ++ ++ gboolean need_hardware_poll; + }; + + G_DEFINE_TYPE (MetaGpuXrandr, meta_gpu_xrandr, META_TYPE_GPU) +@@ -86,6 +88,14 @@ get_xmode_name (XRRModeInfo *xmode) + return g_strdup_printf ("%dx%d", width, height); + } + ++static void ++meta_gpu_xrandr_poll_hardware (MetaGpu *gpu) ++{ ++ MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu); ++ ++ gpu_xrandr->need_hardware_poll = TRUE; ++} ++ + static gboolean + meta_gpu_xrandr_read_current (MetaGpu *gpu, + GError **error) +@@ -123,8 +133,18 @@ meta_gpu_xrandr_read_current (MetaGpu *gpu, + monitor_manager->screen_width = WidthOfScreen (screen); + monitor_manager->screen_height = HeightOfScreen (screen); + +- resources = XRRGetScreenResourcesCurrent (xdisplay, +- DefaultRootWindow (xdisplay)); ++ if (gpu_xrandr->need_hardware_poll) ++ { ++ resources = XRRGetScreenResources (xdisplay, ++ DefaultRootWindow (xdisplay)); ++ gpu_xrandr->need_hardware_poll = FALSE; ++ } ++ else ++ { ++ resources = XRRGetScreenResourcesCurrent (xdisplay, ++ DefaultRootWindow (xdisplay)); ++ } ++ + if (!resources) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +@@ -263,6 +283,7 @@ meta_gpu_xrandr_finalize (GObject *object) + static void + meta_gpu_xrandr_init (MetaGpuXrandr *gpu_xrandr) + { ++ gpu_xrandr->need_hardware_poll = TRUE; + } + + static void +@@ -274,4 +295,5 @@ meta_gpu_xrandr_class_init (MetaGpuXrandrClass *klass) + object_class->finalize = meta_gpu_xrandr_finalize; + + gpu_class->read_current = meta_gpu_xrandr_read_current; ++ gpu_class->poll_hardware = meta_gpu_xrandr_poll_hardware; + } +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 1ddc2a7870..61e13f459d 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -72,6 +72,10 @@ struct _MetaMonitorManagerXrandr + Display *xdisplay; + int rr_event_base; + int rr_error_base; ++ ++ guint logind_watch_id; ++ guint logind_signal_sub_id; ++ + gboolean has_randr15; + + xcb_timestamp_t last_xrandr_set_timestamp; +@@ -96,6 +100,8 @@ typedef struct _MetaMonitorXrandrData + + GQuark quark_meta_monitor_xrandr_data; + ++static void meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr); ++ + Display * + meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr) + { +@@ -1009,6 +1015,64 @@ meta_monitor_manager_xrandr_set_output_ctm (MetaOutput *output, + meta_output_xrandr_set_ctm (META_OUTPUT_XRANDR (output), ctm); + } + ++static void ++logind_signal_handler (GDBusConnection *connection, ++ const gchar *sender_name, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *signal_name, ++ GVariant *parameters, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ gboolean suspending; ++ ++ if (!g_str_equal (signal_name, "PrepareForSleep")) ++ return; ++ ++ g_variant_get (parameters, "(b)", &suspending); ++ if (!suspending) ++ { ++ MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr); ++ ++ meta_gpu_poll_hardware (gpu); ++ meta_monitor_manager_xrandr_update (manager_xrandr); ++ } ++} ++ ++static void ++logind_appeared (GDBusConnection *connection, ++ const gchar *name, ++ const gchar *name_owner, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ ++ manager_xrandr->logind_signal_sub_id = g_dbus_connection_signal_subscribe (connection, ++ "org.freedesktop.login1", ++ "org.freedesktop.login1.Manager", ++ "PrepareForSleep", ++ "/org/freedesktop/login1", ++ NULL, ++ G_DBUS_SIGNAL_FLAGS_NONE, ++ logind_signal_handler, ++ manager_xrandr, ++ NULL); ++} ++ ++static void ++logind_vanished (GDBusConnection *connection, ++ const gchar *name, ++ gpointer user_data) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = user_data; ++ ++ if (connection && manager_xrandr->logind_signal_sub_id > 0) ++ g_dbus_connection_signal_unsubscribe (connection, manager_xrandr->logind_signal_sub_id); ++ ++ manager_xrandr->logind_signal_sub_id = 0; ++} ++ + static void + meta_monitor_manager_xrandr_constructed (GObject *object) + { +@@ -1061,12 +1125,23 @@ meta_monitor_manager_xrandr_finalize (GObject *object) + g_hash_table_destroy (manager_xrandr->tiled_monitor_atoms); + g_free (manager_xrandr->supported_scales); + ++ if (manager_xrandr->logind_watch_id > 0) ++ g_bus_unwatch_name (manager_xrandr->logind_watch_id); ++ manager_xrandr->logind_watch_id = 0; ++ + G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object); + } + + static void + meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) + { ++ manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, ++ "org.freedesktop.login1", ++ G_BUS_NAME_WATCHER_FLAGS_NONE, ++ logind_appeared, ++ logind_vanished, ++ manager_xrandr, ++ NULL); + } + + static void +@@ -1114,9 +1189,8 @@ is_xvnc (MetaMonitorManager *manager) + return FALSE; + } + +-gboolean +-meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, +- XEvent *event) ++static void ++meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr) + { + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); + MetaGpu *gpu = meta_monitor_manager_xrandr_get_gpu (manager_xrandr); +@@ -1126,11 +1200,6 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra + gboolean is_our_configuration; + unsigned int timestamp; + +- if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) +- return FALSE; +- +- XRRUpdateConfiguration (event); +- + meta_monitor_manager_read_current_state (manager); + + gpu_xrandr = META_GPU_XRANDR (gpu); +@@ -1165,6 +1234,19 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra + + meta_monitor_manager_xrandr_rebuild_derived (manager, config); + } ++} ++ ++gboolean ++meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, ++ XEvent *event) ++{ ++ ++ if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) ++ return FALSE; ++ ++ XRRUpdateConfiguration (event); ++ ++ meta_monitor_manager_xrandr_update (manager_xrandr); + + return TRUE; + } +-- +2.31.1 + + +From 7a04949b978ebe96cd088d7bd255fd3f52c7c355 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 24 Feb 2020 16:09:59 +0100 +Subject: [PATCH 3/9] Revert "MetaMonitorManager: ignore hotplug_mode_update at + startup" + +This reverts commit 183f4b0c13f3dc9565bf5f693f2e5d61ca0199c9. +--- + src/backends/meta-monitor-manager.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c +index a75da9329e..c291ddb5d3 100644 +--- a/src/backends/meta-monitor-manager.c ++++ b/src/backends/meta-monitor-manager.c +@@ -609,8 +609,7 @@ meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager) + static gboolean + should_use_stored_config (MetaMonitorManager *manager) + { +- return (manager->in_init || +- !meta_monitor_manager_has_hotplug_mode_update (manager)); ++ return !meta_monitor_manager_has_hotplug_mode_update (manager); + } + + MetaMonitorsConfig * +-- +2.31.1 + + +From babcf2a6d09136bcf1bf2dc958046aaa0334b85e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 28 Jan 2016 15:26:33 +0100 +Subject: [PATCH 4/9] monitor-manager: Consider external layout before default + linear config + +In case of no existing configuration, we use a default layout of +aligning attached displays horizontally. This sidesteps any layout +configuration that is done externally, for instance via xorg.conf, +which is not desirable. Instead, base the initial configuration on +the existing layout if it passes some sanity checks before falling +back to the default linear config. +--- + src/backends/meta-monitor-config-manager.c | 86 ++++++++++++++++++++++ + src/backends/meta-monitor-config-manager.h | 2 + + src/backends/meta-monitor-manager.c | 19 +++++ + 3 files changed, 107 insertions(+) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index 0253e072ff..2f6cc3856f 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -739,6 +739,92 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_ma + return logical_monitor_config; + } + ++static MetaLogicalMonitorConfig * ++create_logical_monitor_config_from_output (MetaMonitorManager *monitor_manager, ++ MetaMonitor *monitor, ++ MetaLogicalMonitorConfig *primary_logical_monitor_config, ++ MetaLogicalMonitorLayoutMode layout_mode) ++{ ++ MetaOutput *output; ++ MetaCrtc *crtc; ++ const MetaCrtcConfig *crtc_config; ++ ++ output = meta_monitor_get_main_output (monitor); ++ crtc = meta_output_get_assigned_crtc (output); ++ crtc_config = meta_crtc_get_config (crtc); ++ if (!crtc_config) ++ return NULL; ++ ++ return create_preferred_logical_monitor_config (monitor_manager, ++ monitor, ++ (int) crtc_config->layout.origin.x, ++ (int) crtc_config->layout.origin.y, ++ primary_logical_monitor_config, ++ layout_mode); ++} ++ ++MetaMonitorsConfig * ++meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager) ++{ ++ MetaMonitorManager *monitor_manager = config_manager->monitor_manager; ++ GList *logical_monitor_configs; ++ MetaMonitor *primary_monitor; ++ MetaLogicalMonitorLayoutMode layout_mode; ++ MetaLogicalMonitorConfig *primary_logical_monitor_config; ++ GList *monitors; ++ GList *l; ++ ++ if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0) ++ return NULL; ++ ++ primary_monitor = find_primary_monitor (monitor_manager); ++ if (!primary_monitor || !meta_monitor_is_active (primary_monitor)) ++ return NULL; ++ ++ layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager); ++ ++ primary_logical_monitor_config = ++ create_logical_monitor_config_from_output (monitor_manager, ++ primary_monitor, ++ NULL, ++ layout_mode); ++ if (!primary_logical_monitor_config) ++ return NULL; ++ ++ primary_logical_monitor_config->is_primary = TRUE; ++ logical_monitor_configs = g_list_append (NULL, ++ primary_logical_monitor_config); ++ ++ monitors = meta_monitor_manager_get_monitors (monitor_manager); ++ for (l = monitors; l; l = l->next) ++ { ++ MetaMonitor *monitor = l->data; ++ MetaLogicalMonitorConfig *logical_monitor_config; ++ ++ if (monitor == primary_monitor) ++ continue; ++ ++ if (!meta_monitor_is_active (monitor)) ++ continue; ++ ++ logical_monitor_config = ++ create_logical_monitor_config_from_output (monitor_manager, ++ monitor, ++ primary_logical_monitor_config, ++ layout_mode); ++ if (!logical_monitor_config) ++ continue; ++ ++ logical_monitor_configs = g_list_append (logical_monitor_configs, ++ logical_monitor_config); ++ } ++ ++ return meta_monitors_config_new (monitor_manager, ++ logical_monitor_configs, ++ layout_mode, ++ META_MONITORS_CONFIG_FLAG_NONE); ++} ++ + MetaMonitorsConfig * + meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager) + { +diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h +index 86756a7e33..961d604bd5 100644 +--- a/src/backends/meta-monitor-config-manager.h ++++ b/src/backends/meta-monitor-config-manager.h +@@ -94,6 +94,8 @@ gboolean meta_monitor_config_manager_assign (MetaMonitorManager *manager, + META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager); + ++META_EXPORT_TEST ++MetaMonitorsConfig * meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager); + META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager); + +diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c +index c291ddb5d3..96f0d6b84a 100644 +--- a/src/backends/meta-monitor-manager.c ++++ b/src/backends/meta-monitor-manager.c +@@ -695,6 +695,25 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + g_clear_object (&config); + } + ++ config = meta_monitor_config_manager_create_current (manager->config_manager); ++ if (config) ++ { ++ if (!meta_monitor_manager_apply_monitors_config (manager, ++ config, ++ method, ++ &error)) ++ { ++ g_clear_object (&config); ++ g_warning ("Failed to use current monitor configuration: %s", ++ error->message); ++ g_clear_error (&error); ++ } ++ else ++ { ++ goto done; ++ } ++ } ++ + config = meta_monitor_config_manager_create_linear (manager->config_manager); + if (config) + { +-- +2.31.1 + + +From ada8c9b1346fe261a8fa04f68149c79d95c969ac Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 11 Sep 2018 10:19:44 -0400 +Subject: [PATCH 5/9] monitor-manager: only reuse initial-config if monitor + topology matches startup + +Right now we try to apply the current monitor config when a new +monitor is attached. The current config obviously doesn't include the +new monitor, so the new monitor isn't lit up. + +The only reason we apply the current config at all is to handle the +startup case: We want to reuse the config set in Xorg when first +logging in. + +This commit changes the code to look at the *initial config* instead +of the current config, and only if the new monitor topology matches +the start up topology. +--- + src/backends/meta-monitor-config-manager.c | 20 +++++++++++++++----- + src/backends/meta-monitor-config-manager.h | 2 +- + src/backends/meta-monitor-manager.c | 16 +++++++++++++++- + 3 files changed, 31 insertions(+), 7 deletions(-) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index 2f6cc3856f..46249755bc 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -42,6 +42,7 @@ struct _MetaMonitorConfigManager + MetaMonitorConfigStore *config_store; + + MetaMonitorsConfig *current_config; ++ MetaMonitorsConfig *initial_config; + GQueue config_history; + }; + +@@ -764,9 +765,10 @@ create_logical_monitor_config_from_output (MetaMonitorManager *monitor + } + + MetaMonitorsConfig * +-meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager) ++meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager) + { + MetaMonitorManager *monitor_manager = config_manager->monitor_manager; ++ MetaMonitorsConfig *initial_config; + GList *logical_monitor_configs; + MetaMonitor *primary_monitor; + MetaLogicalMonitorLayoutMode layout_mode; +@@ -774,6 +776,9 @@ meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_man + GList *monitors; + GList *l; + ++ if (config_manager->initial_config != NULL) ++ return g_object_ref (config_manager->initial_config); ++ + if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0) + return NULL; + +@@ -819,10 +824,14 @@ meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_man + logical_monitor_config); + } + +- return meta_monitors_config_new (monitor_manager, +- logical_monitor_configs, +- layout_mode, +- META_MONITORS_CONFIG_FLAG_NONE); ++ initial_config = meta_monitors_config_new (monitor_manager, ++ logical_monitor_configs, ++ layout_mode, ++ META_MONITORS_CONFIG_FLAG_NONE); ++ ++ config_manager->initial_config = g_object_ref (initial_config); ++ ++ return initial_config; + } + + MetaMonitorsConfig * +@@ -1453,6 +1462,7 @@ meta_monitor_config_manager_dispose (GObject *object) + META_MONITOR_CONFIG_MANAGER (object); + + g_clear_object (&config_manager->current_config); ++ g_clear_object (&config_manager->initial_config); + meta_monitor_config_manager_clear_history (config_manager); + + G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object); +diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h +index 961d604bd5..dc273c961b 100644 +--- a/src/backends/meta-monitor-config-manager.h ++++ b/src/backends/meta-monitor-config-manager.h +@@ -95,7 +95,7 @@ META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager); + + META_EXPORT_TEST +-MetaMonitorsConfig * meta_monitor_config_manager_create_current (MetaMonitorConfigManager *config_manager); ++MetaMonitorsConfig * meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager); + META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager); + +diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c +index 96f0d6b84a..baf5bf2f9f 100644 +--- a/src/backends/meta-monitor-manager.c ++++ b/src/backends/meta-monitor-manager.c +@@ -615,9 +615,11 @@ should_use_stored_config (MetaMonitorManager *manager) + MetaMonitorsConfig * + meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + { ++ g_autoptr (MetaMonitorsConfig) initial_config = NULL; + MetaMonitorsConfig *config = NULL; + GError *error = NULL; + gboolean use_stored_config; ++ MetaMonitorsConfigKey *current_state_key; + MetaMonitorsConfigMethod method; + MetaMonitorsConfigMethod fallback_method = + META_MONITORS_CONFIG_METHOD_TEMPORARY; +@@ -628,6 +630,18 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + else + method = META_MONITORS_CONFIG_METHOD_TEMPORARY; + ++ initial_config = meta_monitor_config_manager_create_initial (manager->config_manager); ++ ++ if (initial_config) ++ { ++ current_state_key = meta_create_monitors_config_key_for_current_state (manager); ++ ++ /* don't ever reuse initial configuration, if the monitor topology changed ++ */ ++ if (current_state_key && !meta_monitors_config_key_equal (current_state_key, initial_config->key)) ++ g_clear_object (&initial_config); ++ } ++ + if (use_stored_config) + { + config = meta_monitor_config_manager_get_stored (manager->config_manager); +@@ -695,7 +709,7 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + g_clear_object (&config); + } + +- config = meta_monitor_config_manager_create_current (manager->config_manager); ++ config = g_steal_pointer (&initial_config); + if (config) + { + if (!meta_monitor_manager_apply_monitors_config (manager, +-- +2.31.1 + + +From baa22f3ac77f549bd36c2a0ea45ba4caee434ddc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 18 Mar 2019 17:08:11 +0100 +Subject: [PATCH 6/9] monitor-config-manager: Use current mode when deriving + current config + +Instead of overriding the existing mode with the preferred mode of the monitor, +use the one already configured. Also use the MetaMonitor API for deriving the +position of the monitor in the screen coordinate space. +--- + src/backends/meta-monitor-config-manager.c | 80 +++++++++++++--------- + 1 file changed, 46 insertions(+), 34 deletions(-) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index 46249755bc..f355879c3e 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -678,21 +678,20 @@ get_monitor_transform (MetaMonitorManager *monitor_manager, + } + + static MetaLogicalMonitorConfig * +-create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager, +- MetaMonitor *monitor, +- int x, +- int y, +- MetaLogicalMonitorConfig *primary_logical_monitor_config, +- MetaLogicalMonitorLayoutMode layout_mode) ++create_logical_monitor_config (MetaMonitorManager *monitor_manager, ++ MetaMonitor *monitor, ++ MetaMonitorMode *mode, ++ int x, ++ int y, ++ MetaLogicalMonitorConfig *primary_logical_monitor_config, ++ MetaLogicalMonitorLayoutMode layout_mode) + { +- MetaMonitorMode *mode; + int width, height; + float scale; + MetaMonitorTransform transform; + MetaMonitorConfig *monitor_config; + MetaLogicalMonitorConfig *logical_monitor_config; + +- mode = meta_monitor_get_preferred_mode (monitor); + meta_monitor_mode_get_resolution (mode, &width, &height); + + if ((meta_monitor_manager_get_capabilities (monitor_manager) & +@@ -741,27 +740,40 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_ma + } + + static MetaLogicalMonitorConfig * +-create_logical_monitor_config_from_output (MetaMonitorManager *monitor_manager, +- MetaMonitor *monitor, +- MetaLogicalMonitorConfig *primary_logical_monitor_config, +- MetaLogicalMonitorLayoutMode layout_mode) ++create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager, ++ MetaMonitor *monitor, ++ int x, ++ int y, ++ MetaLogicalMonitorConfig *primary_logical_monitor_config, ++ MetaLogicalMonitorLayoutMode layout_mode) + { +- MetaOutput *output; +- MetaCrtc *crtc; +- const MetaCrtcConfig *crtc_config; ++ return create_logical_monitor_config (monitor_manager, ++ monitor, ++ meta_monitor_get_preferred_mode (monitor), ++ x, y, ++ primary_logical_monitor_config, ++ layout_mode); ++} + +- output = meta_monitor_get_main_output (monitor); +- crtc = meta_output_get_assigned_crtc (output); +- crtc_config = meta_crtc_get_config (crtc); +- if (!crtc_config) +- return NULL; ++static MetaLogicalMonitorConfig * ++create_logical_monitor_config_from_monitor (MetaMonitorManager *monitor_manager, ++ MetaMonitor *monitor, ++ MetaLogicalMonitorConfig *primary_logical_monitor_config, ++ MetaLogicalMonitorLayoutMode layout_mode) ++{ ++ MetaRectangle monitor_layout; ++ MetaMonitorMode *mode; ++ ++ meta_monitor_derive_layout (monitor, &monitor_layout); ++ mode = meta_monitor_get_current_mode (monitor); + +- return create_preferred_logical_monitor_config (monitor_manager, +- monitor, +- (int) crtc_config->layout.origin.x, +- (int) crtc_config->layout.origin.y, +- primary_logical_monitor_config, +- layout_mode); ++ return create_logical_monitor_config (monitor_manager, ++ monitor, ++ mode, ++ monitor_layout.x, ++ monitor_layout.y, ++ primary_logical_monitor_config, ++ layout_mode); + } + + MetaMonitorsConfig * +@@ -789,10 +801,10 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man + layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager); + + primary_logical_monitor_config = +- create_logical_monitor_config_from_output (monitor_manager, +- primary_monitor, +- NULL, +- layout_mode); ++ create_logical_monitor_config_from_monitor (monitor_manager, ++ primary_monitor, ++ NULL, ++ layout_mode); + if (!primary_logical_monitor_config) + return NULL; + +@@ -813,10 +825,10 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man + continue; + + logical_monitor_config = +- create_logical_monitor_config_from_output (monitor_manager, +- monitor, +- primary_logical_monitor_config, +- layout_mode); ++ create_logical_monitor_config_from_monitor (monitor_manager, ++ monitor, ++ primary_logical_monitor_config, ++ layout_mode); + if (!logical_monitor_config) + continue; + +-- +2.31.1 + + +From 52622c80f747a03738823471be9d275c7a2fd8c0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 18 Mar 2019 17:10:37 +0100 +Subject: [PATCH 7/9] monitor-manager: Don't try to derive current config on + non-X11 + +This commit also reworks the initial config state reading some. Appart from +avoiding trying to inherit from backends where it doesn't make sense, it does +the following changes: + + * Replace the name "initial" with "inherited", as the initial config in the + context of monitor management is the one used initialization. E.g. if there is + a applicable configuration in monitors.xml, the initial config is taken from + there. + + * Don't make "_create_()" functions have side effects. Previously + meta_monitor_config_manager_create_initial() also set state on the config + manager object. Instead, add a meta_monitor_config_manager_ensure_inherited() + and meta_monitor_manager_get_inherited_config() function to make things more + explicit. + + * Don't recreate "is-applicable" logic, just use the existing helper. +--- + src/backends/meta-monitor-config-manager.c | 39 +++++++++++-------- + src/backends/meta-monitor-config-manager.h | 5 +++ + src/backends/meta-monitor-manager-private.h | 4 +- + src/backends/meta-monitor-manager.c | 32 ++++++++------- + .../x11/meta-monitor-manager-xrandr.c | 3 +- + 5 files changed, 49 insertions(+), 34 deletions(-) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index f355879c3e..4b37657d34 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -42,7 +42,7 @@ struct _MetaMonitorConfigManager + MetaMonitorConfigStore *config_store; + + MetaMonitorsConfig *current_config; +- MetaMonitorsConfig *initial_config; ++ MetaMonitorsConfig *inherited_config; + GQueue config_history; + }; + +@@ -776,11 +776,10 @@ create_logical_monitor_config_from_monitor (MetaMonitorManager *monito + layout_mode); + } + +-MetaMonitorsConfig * +-meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager) ++static MetaMonitorsConfig * ++meta_monitor_config_manager_derive_current (MetaMonitorConfigManager *config_manager) + { + MetaMonitorManager *monitor_manager = config_manager->monitor_manager; +- MetaMonitorsConfig *initial_config; + GList *logical_monitor_configs; + MetaMonitor *primary_monitor; + MetaLogicalMonitorLayoutMode layout_mode; +@@ -788,12 +787,6 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man + GList *monitors; + GList *l; + +- if (config_manager->initial_config != NULL) +- return g_object_ref (config_manager->initial_config); +- +- if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0) +- return NULL; +- + primary_monitor = find_primary_monitor (monitor_manager); + if (!primary_monitor || !meta_monitor_is_active (primary_monitor)) + return NULL; +@@ -836,14 +829,26 @@ meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_man + logical_monitor_config); + } + +- initial_config = meta_monitors_config_new (monitor_manager, +- logical_monitor_configs, +- layout_mode, +- META_MONITORS_CONFIG_FLAG_NONE); ++ return meta_monitors_config_new (monitor_manager, ++ logical_monitor_configs, ++ layout_mode, ++ META_MONITORS_CONFIG_FLAG_NONE); ++} ++ ++void ++meta_monitor_config_manager_ensure_inherited_config (MetaMonitorConfigManager *config_manager) ++{ ++ if (config_manager->inherited_config) ++ return; + +- config_manager->initial_config = g_object_ref (initial_config); ++ config_manager->inherited_config = ++ meta_monitor_config_manager_derive_current (config_manager); ++} + +- return initial_config; ++MetaMonitorsConfig * ++meta_monitor_config_manager_get_inherited_config (MetaMonitorConfigManager *config_manager) ++{ ++ return config_manager->inherited_config; + } + + MetaMonitorsConfig * +@@ -1474,7 +1479,7 @@ meta_monitor_config_manager_dispose (GObject *object) + META_MONITOR_CONFIG_MANAGER (object); + + g_clear_object (&config_manager->current_config); +- g_clear_object (&config_manager->initial_config); ++ g_clear_object (&config_manager->inherited_config); + meta_monitor_config_manager_clear_history (config_manager); + + G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object); +diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h +index dc273c961b..641ed1bc1a 100644 +--- a/src/backends/meta-monitor-config-manager.h ++++ b/src/backends/meta-monitor-config-manager.h +@@ -96,6 +96,11 @@ MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigMa + + META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager); ++ ++void meta_monitor_config_manager_ensure_inherited_config (MetaMonitorConfigManager *config_manager); ++ ++MetaMonitorsConfig * meta_monitor_config_manager_get_inherited_config (MetaMonitorConfigManager *config_manager); ++ + META_EXPORT_TEST + MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager); + +diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h +index 60c1e90821..571b9000dc 100644 +--- a/src/backends/meta-monitor-manager-private.h ++++ b/src/backends/meta-monitor-manager-private.h +@@ -44,7 +44,8 @@ typedef enum _MetaMonitorManagerCapability + { + META_MONITOR_MANAGER_CAPABILITY_NONE = 0, + META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 0), +- META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED = (1 << 1) ++ META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED = (1 << 1), ++ META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT = (1 << 2), + } MetaMonitorManagerCapability; + + /* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */ +@@ -145,6 +146,7 @@ struct _MetaMonitorManager + guint panel_orientation_managed : 1; + + MetaMonitorConfigManager *config_manager; ++ MetaMonitorsConfig *initial_config; + + GnomePnpIds *pnp_ids; + +diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c +index baf5bf2f9f..9e57db94cd 100644 +--- a/src/backends/meta-monitor-manager.c ++++ b/src/backends/meta-monitor-manager.c +@@ -612,14 +612,21 @@ should_use_stored_config (MetaMonitorManager *manager) + return !meta_monitor_manager_has_hotplug_mode_update (manager); + } + ++static gboolean ++can_derive_current_config (MetaMonitorManager *manager) ++{ ++ MetaMonitorManagerCapability capabilities; ++ ++ capabilities = meta_monitor_manager_get_capabilities (manager); ++ return !!(capabilities & META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT); ++} ++ + MetaMonitorsConfig * + meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + { +- g_autoptr (MetaMonitorsConfig) initial_config = NULL; + MetaMonitorsConfig *config = NULL; + GError *error = NULL; + gboolean use_stored_config; +- MetaMonitorsConfigKey *current_state_key; + MetaMonitorsConfigMethod method; + MetaMonitorsConfigMethod fallback_method = + META_MONITORS_CONFIG_METHOD_TEMPORARY; +@@ -630,17 +637,8 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + else + method = META_MONITORS_CONFIG_METHOD_TEMPORARY; + +- initial_config = meta_monitor_config_manager_create_initial (manager->config_manager); +- +- if (initial_config) +- { +- current_state_key = meta_create_monitors_config_key_for_current_state (manager); +- +- /* don't ever reuse initial configuration, if the monitor topology changed +- */ +- if (current_state_key && !meta_monitors_config_key_equal (current_state_key, initial_config->key)) +- g_clear_object (&initial_config); +- } ++ if (can_derive_current_config (manager)) ++ meta_monitor_config_manager_ensure_inherited_config (manager->config_manager); + + if (use_stored_config) + { +@@ -709,9 +707,13 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) + g_clear_object (&config); + } + +- config = g_steal_pointer (&initial_config); +- if (config) ++ config = ++ meta_monitor_config_manager_get_inherited_config (manager->config_manager); ++ if (config && ++ meta_monitor_manager_is_config_complete (manager, config)) + { ++ config = g_object_ref (config); ++ + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + method, +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 61e13f459d..90ccb74053 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -984,7 +984,8 @@ meta_monitor_manager_xrandr_calculate_supported_scales (MetaMonitorManager + static MetaMonitorManagerCapability + meta_monitor_manager_xrandr_get_capabilities (MetaMonitorManager *manager) + { +- return META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED; ++ return (META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED | ++ META_MONITOR_MANAGER_CAPABILITY_CAN_DERIVE_CURRENT); + } + + static gboolean +-- +2.31.1 + + +From e15c812ef8525d6dd6db730c1c6a1f8ad839bb09 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 27 Nov 2019 19:03:50 +0100 +Subject: [PATCH 8/9] monitor-manager-xrandr: Move dpms state and screen size + updating into helpers + +To be used by no-Xrandr fallback path. +--- + src/backends/x11/meta-gpu-xrandr.c | 39 +++++++++++++------ + .../x11/meta-monitor-manager-xrandr.c | 18 ++++++--- + 2 files changed, 40 insertions(+), 17 deletions(-) + +diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c +index 6a96e53979..e8361c77bc 100644 +--- a/src/backends/x11/meta-gpu-xrandr.c ++++ b/src/backends/x11/meta-gpu-xrandr.c +@@ -96,6 +96,32 @@ meta_gpu_xrandr_poll_hardware (MetaGpu *gpu) + gpu_xrandr->need_hardware_poll = TRUE; + } + ++static void ++update_screen_size (MetaGpuXrandr *gpu_xrandr) ++{ ++ MetaGpu *gpu = META_GPU (gpu_xrandr); ++ MetaBackend *backend = meta_gpu_get_backend (gpu); ++ MetaMonitorManager *monitor_manager = ++ meta_backend_get_monitor_manager (backend); ++ MetaMonitorManagerXrandr *monitor_manager_xrandr = ++ META_MONITOR_MANAGER_XRANDR (monitor_manager); ++ Display *xdisplay = ++ meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr); ++ int min_width, min_height; ++ Screen *screen; ++ ++ XRRGetScreenSizeRange (xdisplay, DefaultRootWindow (xdisplay), ++ &min_width, ++ &min_height, ++ &gpu_xrandr->max_screen_width, ++ &gpu_xrandr->max_screen_height); ++ ++ screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay)); ++ /* This is updated because we called XRRUpdateConfiguration. */ ++ monitor_manager->screen_width = WidthOfScreen (screen); ++ monitor_manager->screen_height = HeightOfScreen (screen); ++} ++ + static gboolean + meta_gpu_xrandr_read_current (MetaGpu *gpu, + GError **error) +@@ -112,8 +138,6 @@ meta_gpu_xrandr_read_current (MetaGpu *gpu, + RROutput primary_output; + unsigned int i, j; + GList *l; +- int min_width, min_height; +- Screen *screen; + GList *outputs = NULL; + GList *modes = NULL; + GList *crtcs = NULL; +@@ -122,16 +146,7 @@ meta_gpu_xrandr_read_current (MetaGpu *gpu, + XRRFreeScreenResources (gpu_xrandr->resources); + gpu_xrandr->resources = NULL; + +- XRRGetScreenSizeRange (xdisplay, DefaultRootWindow (xdisplay), +- &min_width, +- &min_height, +- &gpu_xrandr->max_screen_width, +- &gpu_xrandr->max_screen_height); +- +- screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay)); +- /* This is updated because we called XRRUpdateConfiguration. */ +- monitor_manager->screen_width = WidthOfScreen (screen); +- monitor_manager->screen_height = HeightOfScreen (screen); ++ update_screen_size (gpu_xrandr); + + if (gpu_xrandr->need_hardware_poll) + { +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 90ccb74053..1b35545a09 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -140,12 +140,9 @@ x11_dpms_state_to_power_save (CARD16 dpms_state) + } + + static void +-meta_monitor_manager_xrandr_read_current_state (MetaMonitorManager *manager) ++meta_monitor_manager_xrandr_update_dpms_state (MetaMonitorManagerXrandr *manager_xrandr) + { +- MetaMonitorManagerXrandr *manager_xrandr = +- META_MONITOR_MANAGER_XRANDR (manager); +- MetaMonitorManagerClass *parent_class = +- META_MONITOR_MANAGER_CLASS (meta_monitor_manager_xrandr_parent_class); ++ MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); + Display *xdisplay = meta_monitor_manager_xrandr_get_xdisplay (manager_xrandr); + BOOL dpms_capable, dpms_enabled; + CARD16 dpms_state; +@@ -161,6 +158,17 @@ meta_monitor_manager_xrandr_read_current_state (MetaMonitorManager *manager) + power_save_mode = META_POWER_SAVE_UNSUPPORTED; + + meta_monitor_manager_power_save_mode_changed (manager, power_save_mode); ++} ++ ++static void ++meta_monitor_manager_xrandr_read_current_state (MetaMonitorManager *manager) ++{ ++ MetaMonitorManagerXrandr *manager_xrandr = ++ META_MONITOR_MANAGER_XRANDR (manager); ++ MetaMonitorManagerClass *parent_class = ++ META_MONITOR_MANAGER_CLASS (meta_monitor_manager_xrandr_parent_class); ++ ++ meta_monitor_manager_xrandr_update_dpms_state (manager_xrandr); + + parent_class->read_current_state (manager); + } +-- +2.31.1 + + +From 49307c3171b086ba5cdebe633f97a217042c8903 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 3 Oct 2018 10:50:47 +0200 +Subject: [PATCH 9/9] monitor-manager/xrandr: Create dummy screen sized monitor + if no RANDR + +When there is no RANDR support enabled in the X server, we wont get +notified of any monitors, resulting in mutter believing we're being +headless. To get at least something working, although with no way +configuration ability, lets pretend the whole screen is just a single +monitor with a single output, crtc and mode. +--- + src/backends/x11/meta-gpu-xrandr.c | 86 +++++++++++++++++++ + .../x11/meta-monitor-manager-xrandr.c | 22 ++++- + .../x11/meta-monitor-manager-xrandr.h | 4 + + 3 files changed, 111 insertions(+), 1 deletion(-) + +diff --git a/src/backends/x11/meta-gpu-xrandr.c b/src/backends/x11/meta-gpu-xrandr.c +index e8361c77bc..3ecb80bb2c 100644 +--- a/src/backends/x11/meta-gpu-xrandr.c ++++ b/src/backends/x11/meta-gpu-xrandr.c +@@ -122,6 +122,89 @@ update_screen_size (MetaGpuXrandr *gpu_xrandr) + monitor_manager->screen_height = HeightOfScreen (screen); + } + ++static gboolean ++read_current_fallback (MetaGpuXrandr *gpu_xrandr, ++ MetaMonitorManagerXrandr *monitor_manager_xrandr) ++{ ++ MetaGpu *gpu = META_GPU (gpu_xrandr); ++ MetaMonitorManager *monitor_manager = ++ META_MONITOR_MANAGER (monitor_manager_xrandr); ++ g_autoptr (MetaCrtcModeInfo) crtc_mode_info = NULL; ++ g_autofree char *mode_name = NULL; ++ MetaCrtcMode *mode; ++ MetaCrtc *crtc; ++ g_autoptr (MetaOutputInfo) output_info = NULL; ++ MetaOutputAssignment output_assignment; ++ MetaOutput *output; ++ ++ meta_monitor_manager_xrandr_update_dpms_state (monitor_manager_xrandr); ++ update_screen_size (gpu_xrandr); ++ ++ crtc_mode_info = meta_crtc_mode_info_new (); ++ crtc_mode_info->width = monitor_manager->screen_width; ++ crtc_mode_info->height = monitor_manager->screen_height; ++ crtc_mode_info->refresh_rate = 60.0; ++ ++ mode_name = g_strdup_printf ("%dx%d", ++ crtc_mode_info->width, ++ crtc_mode_info->height); ++ mode = g_object_new (META_TYPE_CRTC_MODE, ++ "id", 0, ++ "name", mode_name, ++ "info", crtc_mode_info, ++ NULL); ++ ++ meta_gpu_take_modes (gpu, g_list_prepend (NULL, mode)); ++ ++ crtc = g_object_new (META_TYPE_CRTC_XRANDR, ++ "id", 0, ++ "gpu", gpu, ++ NULL); ++ meta_crtc_set_config (crtc, ++ &(graphene_rect_t) { ++ .size = { ++ .width = crtc_mode_info->width, ++ .height = crtc_mode_info->width, ++ }, ++ }, ++ mode, ++ META_MONITOR_TRANSFORM_NORMAL); ++ ++ meta_gpu_take_crtcs (gpu, g_list_prepend (NULL, crtc)); ++ ++ output_info = meta_output_info_new (); ++ output_info->name = g_strdup ("X11 Screen"); ++ output_info->vendor = g_strdup ("unknown"); ++ output_info->product = g_strdup ("unknown"); ++ output_info->serial = g_strdup ("unknown"); ++ output_info->hotplug_mode_update = TRUE; ++ output_info->suggested_x = -1; ++ output_info->suggested_y = -1; ++ output_info->connector_type = META_CONNECTOR_TYPE_Unknown; ++ output_info->modes = g_new0 (MetaCrtcMode *, 1); ++ output_info->modes[0] = mode; ++ output_info->n_modes = 1; ++ output_info->preferred_mode = mode; ++ output_info->possible_crtcs = g_new0 (MetaCrtc *, 1); ++ output_info->possible_crtcs[0] = crtc; ++ output_info->n_possible_crtcs = 1; ++ ++ output = g_object_new (META_TYPE_OUTPUT_XRANDR, ++ "id", (uint64_t) 0, ++ "gpu", gpu, ++ "info", output_info, ++ NULL); ++ ++ output_assignment = (MetaOutputAssignment) { ++ .output = output, ++ .is_primary = TRUE, ++ }; ++ meta_output_assign_crtc (output, crtc, &output_assignment); ++ meta_gpu_take_outputs (gpu, g_list_prepend (NULL, output)); ++ ++ return TRUE; ++} ++ + static gboolean + meta_gpu_xrandr_read_current (MetaGpu *gpu, + GError **error) +@@ -142,6 +225,9 @@ meta_gpu_xrandr_read_current (MetaGpu *gpu, + GList *modes = NULL; + GList *crtcs = NULL; + ++ if (!meta_monitor_manager_xrandr_has_randr (monitor_manager_xrandr)) ++ return read_current_fallback (gpu_xrandr, monitor_manager_xrandr); ++ + if (gpu_xrandr->resources) + XRRFreeScreenResources (gpu_xrandr->resources); + gpu_xrandr->resources = NULL; +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c +index 1b35545a09..98eb080b6b 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.c ++++ b/src/backends/x11/meta-monitor-manager-xrandr.c +@@ -76,6 +76,7 @@ struct _MetaMonitorManagerXrandr + guint logind_watch_id; + guint logind_signal_sub_id; + ++ gboolean has_randr; + gboolean has_randr15; + + xcb_timestamp_t last_xrandr_set_timestamp; +@@ -108,6 +109,12 @@ meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xran + return manager_xrandr->xdisplay; + } + ++gboolean ++meta_monitor_manager_xrandr_has_randr (MetaMonitorManagerXrandr *manager_xrandr) ++{ ++ return manager_xrandr->has_randr; ++} ++ + gboolean + meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr) + { +@@ -139,7 +146,7 @@ x11_dpms_state_to_power_save (CARD16 dpms_state) + } + } + +-static void ++void + meta_monitor_manager_xrandr_update_dpms_state (MetaMonitorManagerXrandr *manager_xrandr) + { + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); +@@ -615,9 +622,18 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *mana + MetaMonitorsConfigMethod method, + GError **error) + { ++ MetaMonitorManagerXrandr *manager_xrandr = ++ META_MONITOR_MANAGER_XRANDR (manager); + GPtrArray *crtc_assignments; + GPtrArray *output_assignments; + ++ if (!manager_xrandr->has_randr) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Tried to change configuration without XRANDR support"); ++ return FALSE; ++ } ++ + if (!config) + { + if (!manager->in_init) +@@ -1097,11 +1113,15 @@ meta_monitor_manager_xrandr_constructed (GObject *object) + &manager_xrandr->rr_event_base, + &manager_xrandr->rr_error_base)) + { ++ g_warning ("No RANDR support, monitor configuration disabled"); + return; + } + else + { + int major_version, minor_version; ++ ++ manager_xrandr->has_randr = TRUE; ++ + /* We only use ScreenChangeNotify, but GDK uses the others, + and we don't want to step on its toes */ + XRRSelectInput (manager_xrandr->xdisplay, +diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h +index d55b3d2b88..dc75134a56 100644 +--- a/src/backends/x11/meta-monitor-manager-xrandr.h ++++ b/src/backends/x11/meta-monitor-manager-xrandr.h +@@ -33,9 +33,13 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr, + + Display * meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr); + ++gboolean meta_monitor_manager_xrandr_has_randr (MetaMonitorManagerXrandr *manager_xrandr); ++ + gboolean meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr); + + gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager, + XEvent *event); + ++void meta_monitor_manager_xrandr_update_dpms_state (MetaMonitorManagerXrandr *manager_xrandr); ++ + #endif /* META_MONITOR_MANAGER_XRANDR_H */ +-- +2.31.1 +