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 <[email protected]>
---
 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

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to