xserver: Branch 'master' - 13 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Oct 12 10:27:43 UTC 2019


 dix/dispatch.c                 |   23 ++
 hw/xwayland/.gitignore         |    2 
 hw/xwayland/Makefile.am        |    9 
 hw/xwayland/meson.build        |    3 
 hw/xwayland/xwayland-cursor.c  |   12 -
 hw/xwayland/xwayland-input.c   |    5 
 hw/xwayland/xwayland-output.c  |  388 ++++++++++++++++++++++++++++++++++++++++-
 hw/xwayland/xwayland-present.c |    6 
 hw/xwayland/xwayland-vidmode.c |  243 ++++++++++++++++---------
 hw/xwayland/xwayland.c         |  302 +++++++++++++++++++++++++++++++
 hw/xwayland/xwayland.h         |   46 ++++
 include/dix.h                  |    1 
 12 files changed, 930 insertions(+), 110 deletions(-)

New commits:
commit 5315f988d9f175e4850f4259f691a68d95ce7ac2
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Sep 2 17:32:45 2019 +0200

    xwayland: Set _XWAYLAND_RANDR_EMU_MONITOR_RECTS property for resolution emulation
    
    Apps using randr to change the resolution when going fullscreen, in
    combination with _NET_WM_STATE_FULLSCREEN to tell the window-manager (WM)
    to make their window fullscreen, expect the WM to give the fullscreen window
    the size of the emulated resolution as would happen when run under Xorg (*).
    
    We need the WM to emulate this behavior for these apps to work correctly,
    with Xwaylands resolution change emulation. For the WM to emulate this,
    it needs to know about the emulated resolution for the Windows owning
    client for each monitor.
    
    This commit adds a _XWAYLAND_RANDR_EMU_MONITOR_RECTS property, which
    contains 4 Cardinals (32 bit integers) per monitor with resolution
    emulation info. Window-managers can use this to get the emulated
    resolution for the client and size the window correctly.
    
    *) Since under Xorg the resolution will actually be changed and after that
    going fullscreen through NET_WM_STATE_FULLSCREEN will size the window to
    be equal to the new resolution.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 8df8330eb..42b96e821 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -29,6 +29,7 @@
 
 #include "xwayland.h"
 #include <randrstr.h>
+#include <X11/Xatom.h>
 
 #define DEFAULT_DPI 96
 #define ALL_ROTATIONS (RR_Rotate_0   | \
@@ -428,6 +429,80 @@ xwl_output_find_mode(struct xwl_output *xwl_output,
     return NULL;
 }
 
+struct xwl_output_randr_emu_prop {
+    Atom atom;
+    uint32_t rects[XWL_CLIENT_MAX_EMULATED_MODES][4];
+    int rect_count;
+};
+
+static void
+xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client,
+                          struct xwl_output_randr_emu_prop *prop)
+{
+    static const char atom_name[] = "_XWAYLAND_RANDR_EMU_MONITOR_RECTS";
+    struct xwl_emulated_mode *emulated_mode;
+    struct xwl_output *xwl_output;
+    int index = 0;
+
+    prop->atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
+
+    xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) {
+        emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
+        if (!emulated_mode)
+            continue;
+
+        prop->rects[index][0] = xwl_output->x;
+        prop->rects[index][1] = xwl_output->y;
+        prop->rects[index][2] = emulated_mode->width;
+        prop->rects[index][3] = emulated_mode->height;
+        index++;
+    }
+
+    prop->rect_count = index;
+}
+
+static void
+xwl_output_set_randr_emu_prop(WindowPtr window,
+                              struct xwl_output_randr_emu_prop *prop)
+{
+    if (!xwl_window_is_toplevel(window))
+        return;
+
+    if (prop->rect_count) {
+        dixChangeWindowProperty(serverClient, window, prop->atom,
+                                XA_CARDINAL, 32, PropModeReplace,
+                                prop->rect_count * 4, prop->rects, TRUE);
+    } else {
+        DeleteProperty(serverClient, window, prop->atom);
+    }
+}
+
+static void
+xwl_output_set_randr_emu_prop_callback(void *resource, XID id, void *user_data)
+{
+    xwl_output_set_randr_emu_prop(resource, user_data);
+}
+
+static void
+xwl_output_set_randr_emu_props(struct xwl_screen *xwl_screen, ClientPtr client)
+{
+    struct xwl_output_randr_emu_prop prop = {};
+
+    xwl_output_randr_emu_prop(xwl_screen, client, &prop);
+    FindClientResourcesByType(client, RT_WINDOW,
+                              xwl_output_set_randr_emu_prop_callback, &prop);
+}
+
+void
+xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
+                                      WindowPtr window)
+{
+    struct xwl_output_randr_emu_prop prop = {};
+
+    xwl_output_randr_emu_prop(xwl_screen, wClient(window), &prop);
+    xwl_output_set_randr_emu_prop(window, &prop);
+}
+
 void
 xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
                              RRModePtr mode, Bool from_vidmode)
@@ -442,6 +517,8 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
         xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode);
 
     xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen);
+
+    xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
 }
 
 static void
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 6c4bbb2c7..97afce0b8 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -720,6 +720,27 @@ xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen)
         xwl_window_check_resolution_change_emulation(xwl_window);
 }
 
+/* This checks if the passed in Window is a toplevel client window, note this
+ * returns false for window-manager decoration windows and returns true for
+ * the actual client top-level window even if it has been reparented to
+ * a window-manager decoration window.
+ */
+Bool
+xwl_window_is_toplevel(WindowPtr window)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
+
+    if (xwl_screen_client_is_window_manager(xwl_screen, wClient(window)))
+        return FALSE;
+
+    /* CSD and override-redirect toplevel windows */
+    if (window_get_damage(window))
+        return TRUE;
+
+    /* Normal toplevel client windows, reparented to decoration window */
+    return (window->parent && window_get_damage(window->parent));
+}
+
 static void
 xwl_window_init_allow_commits(struct xwl_window *xwl_window)
 {
@@ -881,6 +902,8 @@ xwl_realize_window(WindowPtr window)
             return FALSE;
     }
 
+    xwl_output_set_window_randr_emu_props(xwl_screen, window);
+
     return ensure_surface_for_window(window);
 }
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 6dbb108f1..74556bb34 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -414,6 +414,7 @@ Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen);
 struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen);
 void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen);
 Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window);
+Bool xwl_window_is_toplevel(WindowPtr window);
 
 void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool);
 void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
@@ -452,6 +453,8 @@ RRModePtr xwl_output_find_mode(struct xwl_output *xwl_output,
 void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
                                   ClientPtr client, RRModePtr mode,
                                   Bool from_vidmode);
+void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
+                                           WindowPtr window);
 
 RRModePtr xwayland_cvt(int HDisplay, int VDisplay,
                        float VRefresh, Bool Reduced, Bool Interlaced);
commit 0c305dbff8a44f3fa3d6aefd372a967029a7a527
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Aug 26 12:26:34 2019 +0200

    xwayland: xwl_window_should_enable_viewport: Add extra test
    
    Games based on the allegro gaming library or on ClanLib-1.0 do not size
    their window to match the fullscreen resolution, instead they use a
    window covering the entire screen, drawing only the fullscreen resolution
    part of it.
    
    This commit adds a check for these games, so that we correctly apply a
    viewport to them making fullscreen work properly for these games under
    Xwayland.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 6ee440bee..6c4bbb2c7 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -679,6 +679,23 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
         }
     }
 
+    /* 2. Test if the window uses override-redirect + vidmode
+     * and matches (fully covers) the entire screen.
+     * This path gets hit by: allegro4, ClanLib-1.0.
+     */
+    xwl_output = xwl_screen_get_first_output(xwl_screen);
+    emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
+    if (xwl_output && xwl_window->window->overrideRedirect &&
+        emulated_mode && emulated_mode->from_vidmode &&
+        xwl_window->x == 0 && xwl_window->y == 0 &&
+        xwl_window->width  == xwl_screen->width &&
+        xwl_window->height == xwl_screen->height) {
+
+        *emulated_mode_ret = emulated_mode;
+        *xwl_output_ret = xwl_output;
+        return TRUE;
+    }
+
     return FALSE;
 }
 
commit 38de6260816674b5430144cc38a8a27d93d1bf19
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jul 9 09:31:13 2019 +0200

    xwayland: Add vidmode mode changing emulation support
    
    Add support for fake mode changes using viewport, for apps which want to
    change the resolution when going fullscreen.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-vidmode.c b/hw/xwayland/xwayland-vidmode.c
