[PATCH RFC xserver] xwayland: List all wl_output::mode(s) in xrandr

Olivier Fourdan ofourdan at redhat.com
Wed Nov 29 14:26:58 UTC 2017


Xwayland would only list the current wl_output mode in xrandr, even
though multiple modes might be advertised by the Wayland compositor.

List all available modes listed by the Wayland compositor using
wl_output::mode in XrandR.

Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
---
 Note: this works best with weston which lists multiple modes, unlike
       gnome-shell/mutter which advertises only the current mode in
       wl_output::mode.

 hw/xwayland/xwayland-output.c | 87 ++++++++++++++++++++++++++++++++++++++++---
 hw/xwayland/xwayland.h        | 12 ++++++
 2 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index 460caaf56..2a070014b 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -99,12 +99,71 @@ output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
     xwl_output->rotation = wl_transform_to_xrandr(transform);
 }
 
+static void
+output_add_new_mode(struct xwl_output *xwl_output, uint32_t flags,
+                    int width, int height, int refresh)
+{
+    struct xwl_mode *xwl_mode;
+
+    xwl_mode = calloc(1, sizeof *xwl_mode);
+    if (!xwl_mode)
+        FatalError("Failed to create new mode");
+
+    xwl_mode->width = width;
+    xwl_mode->height = height;
+    xwl_mode->refresh = refresh;
+    xwl_mode->randr_mode = xwayland_cvt(width, height, refresh / 1000.0, 0, 0);
+    xorg_list_append(&xwl_mode->link, &xwl_output->modes_list);
+
+    xwl_output->num_modes++;
+    if (flags & WL_OUTPUT_MODE_PREFERRED)
+        xwl_output->preferred_mode = xwl_output->num_modes;
+}
+
+static RRModePtr
+output_get_current_rr_mode(struct xwl_output *xwl_output)
+{
+    struct xwl_mode *xwl_mode;
+
+    xorg_list_for_each_entry(xwl_mode, &xwl_output->modes_list, link) {
+        if (xwl_mode->width == xwl_output->width &&
+            xwl_mode->height == xwl_output->height &&
+            xwl_mode->refresh == xwl_output->refresh)
+            return xwl_mode->randr_mode;
+    }
+
+    FatalError("Cannot find current mode [%ix%i]@%.2f",
+               xwl_output->width, xwl_output->height, xwl_output->refresh / 1000.0);
+}
+
+static RRModePtr *
+output_get_all_rr_modes(struct xwl_output *xwl_output)
+{
+    struct xwl_mode *xwl_mode;
+    RRModePtr *rr_modes;
+    int i = 0;
+
+    rr_modes = xallocarray(xwl_output->num_modes, sizeof(RRModePtr));
+    if (!rr_modes)
+        FatalError("Failed to create the list of RR modes");
+
+    xorg_list_for_each_entry(xwl_mode, &xwl_output->modes_list, link) {
+        rr_modes[i++] = xwl_mode->randr_mode;
+    }
+
+    return rr_modes;
+}
+
 static void
 output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
                    int width, int height, int refresh)
 {
     struct xwl_output *xwl_output = data;
 
+    /* Add available modes during the binding phase */
+    if (xwl_output->binding)
+        output_add_new_mode (xwl_output, flags, width, height, refresh);
+
     if (!(flags & WL_OUTPUT_MODE_CURRENT))
         return;
 
@@ -205,12 +264,21 @@ output_handle_done(void *data, struct wl_output *wl_output)
     struct xwl_output *it, *xwl_output = data;
     struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
     int width = 0, height = 0, has_this_output = 0;
-    RRModePtr randr_mode;
+    RRModePtr randr_current_mode;
 
-    randr_mode = xwayland_cvt(xwl_output->width, xwl_output->height,
-                              xwl_output->refresh / 1000.0, 0, 0);
-    RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1);
-    RRCrtcNotify(xwl_output->randr_crtc, randr_mode,
+    if (xwl_output->binding) {
+        RRModePtr *randr_modes;
+
+        randr_modes = output_get_all_rr_modes(xwl_output);
+        RROutputSetModes(xwl_output->randr_output, randr_modes,
+                         xwl_output->num_modes, xwl_output->preferred_mode);
+        free(randr_modes);
+        /* We're done with binding. do not expect further modes to list */
+        xwl_output->binding = FALSE;
+    }
+
+    randr_current_mode = output_get_current_rr_mode(xwl_output);
+    RRCrtcNotify(xwl_output->randr_crtc, randr_current_mode,
                  xwl_output->x, xwl_output->y,
                  xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
 
@@ -269,6 +337,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
         goto err;
     }
 
+    xwl_output->binding = TRUE;
     xwl_output->server_output_id = id;
     wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
 
@@ -288,7 +357,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
         ErrorF("Failed creating RandR Output\n");
         goto err;
     }
-
+    xorg_list_init(&xwl_output->modes_list);
     RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
     RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
     RROutputSetConnection(xwl_output->randr_output, RR_Connected);
@@ -316,8 +385,14 @@ xwl_output_remove(struct xwl_output *xwl_output)
 {
     struct xwl_output *it;
     struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+    struct xwl_mode *xwl_mode, *next_xwl_mode;
     int width = 0, height = 0;
 
+    xorg_list_for_each_entry_safe(xwl_mode, next_xwl_mode, &xwl_output->modes_list, link) {
+        RRModeDestroy(xwl_mode->randr_mode);
+        free(xwl_mode);
+    }
+
     RRCrtcDestroy(xwl_output->randr_crtc);
     RROutputDestroy(xwl_output->randr_output);
     xorg_list_del(&xwl_output->link);
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 3adee82fa..0b6e212e5 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -255,11 +255,23 @@ struct xwl_tablet_pad {
     struct xorg_list pad_group_list;
 };
 
+struct xwl_mode {
+    struct xorg_list link;
+    int width;
+    int height;
+    int refresh;
+    RRModePtr randr_mode;
+};
+
 struct xwl_output {
     struct xorg_list link;
     struct wl_output *output;
     uint32_t server_output_id;
     struct xwl_screen *xwl_screen;
+    struct xorg_list modes_list;
+    Bool binding;
+    int num_modes;
+    int preferred_mode;
     RROutputPtr randr_output;
     RRCrtcPtr randr_crtc;
     int32_t x, y, width, height, refresh;
-- 
2.14.3



More information about the wayland-devel mailing list