[mutter/cherry-pick-4f544b63] xwayland: Set xrandr primary output




commit 00e247ed7af9d762186779024bec4c3c5b9439c7
Author: Aleksandr Mezin <mezin alexander gmail com>
Date:   Wed Nov 11 12:17:14 2020 +0000

    xwayland: Set xrandr primary output
    
    To find XWayland output that should be the primary one, iterate through all
    XWayland outputs, and compare their geometry to the geometry of the primary
    logical monitor.
    
    To avoid possible race conditions (Mutter's monitor configuration already
    updated, but Xrandr not yet), set the output both after Randr notifications and
    after 'monitors-changed' signal.
    
    https://gitlab.gnome.org/GNOME/mutter/-/issues/1407
    
    Signed-off-by: Aleksandr Mezin <mezin alexander gmail com>
    
    
    (cherry picked from commit 4f544b63626aa98a0e706c3862def62b41adb628)
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1638>

 src/wayland/meta-wayland-private.h  |   4 ++
 src/wayland/meta-xwayland-private.h |   3 +
 src/wayland/meta-xwayland.c         | 115 ++++++++++++++++++++++++++++++++++++
 src/x11/events.c                    |   2 +-
 4 files changed, 123 insertions(+), 1 deletion(-)
---
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index da0b56571d..82a256f60f 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -71,6 +71,10 @@ typedef struct
   GList *x11_windows;
 
   MetaXWaylandDnd *dnd;
+
+  gboolean has_xrandr;
+  int rr_event_base;
+  int rr_error_base;
 } MetaXWaylandManager;
 
 struct _MetaWaylandCompositor