index e9aea7269..56aac693a 100644
--- a/hw/xwayland/xwayland-vidmode.c
+++ b/hw/xwayland/xwayland-vidmode.c
@@ -106,26 +106,25 @@ xwlRRModeToDisplayMode(RRModePtr rrmode, DisplayModePtr mode)
 static RRModePtr
 xwlVidModeGetRRMode(ScreenPtr pScreen, int32_t width, int32_t height)
 {
-    RROutputPtr output = RRFirstOutput(pScreen);
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
 
-    if (output == NULL)
+    if (!xwl_output)
         return NULL;
 
-    return xwl_output_find_mode(output->devPrivate, width, height);
+    return xwl_output_find_mode(xwl_output, width, height);
 }
 
 static RRModePtr
 xwlVidModeGetCurrentRRMode(ScreenPtr pScreen)
 {
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
     struct xwl_emulated_mode *emulated_mode;
-    struct xwl_output *xwl_output;
-    RROutputPtr output;
 
-    output = RRFirstOutput(pScreen);
-    if (output == NULL)
+    if (!xwl_output)
         return NULL;
 
-    xwl_output = output->devPrivate;
     emulated_mode =
         xwl_output_get_emulated_mode_for_client(xwl_output, GetCurrentClient());
 
@@ -199,39 +198,79 @@ xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx)
 static int
 xwlVidModeGetDotClock(ScreenPtr pScreen, int Clock)
 {
-    RRModePtr rrmode;
-
-    rrmode = xwlVidModeGetCurrentRRMode(pScreen);
-    if (rrmode == NULL)
-        return 0;
-
-    return rrmode->mode.dotClock / 1000.0;
+    return Clock;
 }
 
 static int
 xwlVidModeGetNumOfClocks(ScreenPtr pScreen, Bool *progClock)
 {
-    return 1;
+    /* We emulate a programmable clock, rather then a fixed set of clocks */
+    *progClock = TRUE;
+    return 0;
 }
 
 static Bool
 xwlVidModeGetClocks(ScreenPtr pScreen, int *Clocks)
 {
-    *Clocks = xwlVidModeGetDotClock(pScreen, 0);
-
-    return TRUE;
+    return FALSE; /* Programmable clock, no clock list */
 }
 
+/* GetFirstModeline and GetNextModeline are used from Xext/vidmode.c like this:
+ *  if (pVidMode->GetFirstModeline(pScreen, &mode, &dotClock)) {
+ *      do {
+ *          ...
+ *          if (...)
+ *              break;
+ *      } while (pVidMode->GetNextModeline(pScreen, &mode, &dotClock));
+ *  }
+ * IOW our caller basically always loops over all the modes. There never is a
+ * return to the mainloop between GetFirstModeline and NextModeline calls where
+ * other parts of the server may change our state so we do not need to worry
+ * about xwl_output->randr_output->modes changing underneath us.
+ * Thus we can simply implement these two callbacks by storing the enumeration
+ * index in pVidMode->Next.
+ */
+
 static Bool
 xwlVidModeGetNextModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock)
 {
-    return FALSE;
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
+    VidModePtr pVidMode;
+    DisplayModePtr pMod;
+    intptr_t index;
+
+    pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey);
+    pVidMode = VidModeGetPtr(pScreen);
+    if (xwl_output == NULL || pMod == NULL || pVidMode == NULL)
+        return FALSE;
+
+    index = (intptr_t)pVidMode->Next;
+    if (index >= xwl_output->randr_output->numModes)
+        return FALSE;
+    xwlRRModeToDisplayMode(xwl_output->randr_output->modes[index], pMod);
+    index++;
+    pVidMode->Next = (void *)index;
+
+    *mode = pMod;
+    if (dotClock != NULL)
+        *dotClock = pMod->Clock;
+
+    return TRUE;
 }
 
 static Bool
 xwlVidModeGetFirstModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock)
 {
-    return xwlVidModeGetCurrentModeline(pScreen, mode, dotClock);
+    VidModePtr pVidMode;
+    intptr_t index = 0;
+
+    pVidMode = VidModeGetPtr(pScreen);
+    if (pVidMode == NULL)
+        return FALSE;
+
+    pVidMode->Next = (void *)index; /* 0 */
+    return xwlVidModeGetNextModeline(pScreen, mode, dotClock);
 }
 
 static Bool
@@ -251,37 +290,27 @@ xwlVidModeZoomViewport(ScreenPtr pScreen, int zoom)
 static Bool
 xwlVidModeSetViewPort(ScreenPtr pScreen, int x, int y)
 {
-    RROutputPtr output;
-    RRCrtcPtr crtc;
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
 
-    output = RRFirstOutput(pScreen);
-    if (output == NULL)
-        return FALSE;
-
-    crtc = output->crtc;
-    if (crtc == NULL)
+    if (!xwl_output)
         return FALSE;
 
     /* Support only default viewport */
-    return (x == crtc->x && y == crtc->y);
+    return (x == xwl_output->x && y == xwl_output->y);
 }
 
 static Bool
 xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y)
 {
-    RROutputPtr output;
-    RRCrtcPtr crtc;
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
 
-    output = RRFirstOutput(pScreen);
-    if (output == NULL)
+    if (!xwl_output)
         return FALSE;
 
-    crtc = output->crtc;
-    if (crtc == NULL)
-        return FALSE;
-
-    *x = crtc->x;
-    *y = crtc->y;
+    *x = xwl_output->x;
+    *y = xwl_output->y;
 
     return TRUE;
 }
@@ -289,8 +318,19 @@ xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y)
 static Bool
 xwlVidModeSwitchMode(ScreenPtr pScreen, DisplayModePtr mode)
 {
-    /* Unsupported for now */
-    return FALSE;
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
+    RRModePtr rrmode;
+
+    if (!xwl_output)
+        return FALSE;
+
+    rrmode = xwl_output_find_mode(xwl_output, mode->HDisplay, mode->VDisplay);
+    if (rrmode == NULL)
+        return FALSE;
+
+    xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), rrmode, TRUE);
+    return TRUE;
 }
 
 static Bool
@@ -344,8 +384,10 @@ xwlVidModeAddModeline(ScreenPtr pScreen, DisplayModePtr mode)
 static int
 xwlVidModeGetNumOfModes(ScreenPtr pScreen)
 {
-    /* We have only one mode */
-    return 1;
+    struct xwl_screen *xwl_screen = xwl_screen_get(pScreen);
+    struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen);
+
+    return xwl_output ? xwl_output->randr_output->numModes : 0;
 }
 
 static Bool
commit bcad1b813a04b9f3ff225f57a4baad09bd6315b9
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Jul 8 18:35:27 2019 +0200

    xwayland: Add xwlVidModeGetCurrentRRMode helper to the vidmode code
    
    crtc->mode reflects the mode set through the xrandr extension, once we
    add support for also changing the mode through the vidmode extension this
    will no longer correctly reflect the emulated resolution.
    
    Add a new xwlVidModeGetCurrentRRMode helper which determines the mode by
    looking at the emulated_mode instead.
    
    Likewise add a xwlVidModeGetRRMode helper and use that in
    xwlVidModeCheckModeForMonitor/xwlVidModeCheckModeForDriver to allow any
    mode listed in the randr_output's mode list.
    
    This is a preparation patch for adding emulated mode/resolution change
    support to Xwayland's XF86 vidmode extension emulation.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-vidmode.c b/hw/xwayland/xwayland-vidmode.c
index a59c9f6a9..e9aea7269 100644
--- a/hw/xwayland/xwayland-vidmode.c
+++ b/hw/xwayland/xwayland-vidmode.c
@@ -103,26 +103,56 @@ xwlRRModeToDisplayMode(RRModePtr rrmode, DisplayModePtr mode)
     mode->HSync = mode_hsync(mode_info);
 }
 
