fdf2dbc
From 7d2dd5dee5873fd817c010e73535701e1d647b27 Mon Sep 17 00:00:00 2001
fdf2dbc
From: Hans de Goede <hdegoede@redhat.com>
fdf2dbc
Date: Tue, 3 Sep 2019 16:18:00 +0200
fdf2dbc
Subject: [PATCH 2/2] window-xwayland: Add Xwayland fullscreen games workaround
fdf2dbc
fdf2dbc
This is a workaround for X11 games which use randr to change the resolution
fdf2dbc
in combination with NET_WM_STATE_FULLSCREEN when going fullscreen.
fdf2dbc
fdf2dbc
Newer versions of Xwayland support the randr part of this by supporting randr
fdf2dbc
resolution change emulation in combination with using WPviewport to scale the
fdf2dbc
app's window (at the emulated resolution) to fill the entire monitor.
fdf2dbc
fdf2dbc
Apps using randr in combination with NET_WM_STATE_FULLSCREEN expect the
fdf2dbc
fullscreen window to have the size of the emulated randr resolution since
fdf2dbc
when running on regular Xorg the resolution will actually be changed and
fdf2dbc
after that going fullscreen through NET_WM_STATE_FULLSCREEN will size
fdf2dbc
the window to be equal to the new resolution.
fdf2dbc
fdf2dbc
We need to emulate this behavior for these games to work correctly.
fdf2dbc
fdf2dbc
Xwayland's emulated resolution is a per X11 client setting and Xwayland
fdf2dbc
will set a special _XWAYLAND_RANDR_EMU_MONITOR_RECTS property on the
fdf2dbc
toplevel windows of a client (and only those of that client), which has
fdf2dbc
changed the (emulated) resolution through a randr call.
fdf2dbc
fdf2dbc
This commit checks for that property and if it is set adjusts the fullscreen
fdf2dbc
monitor rect for this window to match the emulated resolution.
fdf2dbc
fdf2dbc
Here is a step-by-step of such an app going fullscreen:
fdf2dbc
1. App changes monitor resolution with randr.
fdf2dbc
2. Xwayland sets the _XWAYLAND_RANDR_EMU_MONITOR_RECTS property on all the
fdf2dbc
   apps current and future windows. This property contains the origin of the
fdf2dbc
   monitor for which the emulated resolution is set and the emulated
fdf2dbc
   resolution.
fdf2dbc
3. App sets _NET_WM_FULLSCREEN.
fdf2dbc
4. We check the property and adjust the app's fullscreen size to match
fdf2dbc
   the emulated resolution.
fdf2dbc
5. Xwayland sees a Window at monitor origin fully covering the emulated
fdf2dbc
   monitor resolution. Xwayland sets a viewport making the emulated
fdf2dbc
   resolution sized window cover the full actual monitor resolution.
fdf2dbc
fdf2dbc
https://gitlab.gnome.org/GNOME/mutter/merge_requests/739
fdf2dbc
---
fdf2dbc
 src/wayland/meta-window-xwayland.c | 89 ++++++++++++++++++++++++++++++
fdf2dbc
 src/x11/atomnames.h                |  1 +
fdf2dbc
 2 files changed, 90 insertions(+)
fdf2dbc
fdf2dbc
diff --git a/src/wayland/meta-window-xwayland.c b/src/wayland/meta-window-xwayland.c
fdf2dbc
index 6f073893a..9967f439a 100644
fdf2dbc
--- a/src/wayland/meta-window-xwayland.c
fdf2dbc
+++ b/src/wayland/meta-window-xwayland.c
fdf2dbc
@@ -20,6 +20,7 @@
fdf2dbc
 
fdf2dbc
 #include "x11/window-x11.h"
fdf2dbc
 #include "x11/window-x11-private.h"
fdf2dbc
+#include "x11/xprops.h"
fdf2dbc
 #include "wayland/meta-window-xwayland.h"
fdf2dbc
 #include "wayland/meta-wayland.h"
fdf2dbc
 
fdf2dbc
@@ -53,6 +54,93 @@ meta_window_xwayland_init (MetaWindowXwayland *window_xwayland)
fdf2dbc
 {
fdf2dbc
 }
fdf2dbc
 