diff --git a/src/wayland/meta-xwayland-private.h b/src/wayland/meta-xwayland-private.h
index 51dfa633b9..79bf45ade6 100644
--- a/src/wayland/meta-xwayland-private.h
+++ b/src/wayland/meta-xwayland-private.h
@@ -35,6 +35,9 @@ meta_xwayland_complete_init (MetaDisplay *display,
 void
 meta_xwayland_shutdown (MetaXWaylandManager *manager);
 
+gboolean
+meta_xwayland_handle_xevent (XEvent *event);
+
 /* wl_data_device/X11 selection interoperation */
 void     meta_xwayland_init_dnd         (Display *xdisplay);
 void     meta_xwayland_shutdown_dnd     (Display *xdisplay);
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
index fc184426ad..cd95d6886a 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -37,8 +37,10 @@
 #include <linux/random.h>
 #endif
 #include <unistd.h>
+#include <X11/extensions/Xrandr.h>
 #include <X11/Xauth.h>
 
+#include "backends/meta-monitor-manager-private.h"
 #include "backends/meta-settings-private.h"
 #include "core/main-private.h"
 #include "meta/main.h"
@@ -50,6 +52,9 @@ static int display_number_override = -1;
 
 static void meta_xwayland_stop_xserver (MetaXWaylandManager *manager);
 
+static void
+meta_xwayland_set_primary_output (Display *xdisplay);
+
 void
 meta_xwayland_associate_window_with_surface (MetaWindow          *window,
                                              MetaWaylandSurface  *surface)
@@ -833,17 +838,50 @@ meta_xwayland_init (MetaXWaylandManager *manager,
   return TRUE;
 }
 
+static void
+monitors_changed_cb (MetaMonitorManager *monitor_manager)
+{
+  MetaX11Display *x11_display = meta_get_display ()->x11_display;
+
+  meta_xwayland_set_primary_output (x11_display->xdisplay);
+}
+
 static void
 on_x11_display_closing (MetaDisplay *display)
 {
   Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
 
   meta_xwayland_shutdown_dnd (xdisplay);
+  g_signal_handlers_disconnect_by_func (meta_monitor_manager_get (),
+                                        monitors_changed_cb,
+                                        NULL);
   g_signal_handlers_disconnect_by_func (display,
                                         on_x11_display_closing,
                                         NULL);
 }
 
+static void
+meta_xwayland_init_xrandr (MetaXWaylandManager *manager,
+                           Display             *xdisplay)
+{
+  MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
+
+  manager->has_xrandr = XRRQueryExtension (xdisplay,
+                                           &manager->rr_event_base,
+                                           &manager->rr_error_base);
+
+  if (!manager->has_xrandr)
+    return;
+
+  XRRSelectInput (xdisplay, DefaultRootWindow (xdisplay),
+                  RRCrtcChangeNotifyMask | RROutputChangeNotifyMask);
+
+  g_signal_connect (monitor_manager, "monitors-changed",
+                    G_CALLBACK (monitors_changed_cb), NULL);
+
+  meta_xwayland_set_primary_output (xdisplay);
+}
+
 /* To be called right after connecting */
 void
 meta_xwayland_complete_init (MetaDisplay *display,
@@ -863,6 +901,7 @@ meta_xwayland_complete_init (MetaDisplay *display,
                     G_CALLBACK (on_x11_display_closing), NULL);
   meta_xwayland_init_dnd (xdisplay);
   add_local_user_to_xhost (xdisplay);
+  meta_xwayland_init_xrandr (manager, xdisplay);
 
   if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
     {
@@ -904,3 +943,79 @@ meta_xwayland_shutdown (MetaXWaylandManager *manager)
       g_clear_pointer (&manager->auth_file, g_free);
     }
 }
+
+static void
+meta_xwayland_set_primary_output (Display *xdisplay)
+{
+  XRRScreenResources *resources;
+  MetaMonitorManager *monitor_manager;
+  MetaLogicalMonitor *primary_monitor;
+  int i;
+
+  monitor_manager = meta_monitor_manager_get ();
+  primary_monitor =
+    meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
+
+  if (!primary_monitor)
+    return;
+
+  resources = XRRGetScreenResourcesCurrent (xdisplay,
+                                            DefaultRootWindow (xdisplay));
+  if (!resources)
+    return;
+
+  for (i = 0; i < resources->noutput; i++)
+    {
+      RROutput output_id = resources->outputs[i];
+      XRROutputInfo *xrandr_output;
+      XRRCrtcInfo *crtc_info = NULL;
+      MetaRectangle crtc_geometry;
+
+      xrandr_output = XRRGetOutputInfo (xdisplay, resources, output_id);
+      if (!xrandr_output)
+        continue;
+
+      if (xrandr_output->crtc)
+        crtc_info = XRRGetCrtcInfo (xdisplay, resources, xrandr_output->crtc);
+
+      XRRFreeOutputInfo (xrandr_output);
+
+      if (!crtc_info)
+        continue;
+
+      crtc_geometry.x = crtc_info->x;
+      crtc_geometry.y = crtc_info->y;
+      crtc_geometry.width = crtc_info->width;
+      crtc_geometry.height = crtc_info->height;
+
+      XRRFreeCrtcInfo (crtc_info);
+
+      if (meta_rectangle_equal (&crtc_geometry, &primary_monitor->rect))
+        {
+          XRRSetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay),
+                               output_id);
+          break;
+        }
+    }
+
+  XRRFreeScreenResources (resources);
+}
+
+gboolean
+meta_xwayland_handle_xevent (XEvent *event)
+{
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+  MetaXWaylandManager *manager = &compositor->xwayland_manager;
+
+  if (meta_xwayland_dnd_handle_event (event))
+    return TRUE;
+
+  if (manager->has_xrandr && event->type == manager->rr_event_base + RRNotify)
+    {
+      MetaX11Display *x11_display = meta_get_display ()->x11_display;
+      meta_xwayland_set_primary_output (x11_display->xdisplay);
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/src/x11/events.c b/src/x11/events.c
index 8c78b2ff1c..6d0e10a3f2 100644
--- a/src/x11/events.c
+++ b/src/x11/events.c
@@ -1793,7 +1793,7 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
 
 #ifdef HAVE_WAYLAND
   if (meta_is_wayland_compositor () &&
-      meta_xwayland_dnd_handle_event (event))
+      meta_xwayland_handle_xevent (event))
     {
       bypass_gtk = bypass_compositor = TRUE;
       goto out;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]