+static RRModePtr
+xwlVidModeGetRRMode(ScreenPtr pScreen, int32_t width, int32_t height)
+{
+    RROutputPtr output = RRFirstOutput(pScreen);
+
+    if (output == NULL)
+        return NULL;
+
+    return xwl_output_find_mode(output->devPrivate, width, height);
+}
+
+static RRModePtr
+xwlVidModeGetCurrentRRMode(ScreenPtr pScreen)
+{
+    struct xwl_emulated_mode *emulated_mode;
+    struct xwl_output *xwl_output;
+    RROutputPtr output;
+
+    output = RRFirstOutput(pScreen);
+    if (output == NULL)
+        return NULL;
+
+    xwl_output = output->devPrivate;
+    emulated_mode =
+        xwl_output_get_emulated_mode_for_client(xwl_output, GetCurrentClient());
+
+    if (emulated_mode) {
+        return xwl_output_find_mode(xwl_output,
+                                    emulated_mode->width,
+                                    emulated_mode->height);
+    } else {
+        return xwl_output_find_mode(xwl_output, -1, -1);
+    }
+}
+
 static Bool
 xwlVidModeGetCurrentModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock)
 {
     DisplayModePtr pMod;
-    RROutputPtr output;
-    RRCrtcPtr crtc;
+    RRModePtr rrmode;
 
     pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey);
     if (pMod == NULL)
         return FALSE;
 
-    output = RRFirstOutput(pScreen);
-    if (output == NULL)
-        return FALSE;
-
-    crtc = output->crtc;
-    if (crtc == NULL)
+    rrmode = xwlVidModeGetCurrentRRMode(pScreen);
+    if (rrmode == NULL)
         return FALSE;
 
-    xwlRRModeToDisplayMode(crtc->mode, pMod);
+    xwlRRModeToDisplayMode(rrmode, pMod);
 
     *mode = pMod;
     if (dotClock != NULL)
@@ -135,9 +165,10 @@ static vidMonitorValue
 xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx)
 {
     vidMonitorValue ret = { NULL, };
-    DisplayModePtr pMod;
+    RRModePtr rrmode;
 
-    if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL))
+    rrmode = xwlVidModeGetCurrentRRMode(pScreen);
+    if (rrmode == NULL)
         return ret;
 
     switch (valtyp) {
@@ -155,11 +186,11 @@ xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx)
         break;
     case VIDMODE_MON_HSYNC_LO:
     case VIDMODE_MON_HSYNC_HI:
-        ret.f = 100.0 * pMod->HSync;
+        ret.f = mode_hsync(&rrmode->mode) * 100.0;
         break;
     case VIDMODE_MON_VREFRESH_LO:
     case VIDMODE_MON_VREFRESH_HI:
-        ret.f = 100.0 * pMod->VRefresh;
+        ret.f = mode_refresh(&rrmode->mode) * 100.0;
         break;
     }
     return ret;
@@ -168,13 +199,13 @@ xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx)
 static int
 xwlVidModeGetDotClock(ScreenPtr pScreen, int Clock)
 {
-    DisplayModePtr pMod;
+    RRModePtr rrmode;
 
-    if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL))
+    rrmode = xwlVidModeGetCurrentRRMode(pScreen);
+    if (rrmode == NULL)
         return 0;
 
-    return pMod->Clock;
-
+    return rrmode->mode.dotClock / 1000.0;
 }
 
 static int
@@ -272,14 +303,15 @@ xwlVidModeLockZoom(ScreenPtr pScreen, Bool lock)
 static ModeStatus
 xwlVidModeCheckModeForMonitor(ScreenPtr pScreen, DisplayModePtr mode)
 {
-    DisplayModePtr pMod;
+    RRModePtr rrmode;
 
-    /* This should not happen */
-    if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL))
+    rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay);
+    if (rrmode == NULL)
         return MODE_ERROR;
 
     /* Only support mode with the same HSync/VRefresh as we advertise */
-    if (mode->HSync == pMod->HSync && mode->VRefresh == pMod->VRefresh)
+    if (mode->HSync == mode_hsync(&rrmode->mode) &&
+        mode->VRefresh == mode_refresh(&rrmode->mode))
         return MODE_OK;
 
     /* All the rest is unsupported - If we want to succeed, return MODE_OK instead */
@@ -289,20 +321,10 @@ xwlVidModeCheckModeForMonitor(ScreenPtr pScreen, DisplayModePtr mode)
 static ModeStatus
 xwlVidModeCheckModeForDriver(ScreenPtr pScreen, DisplayModePtr mode)
 {
-    DisplayModePtr pMod;
-
-    /* This should not happen */
-    if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL))
-        return MODE_ERROR;
-
-    if (mode->HTotal != pMod->HTotal)
-        return MODE_BAD_HVALUE;
+    RRModePtr rrmode;
 
-    if (mode->VTotal != pMod->VTotal)
-        return MODE_BAD_VVALUE;
-
-    /* Unsupported for now, but pretend it works */
-    return MODE_OK;
+    rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay);
+    return rrmode ? MODE_OK : MODE_ERROR;
 }
 
 static void
commit 43c80078126f6f33c6ab7d3cf4668733bde03366
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Jul 8 14:00:27 2019 +0200

    xwayland: Add xwlRRModeToDisplayMode() helper function
    
    This is a preparation patch for adding emulated mode/resolution change
    support to Xwayland's XF86 vidmode extension emulation, using the
    Wayland viewport extension.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-vidmode.c b/hw/xwayland/xwayland-vidmode.c
index 0bcd11401..a59c9f6a9 100644
--- a/hw/xwayland/xwayland-vidmode.c
+++ b/hw/xwayland/xwayland-vidmode.c
@@ -78,13 +78,37 @@ mode_refresh(const xRRModeInfo *mode_info)
     return rate;
 }
 
+static void
+xwlRRModeToDisplayMode(RRModePtr rrmode, DisplayModePtr mode)
+{
+    const xRRModeInfo *mode_info = &rrmode->mode;
+
+    mode->next = mode;
+    mode->prev = mode;
+    mode->name = "";
+    mode->VScan = 1;
+    mode->Private = NULL;
+    mode->HDisplay = mode_info->width;
+    mode->HSyncStart = mode_info->hSyncStart;
+    mode->HSyncEnd = mode_info->hSyncEnd;
+    mode->HTotal = mode_info->hTotal;
+    mode->HSkew = mode_info->hSkew;
+    mode->VDisplay = mode_info->height;
+    mode->VSyncStart = mode_info->vSyncStart;
+    mode->VSyncEnd = mode_info->vSyncEnd;
+    mode->VTotal = mode_info->vTotal;
+    mode->Flags = mode_info->modeFlags;
+    mode->Clock = mode_info->dotClock / 1000.0;
+    mode->VRefresh = mode_refresh(mode_info); /* Or RRVerticalRefresh() */
+    mode->HSync = mode_hsync(mode_info);
+}
+
 static Bool
 xwlVidModeGetCurrentModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock)
 {
     DisplayModePtr pMod;
     RROutputPtr output;
     RRCrtcPtr crtc;
-    xRRModeInfo rrmode;
 
     pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey);
     if (pMod == NULL)
@@ -98,30 +122,11 @@ xwlVidModeGetCurrentModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotCl
     if (crtc == NULL)
         return FALSE;
 
-    rrmode = crtc->mode->mode;
-
-    pMod->next = pMod;
-    pMod->prev = pMod;
-    pMod->name = "";
-    pMod->VScan = 1;
-    pMod->Private = NULL;
-    pMod->HDisplay = rrmode.width;
-    pMod->HSyncStart = rrmode.hSyncStart;
-    pMod->HSyncEnd = rrmode.hSyncEnd;
-    pMod->HTotal = rrmode.hTotal;
-    pMod->HSkew = rrmode.hSkew;
-    pMod->VDisplay = rrmode.height;
-    pMod->VSyncStart = rrmode.vSyncStart;
-    pMod->VSyncEnd = rrmode.vSyncEnd;
-    pMod->VTotal = rrmode.vTotal;
-    pMod->Flags = rrmode.modeFlags;
-    pMod->Clock = rrmode.dotClock / 1000.0;
-    pMod->VRefresh = mode_refresh(&rrmode); /* Or RRVerticalRefresh() */
-    pMod->HSync = mode_hsync(&rrmode);
-    *mode = pMod;
+    xwlRRModeToDisplayMode(crtc->mode, pMod);
 
+    *mode = pMod;
     if (dotClock != NULL)
-        *dotClock = rrmode.dotClock / 1000.0;
+        *dotClock = pMod->Clock;
 
     return TRUE;
 }
