[PATCH 1/2] xwayland: Update screen size on output removal

Olivier Fourdan ofourdan at redhat.com
Fri Nov 13 08:57:22 PST 2015


When unplugging an output, it's still listed in xrandr and the size
of the root window still includes the removed output.

The XRandR output should be destroyed when its Wayland counterpart is
destroyed and the screen dimensions must be updated in both the done
and the destroy handler.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92914
Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
---
 hw/xwayland/xwayland-output.c | 149 ++++++++++++++++++++++++------------------
 1 file changed, 85 insertions(+), 64 deletions(-)

diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index e4623d4..39893e7 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -76,6 +76,76 @@ wl_subpixel_to_xrandr(int subpixel)
     }
 }
 
+static inline void
+output_get_new_size(struct xwl_output *xwl_output, int *height, int *width)
+{
+    if (*width < xwl_output->x + xwl_output->width)
+        *width = xwl_output->x + xwl_output->width;
+
+    if (*height < xwl_output->y + xwl_output->height)
+        *height = xwl_output->y + xwl_output->height;
+}
+
+/* Approximate some kind of mmpd (m.m. per dot) of the screen given the outputs
+ * associated with it.
+ *
+ * It will either calculate the mean mmpd of all the outputs, or default to
+ * 96 DPI if no reasonable value could be calculated.
+ */
+static double
+approximate_mmpd(struct xwl_screen *xwl_screen)
+{
+    struct xwl_output *it;
+    int total_width_mm = 0;
+    int total_width = 0;
+
+    xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
+        if (it->randr_output->mmWidth == 0)
+            continue;
+
+        total_width_mm += it->randr_output->mmWidth;
+        total_width += it->width;
+    }
+
+    if (total_width_mm != 0)
+        return (double)total_width_mm / total_width;
+    else
+        return 25.4 / DEFAULT_DPI;
+}
+
+static void
+update_screen_size(struct xwl_output *xwl_output, int width, int height)
+{
+    struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+    double mmpd;
+
+    if (xwl_screen->screen->root)
+        SetRootClip(xwl_screen->screen, FALSE);
+
+    xwl_screen->width = width;
+    xwl_screen->height = height;
+    xwl_screen->screen->width = width;
+    xwl_screen->screen->height = height;
+
+    if (xwl_output->width == width && xwl_output->height == height) {
+        xwl_screen->screen->mmWidth = xwl_output->randr_output->mmWidth;
+        xwl_screen->screen->mmHeight = xwl_output->randr_output->mmHeight;
+    } else {
+        mmpd = approximate_mmpd(xwl_screen);
+        xwl_screen->screen->mmWidth = width * mmpd;
+        xwl_screen->screen->mmHeight = height * mmpd;
+    }
+
+    if (xwl_screen->screen->root) {
+        xwl_screen->screen->root->drawable.width = width;
+        xwl_screen->screen->root->drawable.height = height;
+        SetRootClip(xwl_screen->screen, TRUE);
+        RRScreenSizeNotify(xwl_screen->screen);
+    }
+
+    update_desktop_dimensions();
+}
+
 static void
 output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
                        int physical_width, int physical_height, int subpixel,
@@ -120,51 +190,12 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
                  xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
 }
 
-static inline void
-output_get_new_size(struct xwl_output *xwl_output,
-		    int *height, int *width)
-{
-    if (*width < xwl_output->x + xwl_output->width)
-        *width = xwl_output->x + xwl_output->width;
-
-    if (*height < xwl_output->y + xwl_output->height)
-        *height = xwl_output->y + xwl_output->height;
-}
-
-/* Approximate some kind of mmpd (m.m. per dot) of the screen given the outputs
- * associated with it.
- *
- * It will either calculate the mean mmpd of all the outputs, or default to
- * 96 DPI if no reasonable value could be calculated.
- */
-static double
-approximate_mmpd(struct xwl_screen *xwl_screen)
-{
-    struct xwl_output *it;
-    int total_width_mm = 0;
-    int total_width = 0;
-
-    xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
-        if (it->randr_output->mmWidth == 0)
-            continue;
-
-        total_width_mm += it->randr_output->mmWidth;
-        total_width += it->width;
-    }
-
-    if (total_width_mm != 0)
-        return (double)total_width_mm / total_width;
-    else
-        return 25.4 / DEFAULT_DPI;
-}
-
 static void
 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;
-    double mmpd;
 
     xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
         /* output done event is sent even when some property
@@ -186,31 +217,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
 	--xwl_screen->expecting_event;
     }
 
-    if (xwl_screen->screen->root)
-        SetRootClip(xwl_screen->screen, FALSE);
-
-    xwl_screen->width = width;
-    xwl_screen->height = height;
-    xwl_screen->screen->width = width;
-    xwl_screen->screen->height = height;
-
-    if (xwl_output->width == width && xwl_output->height == height) {
-        xwl_screen->screen->mmWidth = xwl_output->randr_output->mmWidth;
-        xwl_screen->screen->mmHeight = xwl_output->randr_output->mmHeight;
-    } else {
-        mmpd = approximate_mmpd(xwl_screen);
-        xwl_screen->screen->mmWidth = width * mmpd;
-        xwl_screen->screen->mmHeight = height * mmpd;
-    }
-
-    if (xwl_screen->screen->root) {
-        xwl_screen->screen->root->drawable.width = width;
-        xwl_screen->screen->root->drawable.height = height;
-        SetRootClip(xwl_screen->screen, TRUE);
-        RRScreenSizeNotify(xwl_screen->screen);
-    }
-
-    update_desktop_dimensions();
+    update_screen_size(xwl_output, width, height);
 }
 
 static void
@@ -259,6 +266,20 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
 void
 xwl_output_destroy(struct xwl_output *xwl_output)
 {
+    struct xwl_output *it;
+    struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+    int width = 0, height = 0;
+
+    RROutputSetConnection(xwl_output->randr_output, RR_Disconnected);
+    xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
+        if (it == xwl_output)
+            continue; /* skip the one we are about to destroy */
+
+        output_get_new_size(it, &height, &width);
+    }
+    update_screen_size(xwl_output, width, height);
+    RROutputDestroy(xwl_output->randr_output);
+
     wl_output_destroy(xwl_output->output);
     xorg_list_del(&xwl_output->link);
     free(xwl_output);
-- 
2.5.0



More information about the xorg-devel mailing list