fdf2dbc
+/**
fdf2dbc
+ * meta_window_xwayland_adjust_fullscreen_monitor_rect:
fdf2dbc
+ *
fdf2dbc
+ * This function implements a workaround for X11 apps which use randr to change the
fdf2dbc
+ * the monitor resolution, followed by setting _NET_WM_FULLSCREEN to make the
fdf2dbc
+ * window-manager fullscreen them.
fdf2dbc
+ *
fdf2dbc
+ * Newer versions of Xwayland support the randr part of this by supporting randr
fdf2dbc
+ * resolution change emulation in combination with using WPviewport to scale the
fdf2dbc
+ * app's window (at the emulated resolution) to fill the entire monitor.
fdf2dbc
+ *
fdf2dbc
+ * Apps using randr in combination with NET_WM_STATE_FULLSCREEN expect the
fdf2dbc
+ * fullscreen window to have the size of the emulated randr resolution since
fdf2dbc
+ * when running on regular Xorg the resolution will actually be changed and
fdf2dbc
+ * after that going fullscreen through NET_WM_STATE_FULLSCREEN will size
fdf2dbc
+ * the window to be equal to the new resolution.
fdf2dbc
+ *
fdf2dbc
+ * We need to emulate this behavior for these apps to work correctly.
fdf2dbc
+ *
fdf2dbc
+ * Xwayland's emulated resolution is a per X11 client setting and Xwayland
fdf2dbc
+ * will set a special _XWAYLAND_RANDR_EMU_MONITOR_RECTS property on the
fdf2dbc
+ * toplevel windows of a client (and only those of that client), which has
fdf2dbc
+ * changed the (emulated) resolution through a randr call.
fdf2dbc
+ *
fdf2dbc
+ * Here we check for that property and if it is set we adjust the fullscreen
fdf2dbc
+ * monitor rect for this window to match the emulated resolution.
fdf2dbc
+ *
fdf2dbc
+ * Here is a step-by-step of such an app going fullscreen:
fdf2dbc
+ * 1. App changes monitor resolution with randr.
fdf2dbc
+ * 2. Xwayland sets the _XWAYLAND_RANDR_EMU_MONITOR_RECTS property on all the
fdf2dbc
+ *    apps current and future windows. This property contains the origin of the
fdf2dbc
+ *    monitor for which the emulated resolution is set and the emulated
fdf2dbc
+ *    resolution.
fdf2dbc
+ * 3. App sets _NET_WM_FULLSCREEN.
fdf2dbc
+ * 4. We check the property and adjust the app's fullscreen size to match
fdf2dbc
+ *    the emulated resolution.
fdf2dbc
+ * 5. Xwayland sees a Window at monitor origin fully covering the emulated
fdf2dbc
+ *    monitor resolution. Xwayland sets a viewport making the emulated
fdf2dbc
+ *    resolution sized window cover the full actual monitor resolution.
fdf2dbc
+ */
fdf2dbc
+static void
fdf2dbc
+meta_window_xwayland_adjust_fullscreen_monitor_rect (MetaWindow    *window,
fdf2dbc
+                                                     MetaRectangle *fs_monitor_rect)
fdf2dbc
+{
fdf2dbc
+  MetaX11Display *x11_display = window->display->x11_display;
fdf2dbc
+  MetaRectangle win_monitor_rect;
fdf2dbc
+  cairo_rectangle_int_t *rects;
fdf2dbc
+  uint32_t *list = NULL;
fdf2dbc
+  int i, n_items = 0;
fdf2dbc
+
fdf2dbc
+  if (!window->monitor)
fdf2dbc
+    {
fdf2dbc
+      g_warning ("MetaWindow does not have a monitor");
fdf2dbc
+      return;
fdf2dbc
+    }
fdf2dbc
+
fdf2dbc
+  win_monitor_rect = meta_logical_monitor_get_layout (window->monitor);
fdf2dbc
+
fdf2dbc
+  if (!meta_prop_get_cardinal_list (x11_display,
fdf2dbc
+                                    window->xwindow,
fdf2dbc
+                                    x11_display->atom__XWAYLAND_RANDR_EMU_MONITOR_RECTS,
fdf2dbc
+                                    &list, &n_items))
fdf2dbc
+    return;
fdf2dbc
+
fdf2dbc
+  if (n_items % 4)
fdf2dbc
+    {
fdf2dbc
+      meta_verbose ("_XWAYLAND_RANDR_EMU_MONITOR_RECTS on %s has %d values which is not a multiple of 4",
fdf2dbc
+                    window->desc, n_items);
fdf2dbc
+      g_free (list);
fdf2dbc
+      return;
fdf2dbc
+    }
fdf2dbc
+
fdf2dbc
+  rects = (cairo_rectangle_int_t *) list;
fdf2dbc
+  n_items = n_items / 4;
fdf2dbc
+  for (i = 0; i < n_items; i++)
fdf2dbc
+    {
fdf2dbc
+      if (rects[i].x == win_monitor_rect.x && rects[i].y == win_monitor_rect.y)
fdf2dbc
+        {
fdf2dbc
+          fs_monitor_rect->width = rects[i].width;
fdf2dbc
+          fs_monitor_rect->height = rects[i].height;
fdf2dbc
+          break;
fdf2dbc
+        }
fdf2dbc
+    }
fdf2dbc
+
fdf2dbc
+  g_free (list);
fdf2dbc
+}
fdf2dbc
+
fdf2dbc
 static void
fdf2dbc
 meta_window_xwayland_force_restore_shortcuts (MetaWindow         *window,
fdf2dbc
                                               ClutterInputDevice *source)
fdf2dbc
@@ -115,6 +203,7 @@ meta_window_xwayland_class_init (MetaWindowXwaylandClass *klass)
fdf2dbc
   MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
fdf2dbc
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
fdf2dbc
 
fdf2dbc
+  window_class->adjust_fullscreen_monitor_rect = meta_window_xwayland_adjust_fullscreen_monitor_rect;
fdf2dbc
   window_class->force_restore_shortcuts = meta_window_xwayland_force_restore_shortcuts;
fdf2dbc
   window_class->shortcuts_inhibited = meta_window_xwayland_shortcuts_inhibited;
fdf2dbc
 
fdf2dbc
diff --git a/src/x11/atomnames.h b/src/x11/atomnames.h
fdf2dbc
index b61f47ff4..4099d5d31 100644
fdf2dbc
--- a/src/x11/atomnames.h
fdf2dbc
+++ b/src/x11/atomnames.h
fdf2dbc
@@ -81,6 +81,7 @@ item(ATOM_PAIR)
fdf2dbc
 item(_XKB_RULES_NAMES)
fdf2dbc
 item(WL_SURFACE_ID)
fdf2dbc
 item(_XWAYLAND_MAY_GRAB_KEYBOARD)
fdf2dbc
+item(_XWAYLAND_RANDR_EMU_MONITOR_RECTS)
fdf2dbc
 
fdf2dbc
 /* Oddities: These are used, and we need atoms for them,
fdf2dbc
  * but when we need all _NET_WM hints (i.e. when we're making
fdf2dbc
-- 
fdf2dbc
2.23.0
fdf2dbc