commit d99b9ff0f237d15e7eb507484493c73b393d5dba
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jul 2 11:55:26 2019 +0200

    xwayland: Add support for randr-resolution change emulation using viewport
    
    Add support for per client randr-resolution change emulation using viewport,
    for apps which want to change the resolution when going fullscreen.
    
    Partly based on earlier work on this by Robert Mader <robert.mader at posteo.de>
    
    Note SDL2 and SFML do not restore randr resolution when going from
    fullscreen -> windowed, I believe this is caused by us still reporting the
    desktop resolution when they query the resolution.  This is not a problem
    because when windowed the toplevel window size includes the window-decorations
    so it never matches the emulated resolution.
    
    One exception would be the window being resizable in Windowed mode and the
    user resizing the window so that including decorations it matches the
    emulated resolution *and* the window being at pos 0x0. But this is an
    extreme corner case. Still I will submit patches upstream to SDL2
    and SFML to always restore the desktop resolution under Xwayland,
    disabling resolution emulation all together when going windowed.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 2c3482763..9c574314d 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -486,6 +486,11 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat)
             int dx = xwl_seat->focus_window->window->drawable.x;
             int dy = xwl_seat->focus_window->window->drawable.y;
 
+            if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) {
+                sx *= xwl_seat->focus_window->scale_x;
+                sy *= xwl_seat->focus_window->scale_y;
+            }
+
             x = dx + sx;
             y = dy + sy;
         } else {
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index f91e676c6..8df8330eb 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -408,6 +408,42 @@ err:
     FatalError("Failed to allocate memory for list of RR modes");
 }
 
+RRModePtr
+xwl_output_find_mode(struct xwl_output *xwl_output,
+                     int32_t width, int32_t height)
+{
+    RROutputPtr output = xwl_output->randr_output;
+    int i;
+
+    /* width & height -1 means we want the actual output mode, which is idx 0 */
+    if (width == -1 && height == -1 && output->modes)
+        return output->modes[0];
+
+    for (i = 0; i < output->numModes; i++) {
+        if (output->modes[i]->mode.width == width && output->modes[i]->mode.height == height)
+            return output->modes[i];
+    }
+
+    ErrorF("XWAYLAND: mode %dx%d is not available\n", width, height);
+    return NULL;
+}
+
+void
+xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
+                             RRModePtr mode, Bool from_vidmode)
+{
+    DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n",
+           from_vidmode ? "vidmode" : "randr",
+           mode->mode.width, mode->mode.height);
+
+    if (mode->mode.width == xwl_output->width && mode->mode.height == xwl_output->height)
+        xwl_output_remove_emulated_mode_for_client(xwl_output, client);
+    else
+        xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode);
+
+    xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen);
+}
+
 static void
 apply_output_change(struct xwl_output *xwl_output)
 {
@@ -666,21 +702,36 @@ xwl_randr_screen_set_size(ScreenPtr pScreen,
 static Bool
 xwl_randr_crtc_set(ScreenPtr pScreen,
                    RRCrtcPtr crtc,
-                   RRModePtr mode,
+                   RRModePtr new_mode,
                    int x,
                    int y,
                    Rotation rotation,
                    int numOutputs, RROutputPtr * outputs)
 {
     struct xwl_output *xwl_output = crtc->devPrivate;
+    RRModePtr mode;
 
-    if (!mode || (mode->mode.width  == xwl_output->width &&
-                  mode->mode.height == xwl_output->height)) {
-        RRCrtcChanged(crtc, TRUE);
-        return TRUE;
+    if (new_mode) {
+        mode = xwl_output_find_mode(xwl_output,
+                                    new_mode->mode.width,
+                                    new_mode->mode.height);
+    } else {
+        mode = xwl_output_find_mode(xwl_output, -1, -1);
     }
+    if (!mode)
+        return FALSE;
 
-    return FALSE;
+    xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), mode, FALSE);
+
+    /* A real randr implementation would call:
+     * RRCrtcNotify(xwl_output->randr_crtc, mode, xwl_output->x, xwl_output->y,
+     *              xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
+     * here to update the mode reported to clients querying the randr settings
+     * but that influences *all* clients and we do randr mode change emulation
+     * on a per client basis. So we just return success here.
+     */
+
+    return TRUE;
 }
 
 static Bool
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index e9677fcf1..6ee440bee 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -206,6 +206,23 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
     return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
 }
 
+/* Return the output @ 0x0, falling back to the first output in the list */
+struct xwl_output *
+xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
+{
+    struct xwl_output *xwl_output;
+
+    xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) {
+        if (xwl_output->x == 0 && xwl_output->y == 0)
+            return xwl_output;
+    }
+
+    if (xorg_list_is_empty(&xwl_screen->output_list))
+        return NULL;
+
+    return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link);
+}
+
 static void
 xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
                              const char *debug_msg)
@@ -542,6 +559,150 @@ xwl_pixmap_get(PixmapPtr pixmap)
     return dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
 }
 
+Bool
+xwl_window_has_viewport_enabled(struct xwl_window *xwl_window)
+{
+    return (xwl_window->viewport != NULL);
+}
+
+static void
+xwl_window_disable_viewport(struct xwl_window *xwl_window)
+{
+    assert (xwl_window->viewport);
+
+    DebugF("XWAYLAND: disabling viewport\n");
+    wp_viewport_destroy(xwl_window->viewport);
+    xwl_window->viewport = NULL;
+}
+
+static void
+xwl_window_enable_viewport(struct xwl_window *xwl_window,
+                           struct xwl_output *xwl_output,
+                           struct xwl_emulated_mode *emulated_mode)
+{
+    /* If necessary disable old viewport to apply new settings */
+    if (xwl_window_has_viewport_enabled(xwl_window))
+        xwl_window_disable_viewport(xwl_window);
+
+    DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n",
+           emulated_mode->width, emulated_mode->height,
+           xwl_output->width, xwl_output->height);
+
+    xwl_window->viewport =
+        wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter,
+                                   xwl_window->surface);
+
+    wp_viewport_set_source(xwl_window->viewport,
+                           wl_fixed_from_int(0),
+                           wl_fixed_from_int(0),
+                           wl_fixed_from_int(emulated_mode->width),
+                           wl_fixed_from_int(emulated_mode->height));
+    wp_viewport_set_destination(xwl_window->viewport,
+                                xwl_output->width,
+                                xwl_output->height);
+
+    xwl_window->scale_x = (float)emulated_mode->width  / xwl_output->width;
+    xwl_window->scale_y = (float)emulated_mode->height / xwl_output->height;
+}
+
+static Bool
+xwl_screen_client_is_window_manager(struct xwl_screen *xwl_screen,
+                                    ClientPtr client)
+{
+    WindowPtr root = xwl_screen->screen->root;
+    OtherClients *others;
+
+    for (others = wOtherClients(root); others; others = others->next) {
+        if (SameClient(others, client)) {
+            if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask))
+                return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static ClientPtr
+xwl_window_get_owner(struct xwl_window *xwl_window)
+{
+    WindowPtr window = xwl_window->window;
+    ClientPtr client = wClient(window);
+
+    /* If the toplevel window is owned by the window-manager, then the
+     * actual client toplevel window has been reparented to a window-manager
+     * decoration window. In that case return the client of the
+     * first *and only* child of the toplevel (decoration) window.
+     */
+    if (xwl_screen_client_is_window_manager(xwl_window->xwl_screen, client)) {
+        if (window->firstChild && window->firstChild == window->lastChild)
+            return wClient(window->firstChild);
+        else
+            return NULL; /* Should never happen, skip resolution emulation */
+    }
+
+    return client;
+}
+
+static Bool
+xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
+                                  struct xwl_output **xwl_output_ret,
+                                  struct xwl_emulated_mode **emulated_mode_ret)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_emulated_mode *emulated_mode;
+    struct xwl_output *xwl_output;
+    ClientPtr owner;
+
+    if (!xwl_screen_has_resolution_change_emulation(xwl_screen))
+        return FALSE;
+
+    owner = xwl_window_get_owner(xwl_window);
+    if (!owner)
+        return FALSE;
+
+    /* 1. Test if the window matches the emulated mode on one of the outputs
+     * This path gets hit by most games / libs (e.g. SDL, SFML, OGRE)
+     */
+    xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) {
+        emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner);
+        if (!emulated_mode)
+            continue;
+
+        if (xwl_window->x == xwl_output->x &&
+            xwl_window->y == xwl_output->y &&
+            xwl_window->width  == emulated_mode->width &&
+            xwl_window->height == emulated_mode->height) {
+
+            *emulated_mode_ret = emulated_mode;
+            *xwl_output_ret = xwl_output;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static void
+xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window)
+{
+    struct xwl_emulated_mode *emulated_mode;
+    struct xwl_output *xwl_output;
+
+    if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode))
+        xwl_window_enable_viewport(xwl_window, xwl_output, emulated_mode);
+    else if (xwl_window_has_viewport_enabled(xwl_window))
+        xwl_window_disable_viewport(xwl_window);
+}
+
+void
+xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen)
+{
+    struct xwl_window *xwl_window;
+
+    xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window)
+        xwl_window_check_resolution_change_emulation(xwl_window);
+}
+
 static void
 xwl_window_init_allow_commits(struct xwl_window *xwl_window)
 {
@@ -612,6 +773,8 @@ ensure_surface_for_window(WindowPtr window)
 
     xwl_window->xwl_screen = xwl_screen;
     xwl_window->window = window;
+    xwl_window->width = window->drawable.width;
+    xwl_window->height = window->drawable.height;
     xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor);
     if (xwl_window->surface == NULL) {
         ErrorF("wl_display_create_surface failed\n");
@@ -653,6 +816,7 @@ ensure_surface_for_window(WindowPtr window)
 
     dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window);
     xorg_list_init(&xwl_window->link_damage);
