[mutter] xwayland: Set xrandr primary output



commit 4f544b63626aa98a0e706c3862def62b41adb628
Author: Aleksandr Mezin <mezin alexander gmail com>
Date:   Wed Nov 11 18:17:14 2020 +0600

    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>
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1558>

 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 074644ebb5..679e31804c 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -67,6 +67,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 fa5461c3e3..bba0934bdf 100644
--- a/src/wayland/meta-xwayland-private.h
+++ b/src/wayland/meta-xwayland-private.h
@@ -36,6 +36,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 99d0ef55dd..b9832a587e 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -39,8 +39,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"
@@ -52,6 +54,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)
@@ -871,17 +876,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,
@@ -904,6 +942,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)
     {
@@ -945,3 +984,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 ccd56afed4..efa8f9856b 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]