+    xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list);
 
     xwl_window_init_allow_commits(xwl_window);
 
@@ -747,8 +911,12 @@ xwl_unrealize_window(WindowPtr window)
     if (!xwl_window)
         return ret;
 
+    if (xwl_window_has_viewport_enabled(xwl_window))
+        xwl_window_disable_viewport(xwl_window);
+
     wl_surface_destroy(xwl_window->surface);
     xorg_list_del(&xwl_window->link_damage);
+    xorg_list_del(&xwl_window->link_window);
     unregister_damage(window);
 
     if (xwl_window->frame_callback)
@@ -781,6 +949,33 @@ xwl_set_window_pixmap(WindowPtr window,
 }
 
 static void
+xwl_resize_window(WindowPtr window,
+                  int x, int y,
+                  unsigned int width, unsigned int height,
+                  WindowPtr sib)
+{
+    ScreenPtr screen = window->drawable.pScreen;
+    struct xwl_screen *xwl_screen;
+    struct xwl_window *xwl_window;
+
+    xwl_screen = xwl_screen_get(screen);
+    xwl_window = xwl_window_get(window);
+
+    screen->ResizeWindow = xwl_screen->ResizeWindow;
+    (*screen->ResizeWindow) (window, x, y, width, height, sib);
+    xwl_screen->ResizeWindow = screen->ResizeWindow;
+    screen->ResizeWindow = xwl_resize_window;
+
+    if (xwl_window) {
+        xwl_window->x = x;
+        xwl_window->y = y;
+        xwl_window->width = width;
+        xwl_window->height = height;
+        xwl_window_check_resolution_change_emulation(xwl_window);
+    }
+}
+
+static void
 frame_callback(void *data,
                struct wl_callback *callback,
                uint32_t time)
@@ -1174,6 +1369,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xorg_list_init(&xwl_screen->output_list);
     xorg_list_init(&xwl_screen->seat_list);
     xorg_list_init(&xwl_screen->damage_window_list);
+    xorg_list_init(&xwl_screen->window_list);
     xwl_screen->depth = 24;
 
     xwl_screen->display = wl_display_connect(NULL);
@@ -1270,6 +1466,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     xwl_screen->CloseScreen = pScreen->CloseScreen;
     pScreen->CloseScreen = xwl_close_screen;
 
+    xwl_screen->ResizeWindow = pScreen->ResizeWindow;
+    pScreen->ResizeWindow = xwl_resize_window;
+
     if (xwl_screen->rootless) {
         xwl_screen->SetWindowPixmap = pScreen->SetWindowPixmap;
         pScreen->SetWindowPixmap = xwl_set_window_pixmap;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 5a2397cdc..6dbb108f1 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -132,10 +132,12 @@ struct xwl_screen {
     DestroyWindowProcPtr DestroyWindow;
     XYToWindowProcPtr XYToWindow;
     SetWindowPixmapProcPtr SetWindowPixmap;
+    ResizeWindowProcPtr ResizeWindow;
 
     struct xorg_list output_list;
     struct xorg_list seat_list;
     struct xorg_list damage_window_list;
+    struct xorg_list window_list;
 
     int wayland_fd;
     struct wl_display *display;
@@ -176,9 +178,13 @@ struct xwl_screen {
 struct xwl_window {
     struct xwl_screen *xwl_screen;
     struct wl_surface *surface;
+    struct wp_viewport *viewport;
+    int32_t x, y, width, height;
+    float scale_x, scale_y;
     struct wl_shell_surface *shell_surface;
     WindowPtr window;
     struct xorg_list link_damage;
+    struct xorg_list link_window;
     struct wl_callback *frame_callback;
     Bool allow_commits;
 #ifdef GLAMOR_HAS_GBM
@@ -405,6 +411,9 @@ Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);
 
 struct xwl_screen *xwl_screen_get(ScreenPtr screen);
 Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen);
+struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen);
+void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen);
+Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window);
 
 void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool);
 void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
@@ -438,6 +447,12 @@ void xwl_output_remove(struct xwl_output *xwl_output);
 struct xwl_emulated_mode *xwl_output_get_emulated_mode_for_client(
                             struct xwl_output *xwl_output, ClientPtr client);
 
+RRModePtr xwl_output_find_mode(struct xwl_output *xwl_output,
+                               int32_t width, int32_t height);
+void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
+                                  ClientPtr client, RRModePtr mode,
+                                  Bool from_vidmode);
+
 RRModePtr xwayland_cvt(int HDisplay, int VDisplay,
                        float VRefresh, Bool Reduced, Bool Interlaced);
 
commit aca0a588eb40a5e6669094a2ab7f71ca0ba06b16
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Thu Aug 29 23:04:36 2019 +0200

    xwayland: Add support for storing per client per output emulated resolution
    
    Add support for storing per output randr/vidmode emulated resolution
    into the per client data.
    
    Since we do not have a free/delete callback for the client this uses
    a simple static array. The entries are tied to a specific output by the
    server_output_id, with a server_output_id of 0 indicating a free slot
    (0 is the "None" Wayland object id).
    
    Note that even if we were to store this in a linked list, we would still
    need the server_output_id as this is *per client* *per output*.
    
    This is a preparation patch for adding randr/vidmode resolution
    change emulation.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index abbddddf9..f91e676c6 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -245,6 +245,73 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
     update_desktop_dimensions();
 }
 
+struct xwl_emulated_mode *
+xwl_output_get_emulated_mode_for_client(struct xwl_output *xwl_output,
+                                        ClientPtr client)
+{
+    struct xwl_client *xwl_client = xwl_client_get(client);
+    int i;
+
+    if (!xwl_output)
+        return NULL;
+
+    for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) {
+        if (xwl_client->emulated_modes[i].server_output_id ==
+            xwl_output->server_output_id)
+            return &xwl_client->emulated_modes[i];
+    }
+
+    return NULL;
+}
+
+static void
+xwl_output_add_emulated_mode_for_client(struct xwl_output *xwl_output,
+                                        ClientPtr client,
+                                        RRModePtr mode,
+                                        Bool from_vidmode)
+{
+    struct xwl_client *xwl_client = xwl_client_get(client);
+    struct xwl_emulated_mode *emulated_mode;
+    int i;
+
+    emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
+    if (!emulated_mode) {
+        /* Find a free spot in the emulated modes array */
+        for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) {
+            if (xwl_client->emulated_modes[i].server_output_id == 0) {
+                emulated_mode = &xwl_client->emulated_modes[i];
+                break;
+            }
+        }
+    }
+    if (!emulated_mode) {
+        static Bool warned;
+
+        if (!warned) {
+            ErrorF("Ran out of space for emulated-modes, not adding mode");
+            warned = TRUE;
+        }
+
+        return;
+    }
+
+    emulated_mode->server_output_id = xwl_output->server_output_id;
+    emulated_mode->width  = mode->mode.width;
+    emulated_mode->height = mode->mode.height;
+    emulated_mode->from_vidmode = from_vidmode;
+}
+
+static void
+xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output,
+                                           ClientPtr client)
+{
+    struct xwl_emulated_mode *emulated_mode;
+
+    emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
+    if (emulated_mode)
+        memset(emulated_mode, 0, sizeof(*emulated_mode));
+}
+
 /* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */
 const int32_t xwl_output_fake_modes[][2] = {
     /* 4:3 (1.33) */
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 9c7fb6691..5a2397cdc 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -377,7 +377,21 @@ struct xwl_output {
     Bool xdg_output_done;
 };
 
+/* Per client per output emulated randr/vidmode resolution info. */
+struct xwl_emulated_mode {
+    uint32_t server_output_id;
+    int32_t width;
+    int32_t height;
+    Bool from_vidmode;
+};
+
+/* Apps which use randr/vidmode to change the mode when going fullscreen,
+ * usually change the mode of only a single monitor, so this should be plenty.
+ */
+#define XWL_CLIENT_MAX_EMULATED_MODES 16
+
 struct xwl_client {
+    struct xwl_emulated_mode emulated_modes[XWL_CLIENT_MAX_EMULATED_MODES];
 };
 
 struct xwl_client *xwl_client_get(ClientPtr client);
@@ -421,6 +435,9 @@ void xwl_output_destroy(struct xwl_output *xwl_output);
 
 void xwl_output_remove(struct xwl_output *xwl_output);
 
+struct xwl_emulated_mode *xwl_output_get_emulated_mode_for_client(
+                            struct xwl_output *xwl_output, ClientPtr client);
+
 RRModePtr xwayland_cvt(int HDisplay, int VDisplay,
                        float VRefresh, Bool Reduced, Bool Interlaced);
 
commit 905cb8b9e27add5f49a45fe167a0005bf05218bc
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Thu Aug 29 22:45:12 2019 +0200

    xwayland: Add per client private data
    
    Add per client private data, which for now is empty.
    
    This is a preparation patch for adding randr/vidmode resolution
    change emulation.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 8e416fd9d..e9677fcf1 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -165,11 +165,18 @@ ddxProcessArgument(int argc, char *argv[], int i)
     return 0;
 }
 
+static DevPrivateKeyRec xwl_client_private_key;
 static DevPrivateKeyRec xwl_window_private_key;
 static DevPrivateKeyRec xwl_screen_private_key;
 static DevPrivateKeyRec xwl_pixmap_private_key;
 static DevPrivateKeyRec xwl_damage_private_key;
 
+struct xwl_client *
+xwl_client_get(ClientPtr client)
+{
+    return dixLookupPrivate(&client->devPrivates, &xwl_client_private_key);
+}
+
 static struct xwl_window *
 xwl_window_get(WindowPtr window)
 {
@@ -1121,6 +1128,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
         return FALSE;
     if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0))
         return FALSE;
+    /* There are no easy to use new / delete client hooks, we could use a
+     * ClientStateCallback, but it is easier to let the dix code manage the
+     * memory for us. This will zero fill the initial xwl_client data.
+     */
+    if (!dixRegisterPrivateKey(&xwl_client_private_key, PRIVATE_CLIENT,
+                               sizeof(struct xwl_client)))
+        return FALSE;
 
     dixSetPrivate(&pScreen->devPrivates, &xwl_screen_private_key, xwl_screen);
     xwl_screen->screen = pScreen;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index b0a1cf36a..9c7fb6691 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -377,6 +377,11 @@ struct xwl_output {
     Bool xdg_output_done;
 };
 
+struct xwl_client {
+};
+
+struct xwl_client *xwl_client_get(ClientPtr client);
+
 void xwl_sync_events (struct xwl_screen *xwl_screen);
 void xwl_surface_damage(struct xwl_screen *xwl_screen,
                         struct wl_surface *surface,
commit e89872f51aa834fa9d94a4ca4822f03b0341ab4f
Author: Robert Mader <robert.mader at posteo.de>
Date:   Mon Jan 22 17:57:38 2018 +0100

    xwayland: Use RandR 1.2 interface (rev 2)
    
    This adds the RandR 1.2 interface to xwayland and allows modes
    advertised by the compositor to be set in an undistructive manner.
    
    With this patch, applications that try to set the resolution will usually
    succeed and work while other apps using the same xwayland
    instance are not affected at all.
    
    The RandR 1.2 interface will be needed to implement fake-mode-setting and
    already makes applications work much cleaner and predictive when a mode
    was set.
    
    [hdegoede at redhat.com: Make crtc_set only succeed if the mode matches
     the desktop resolution]
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index ab379f813..abbddddf9 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -577,12 +577,80 @@ xwl_randr_get_info(ScreenPtr pScreen, Rotation * rotations)
     return TRUE;
 }
 
+#ifdef RANDR_10_INTERFACE
 static Bool
 xwl_randr_set_config(ScreenPtr pScreen,
                      Rotation rotation, int rate, RRScreenSizePtr pSize)
 {
     return FALSE;
 }
+#endif
+
+#if RANDR_12_INTERFACE
+static Bool
+xwl_randr_screen_set_size(ScreenPtr pScreen,
+                          CARD16 width,
+                          CARD16 height,
+                          CARD32 mmWidth, CARD32 mmHeight)
+{
+    return TRUE;
+}
+
+static Bool
+xwl_randr_crtc_set(ScreenPtr pScreen,
+                   RRCrtcPtr crtc,
+                   RRModePtr mode,
+                   int x,
+                   int y,
+                   Rotation rotation,
+                   int numOutputs, RROutputPtr * outputs)
+{
+    struct xwl_output *xwl_output = crtc->devPrivate;
+
+    if (!mode || (mode->mode.width  == xwl_output->width &&
+                  mode->mode.height == xwl_output->height)) {
+        RRCrtcChanged(crtc, TRUE);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static Bool
+xwl_randr_crtc_set_gamma(ScreenPtr pScreen, RRCrtcPtr crtc)
+{
+    return TRUE;
+}
+
+static Bool
+xwl_randr_crtc_get_gamma(ScreenPtr pScreen, RRCrtcPtr crtc)
+{
+    return TRUE;
+}
+
+static Bool
+xwl_randr_output_set_property(ScreenPtr pScreen,
+                              RROutputPtr output,
+                              Atom property,
+                              RRPropertyValuePtr value)
+{
+    return TRUE;
+}
+
+static Bool
+xwl_output_validate_mode(ScreenPtr pScreen,
+                         RROutputPtr output,
+                         RRModePtr mode)
+{
+    return TRUE;
+}
+
+static void
+xwl_randr_mode_destroy(ScreenPtr pScreen, RRModePtr mode)
+{
+    return;
+}
+#endif
 
 Bool
 xwl_screen_init_output(struct xwl_screen *xwl_screen)
@@ -596,7 +664,20 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen)
 
     rp = rrGetScrPriv(xwl_screen->screen);
     rp->rrGetInfo = xwl_randr_get_info;
+
+#if RANDR_10_INTERFACE
     rp->rrSetConfig = xwl_randr_set_config;
+#endif
+
+#if RANDR_12_INTERFACE
+    rp->rrScreenSetSize = xwl_randr_screen_set_size;
+    rp->rrCrtcSet = xwl_randr_crtc_set;
+    rp->rrCrtcSetGamma = xwl_randr_crtc_set_gamma;
+    rp->rrCrtcGetGamma = xwl_randr_crtc_get_gamma;
+    rp->rrOutputSetProperty = xwl_randr_output_set_property;
+    rp->rrOutputValidateMode = xwl_output_validate_mode;
+    rp->rrModeDestroy = xwl_randr_mode_destroy;
+#endif
 
     return TRUE;
 }
commit 0d656d796071fb637e4969ea800855fe5d1c9728
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Wed Jun 26 16:46:54 2019 +0200

    xwayland: Add fake output modes to xrandr output mode lists
    
    This is a preparation patch for adding support for apps which want to
    change the resolution when they go fullscreen because they are hardcoded
    to render at a specific resolution, e.g. 640x480.
    
    Follow up patches will fake the mode-switch these apps want by using
    WPviewport to scale there pixmap to cover the entire output.
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index e32ba1284..ab379f813 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -245,14 +245,110 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
     update_desktop_dimensions();
 }
 
+/* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */
+const int32_t xwl_output_fake_modes[][2] = {
+    /* 4:3 (1.33) */
+    { 2048, 1536 },
+    { 1920, 1440 },
+    { 1600, 1200 },
+    { 1440, 1080 },
+    { 1400, 1050 },
+    { 1280, 1024 }, /* 5:4 (1.25) */
+    { 1280,  960 },
+    { 1152,  864 },
+    { 1024,  768 },
+    {  800,  600 },
+    {  640,  480 },
+    {  320,  240 },
+    /* 16:10 (1.6) */
+    { 2560, 1600 },
+    { 1920, 1200 },
+    { 1680, 1050 },
+    { 1440,  900 },
+    { 1280,  800 },
+    {  720,  480 }, /* 3:2 (1.5) */
+    {  640,  400 },
+    {  320,  200 },
+    /* 16:9 (1.77) */
+    { 5120, 2880 },
+    { 4096, 2304 },
+    { 3840, 2160 },
+    { 3200, 1800 },
+    { 2880, 1620 },
+    { 2560, 1440 },
+    { 2048, 1152 },
+    { 1920, 1080 },
+    { 1600,  900 },
+    { 1368,  768 },
+    { 1280,  720 },
+    { 1024,  576 },
+    {  864,  486 },
+    {  720,  400 },
+    {  640,  350 },
+};
+
+/* Build an array with RRModes the first mode is the actual output mode, the
+ * rest are fake modes from the xwl_output_fake_modes list. We do this for apps
+ * which want to change resolution when they go fullscreen.
+ * When an app requests a mode-change, we fake it using WPviewport.
+ */
+static RRModePtr *
+output_get_rr_modes(struct xwl_output *xwl_output,
+                    int32_t width, int32_t height,
+                    int *count)
+{
+    struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+    RRModePtr *rr_modes;
+    int i;
+
+    rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 1, sizeof(RRModePtr));
+    if (!rr_modes)
+        goto err;
+
+    /* Add actual output mode */
+    rr_modes[0] = xwayland_cvt(width, height, xwl_output->refresh / 1000.0, 0, 0);
+    if (!rr_modes[0])
+        goto err;
+
+    *count = 1;
+
+    if (!xwl_screen_has_resolution_change_emulation(xwl_screen))
+        return rr_modes;
+
+    /* Add fake modes */
+    for (i = 0; i < ARRAY_SIZE(xwl_output_fake_modes); i++) {
+        /* Skip actual output mode, already added */
+        if (xwl_output_fake_modes[i][0] == width &&
+            xwl_output_fake_modes[i][1] == height)
+            continue;
+
+        /* Skip modes which are too big, avoid downscaling */
+        if (xwl_output_fake_modes[i][0] > width ||
+            xwl_output_fake_modes[i][1] > height)
+            continue;
+
+        rr_modes[*count] = xwayland_cvt(xwl_output_fake_modes[i][0],
+                                        xwl_output_fake_modes[i][1],
+                                        xwl_output->refresh / 1000.0, 0, 0);
+        if (!rr_modes[*count])
+            goto err;
+
+        (*count)++;
+    }
+
+    return rr_modes;
+err:
+    FatalError("Failed to allocate memory for list of RR modes");
+}
+
 static void
 apply_output_change(struct xwl_output *xwl_output)
 {
     struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
     struct xwl_output *it;
-    int mode_width, mode_height;
+    int mode_width, mode_height, count;
     int width = 0, height = 0, has_this_output = 0;
-    RRModePtr randr_mode;
+    RRModePtr *randr_modes;
     Bool need_rotate;
 
     /* Clear out the "done" received flags */
@@ -271,12 +367,16 @@ apply_output_change(struct xwl_output *xwl_output)
         mode_height = xwl_output->width;
     }
 
-    randr_mode = xwayland_cvt(mode_width, mode_height,
-                              xwl_output->refresh / 1000.0, 0, 0);
-    RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1);
-    RRCrtcNotify(xwl_output->randr_crtc, randr_mode,
+    /* Build a fresh modes array using the current refresh rate */
+    randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
+    RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
+    RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
                  xwl_output->x, xwl_output->y,
                  xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
+    /* RROutputSetModes takes ownership of the passed in modes, so we only
+     * have to free the pointer array.
+     */
+    free(randr_modes);
 
     xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
         /* output done event is sent even when some property
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 4a52f843c..8e416fd9d 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -182,6 +182,23 @@ xwl_screen_get(ScreenPtr screen)
     return dixLookupPrivate(&screen->devPrivates, &xwl_screen_private_key);
 }
 
+static Bool
+xwl_screen_has_viewport_support(struct xwl_screen *xwl_screen)
+{
+    return wl_compositor_get_version(xwl_screen->compositor) >=
+                            WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION &&
+           xwl_screen->viewporter != NULL;
+}
+
+Bool
+xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
+{
+    /* Resolution change emulation is only supported in rootless mode and
+     * it requires viewport support.
+     */
+    return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
+}
+
 static void
 xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow,
                              const char *debug_msg)
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a7605c07d..b0a1cf36a 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -385,6 +385,7 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
 Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);
 
 struct xwl_screen *xwl_screen_get(ScreenPtr screen);
+Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen);
 
 void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool);
 void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
commit 7c6f17790d3aedb164481264b0f05a8a14103731
Author: Robert Mader <robert.mader at posteo.de>
Date:   Tue Jul 2 12:03:12 2019 +0200

    xwayland: Use buffer_damage instead of surface damage if available
    
    When a viewport is set, damage will only work properly when using
    wl_surface_damage_buffer instead of wl_surface_damage.
    
    When no viewport is set, there should be no difference between
    surface and buffer damage.
    
    This is a preparation patch for using viewport to add support for fake
    mode-changes through xrandr for apps which want to change the resolution
    when going fullscreen.
    
    Changes by Hans de Goede <hdegoede at redhat.com>:
    -Split the damage changes out into their own patch
    -Add xwl_surface_damage helper
    -Also use buffer_damage / the new helper for the present and cursor code
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index ec0029438..6c73553bd 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -166,9 +166,9 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
                           xwl_seat->x_cursor->bits->yhot);
     wl_surface_attach(xwl_cursor->surface,
                       xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
-    wl_surface_damage(xwl_cursor->surface, 0, 0,
-                      xwl_seat->x_cursor->bits->width,
-                      xwl_seat->x_cursor->bits->height);
+    xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
+                       xwl_seat->x_cursor->bits->width,
+                       xwl_seat->x_cursor->bits->height);
 
     xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface);
     wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor);
@@ -218,9 +218,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
                                   xwl_seat->x_cursor->bits->yhot);
     wl_surface_attach(xwl_cursor->surface,
                       xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
-    wl_surface_damage(xwl_cursor->surface, 0, 0,
-                      xwl_seat->x_cursor->bits->width,
-                      xwl_seat->x_cursor->bits->height);
+    xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
+                       xwl_seat->x_cursor->bits->width,
+                       xwl_seat->x_cursor->bits->height);
 
     xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface);
     wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor);
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index a1b3109cc..b7da261b7 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -500,9 +500,9 @@ xwl_present_flip(WindowPtr present_window,
     xwl_present_window->frame_timer_firing = FALSE;
     xwl_present_reset_timer(xwl_present_window);
 
-    wl_surface_damage(xwl_window->surface, 0, 0,
-                      damage_box->x2 - damage_box->x1,
-                      damage_box->y2 - damage_box->y1);
+    xwl_surface_damage(xwl_window->xwl_screen, xwl_window->surface, 0, 0,
+                       damage_box->x2 - damage_box->x1,
+                       damage_box->y2 - damage_box->y1);
 
     wl_surface_commit(xwl_window->surface);
 
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 51a187b73..4a52f843c 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -796,6 +796,16 @@ xwl_destroy_window(WindowPtr window)
     return ret;
 }
 
+void xwl_surface_damage(struct xwl_screen *xwl_screen,
+                        struct wl_surface *surface,
+                        int32_t x, int32_t y, int32_t width, int32_t height)
+{
+    if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
+        wl_surface_damage_buffer(surface, x, y, width, height);
+    else
+        wl_surface_damage(surface, x, y, width, height);
+}
+
 static void
 xwl_window_post_damage(struct xwl_window *xwl_window)
 {
@@ -832,13 +842,15 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
      */
     if (RegionNumRects(region) > 256) {
         box = RegionExtents(region);
-        wl_surface_damage(xwl_window->surface, box->x1, box->y1,
-                          box->x2 - box->x1, box->y2 - box->y1);
+        xwl_surface_damage(xwl_screen, xwl_window->surface, box->x1, box->y1,
+                           box->x2 - box->x1, box->y2 - box->y1);
     } else {
         box = RegionRects(region);
-        for (i = 0; i < RegionNumRects(region); i++, box++)
-            wl_surface_damage(xwl_window->surface, box->x1, box->y1,
-                              box->x2 - box->x1, box->y2 - box->y1);
+        for (i = 0; i < RegionNumRects(region); i++, box++) {
+            xwl_surface_damage(xwl_screen, xwl_window->surface,
+                               box->x1, box->y1,
+                               box->x2 - box->x1, box->y2 - box->y1);
+        }
     }
 
     xwl_window->frame_callback = wl_surface_frame(xwl_window->surface);
@@ -881,8 +893,13 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
     struct xwl_screen *xwl_screen = data;
 
     if (strcmp(interface, "wl_compositor") == 0) {
+        uint32_t request_version = 1;
+
+        if (version >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
+            request_version = WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION;
+
         xwl_screen->compositor =
-            wl_registry_bind(registry, id, &wl_compositor_interface, 1);
+            wl_registry_bind(registry, id, &wl_compositor_interface, request_version);
     }
     else if (strcmp(interface, "wl_shm") == 0) {
         xwl_screen->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 1fb8a4fca..a7605c07d 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -378,6 +378,9 @@ struct xwl_output {
 };
 
 void xwl_sync_events (struct xwl_screen *xwl_screen);
+void xwl_surface_damage(struct xwl_screen *xwl_screen,
+                        struct wl_surface *surface,
+                        int32_t x, int32_t y, int32_t width, int32_t height);
 
 Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);
 
commit 47bba4625339592d08b375bcd8e51029c0000850
Author: Robert Mader <robert.mader at posteo.de>
Date:   Mon Jan 22 22:02:32 2018 +0100

    xwayland: Add wp_viewport wayland extension support
    
    This commit adds support for the wayland wp_viewport extension, note
    nothing uses this yet.
    
    This is a preparation patch for adding support for fake mode-changes through
    xrandr for apps which want to change the resolution when going fullscreen.
    
    [hdegoede at redhat.com: Split the code for the extension out into its own patch]
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index 5ea38c055..2fe460529 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -9,6 +9,8 @@ relative-pointer-unstable-v1-client-protocol.h
 relative-pointer-unstable-v1-protocol.c
 tablet-unstable-v2-client-protocol.h
 tablet-unstable-v2-protocol.c
+viewporter-client-protocol.h
+viewporter-protocol.c
 xdg-output-unstable-v1-client-protocol.h
 xdg-output-unstable-v1-protocol.c
 xwayland-keyboard-grab-unstable-v1-client-protocol.h
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 7b7680738..8366cc222 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -81,7 +81,9 @@ Xwayland_built_sources +=					\
 	xdg-output-unstable-v1-protocol.c			\
 	xdg-output-unstable-v1-client-protocol.h		\
 	linux-dmabuf-unstable-v1-client-protocol.h		\
-	linux-dmabuf-unstable-v1-protocol.c
+	linux-dmabuf-unstable-v1-protocol.c			\
+	viewporter-client-protocol.h				\
+	viewporter-protocol.c
 
 if XWAYLAND_EGLSTREAM
 Xwayland_built_sources +=					\
@@ -130,6 +132,11 @@ linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linu
 linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 
+viewporter-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/stable/viewporter/viewporter.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@
+viewporter-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/stable/viewporter/viewporter.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 wayland-eglstream-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml
 	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 wayland-eglstream-controller-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 9e149ae7e..4cea5d792 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -21,6 +21,7 @@ tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml'
 kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml')
 xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml')
 dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
+viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
 
 client_header = generator(scanner,
     output : '@BASENAME at -client-protocol.h',
@@ -43,12 +44,14 @@ srcs += client_header.process(tablet_xml)
 srcs += client_header.process(kbgrab_xml)
 srcs += client_header.process(xdg_output_xml)
 srcs += client_header.process(dmabuf_xml)
+srcs += client_header.process(viewporter_xml)
 srcs += code.process(relative_xml)
 srcs += code.process(pointer_xml)
 srcs += code.process(tablet_xml)
 srcs += code.process(kbgrab_xml)
 srcs += code.process(xdg_output_xml)
 srcs += code.process(dmabuf_xml)
+srcs += code.process(viewporter_xml)
 
 xwayland_glamor = []
 eglstream_srcs = []
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 3983a114c..51a187b73 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -902,6 +902,9 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
             wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
         xwl_screen_init_xdg_output(xwl_screen);
     }
+    else if (strcmp(interface, "wp_viewporter") == 0) {
+        xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
+    }
 #ifdef XWL_HAS_GLAMOR
     else if (xwl_screen->glamor) {
         xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index abbffce9b..1fb8a4fca 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -48,6 +48,7 @@
 #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
 #include "xdg-output-unstable-v1-client-protocol.h"
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
+#include "viewporter-client-protocol.h"
 
 struct xwl_format {
     uint32_t format;
@@ -148,6 +149,7 @@ struct xwl_screen {
     struct zwp_pointer_constraints_v1 *pointer_constraints;
     struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab;
     struct zxdg_output_manager_v1 *xdg_output_manager;
+    struct wp_viewporter *viewporter;
     uint32_t serial;
 
 #define XWL_FORMAT_ARGB8888 (1 << 0)
commit 834a467af978ac7a24ed17b8c8e58b6cddb4faf9
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Thu Aug 29 14:18:28 2019 +0200

    dix: Add GetCurrentClient helper
    
    Request-handlers as registered in the requestVector array, always get
    passed the clientPtr for the client which sent the request.
    But the implementation of many request-handlers typically consists of
    a generic handler calling implementation specific callbacks and / or
    various helpers often multiple levels deep and in many cases the clientPtr
    does not get passed to the callbacks / helpers.
    
    This means that in some places where we would like to have access to the
    current-client, we cannot easily access it and fixing this would require
    a lot of work and often would involve ABI breakage.
    
    This commit adds a GetCurrentClient helper which can be used as a
    shortcut to get access to the clienPtr for the currently being processed
    request without needing a lot of refactoring and ABI breakage.
    
    Note using this new GetCurrentClient helper is only safe for code
    which only runs from the main thread, this new variable MUST NOT be used
    by code which runs from signal handlers or from the input-thread.
    
    The specific use-case which resulted in the creation of this patch is adding
    support for emulation of randr / vidmode resolution changes to Xwayland.
    This emulation will not actually change the monitor resolution instead it
    will scale any window with a size which exactly matches the requested
    resolution to fill the entire monitor. The main use-case for this is
    games which are hard-coded to render at a specific resolution and have
    sofar relied on randr / vidmode to change the monitor resolution when going
    fullscreen.
    
    To make this emulation as robust as possible (e.g. avoid accidentally scaling
    windows from other apps) we want to make the emulated resolution a per client
    state. But e.g. the RRSetCrtc function does not take a client pointer; and is
    a (used) part of the Xorg server ABI (note the problem is not just limited
    to RRSetCrtc).
    
    Reviewed-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 176c7a0dd..ce84e6c8c 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -148,6 +148,7 @@ xConnSetupPrefix connSetupPrefix;
 PaddingInfo PixmapWidthPaddingInfo[33];
 
 static ClientPtr grabClient;
+static ClientPtr currentClient; /* Client for the request currently being dispatched */
 
 #define GrabNone 0
 #define GrabActive 1
@@ -176,6 +177,23 @@ volatile char isItTimeToYield;
 #define SAME_SCREENS(a, b) (\
     (a.pScreen == b.pScreen))
 
+ClientPtr
+GetCurrentClient(void)
+{
+    if (in_input_thread()) {
+        static Bool warned;
+
+        if (!warned) {
+            ErrorF("[dix] Error GetCurrentClient called from input-thread\n");
+            warned = TRUE;
+        }
+
+        return NULL;
+    }
+
+    return currentClient;
+}
+
 void
 SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1)
 {
@@ -474,9 +492,12 @@ Dispatch(void)
                     result = BadLength;
                 else {
                     result = XaceHookDispatch(client, client->majorOp);
-                    if (result == Success)
+                    if (result == Success) {
+                        currentClient = client;
                         result =
                             (*client->requestVector[client->majorOp]) (client);
+                        currentClient = NULL;
+                    }
                 }
                 if (!SmartScheduleSignalEnable)
                     SmartScheduleTime = GetTimeInMillis();
diff --git a/include/dix.h b/include/dix.h
index f2516187f..146679b58 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -148,6 +148,7 @@ typedef struct _TimeStamp {
 } TimeStamp;
 
 /* dispatch.c */
+extern _X_EXPORT ClientPtr GetCurrentClient(void);
 
 extern _X_EXPORT void SetInputCheck(HWEventQueuePtr /*c0 */ ,
                                     HWEventQueuePtr /*c1 */ );


More information about the xorg-commit mailing list