shell: Replace set_margin with set_window_geometry
authorJasper St. Pierre <jstpierre@mecheye.net>
Fri, 2 May 2014 14:21:38 +0000 (10:21 -0400)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 17 Jul 2014 20:59:01 +0000 (13:59 -0700)
Currently, there is a fun flicker when toggling maximization or
fullscreen on a window in mutter or more sophisicated compositors
and WMs.

What happens is that the client want so go maximized, so we
calculate the size that we want the window to resize to (640x480),
and then add on its margins to find the buffer size (+10 = 660x500),
and then send out a configure event for that size. The client
renders to that size, realizes that it's maximized, and then
says "oh hey, my margins are actually 0 now!", and so the compositor
has to send out another configure event.

In order to fix this, make the the configure request correspond to
the window geometry we'd like the window to be at. At the same time,
replace set_margin with set_window_geometry, where we specify a rect
rather than a border around the window.

clients/window.c
desktop-shell/shell.c
protocol/xdg-shell.xml
src/compositor.h
xwayland/window-manager.c

index f44bf64..1700cf9 100644 (file)
@@ -3894,24 +3894,33 @@ window_sync_parent(struct window *window)
 }
 
 static void
-window_sync_margin(struct window *window)
+window_get_geometry(struct window *window, struct rectangle *geometry)
 {
-       int margin;
+       if (window->frame)
+               frame_input_rect(window->frame->frame,
+                                &geometry->x,
+                                &geometry->y,
+                                &geometry->width,
+                                &geometry->height);
+       else
+               window_get_allocation(window, geometry);
+}
 
-       if (!window->xdg_surface)
-               return;
+static void
+window_sync_geometry(struct window *window)
+{
+       struct rectangle geometry;
 
-       if (!window->frame)
+       if (!window->xdg_surface)
                return;
 
-       margin = frame_get_shadow_margin(window->frame->frame);
+       window_get_geometry(window, &geometry);
 
-       /* Shadow size is the same on every side. */
-       xdg_surface_set_margin(window->xdg_surface,
-                                    margin,
-                                    margin,
-                                    margin,
-                                    margin);
+       xdg_surface_set_window_geometry(window->xdg_surface,
+                                       geometry.x,
+                                       geometry.y,
+                                       geometry.width,
+                                       geometry.height);
 }
 
 static void
@@ -3922,7 +3931,7 @@ window_flush(struct window *window)
        if (!window->custom) {
                if (window->xdg_surface) {
                        window_sync_parent(window);
-                       window_sync_margin(window);
+                       window_sync_geometry(window);
                }
        }
 
index fca1c00..593c7f3 100644 (file)
@@ -171,9 +171,9 @@ struct shell_surface {
        bool state_requested;
 
        struct {
-               int left, right, top, bottom;
-       } margin, next_margin;
-       bool has_next_margin;
+               int32_t x, y, width, height;
+       } geometry, next_geometry;
+       bool has_set_geometry, has_next_geometry;
 
        int focus_count;
 };
@@ -1554,14 +1554,12 @@ constrain_position(struct weston_move_grab *move, int *cx, int *cy)
 
        panel_height = get_output_panel_height(shsurf->shell,
                                               shsurf->surface->output);
-       bottom = y + shsurf->surface->height - shsurf->margin.bottom;
+       bottom = y + shsurf->geometry.height;
        if (bottom - panel_height < safety)
-               y = panel_height + safety -
-                       shsurf->surface->height + shsurf->margin.bottom;
+               y = panel_height + safety - shsurf->geometry.height;
 
-       if (move->client_initiated &&
-           y + shsurf->margin.top < panel_height)
-               y = panel_height - shsurf->margin.top;
+       if (move->client_initiated && y + shsurf->geometry.y < panel_height)
+               y = panel_height - shsurf->geometry.y;
 
        *cx = x;
        *cy = y;
@@ -1829,13 +1827,9 @@ surface_resize(struct shell_surface *shsurf,
                return -1;
 
        resize->edges = edges;
-       surface_subsurfaces_boundingbox(shsurf->surface, NULL, NULL,
-                                       &resize->width, &resize->height);
 
-       resize->width -= shsurf->margin.left;
-       resize->width -= shsurf->margin.right;
-       resize->height -= shsurf->margin.top;
-       resize->height -= shsurf->margin.bottom;
+       resize->width = shsurf->geometry.width;
+       resize->height = shsurf->geometry.height;
 
        shsurf->resize_edges = edges;
        shell_surface_state_changed(shsurf);
@@ -2130,14 +2124,14 @@ set_title(struct shell_surface *shsurf, const char *title)
 }
 
 static void
-set_margin(struct shell_surface *shsurf,
-          int32_t left, int32_t right, int32_t top, int32_t bottom)
+set_window_geometry(struct shell_surface *shsurf,
+                   int32_t x, int32_t y, int32_t width, int32_t height)
 {
-       shsurf->next_margin.left = left;
-       shsurf->next_margin.right = right;
-       shsurf->next_margin.top = top;
-       shsurf->next_margin.bottom = bottom;
-       shsurf->has_next_margin = true;
+       shsurf->next_geometry.x = x;
+       shsurf->next_geometry.y = y;
+       shsurf->next_geometry.width = width;
+       shsurf->next_geometry.height = height;
+       shsurf->has_next_geometry = true;
 }
 
 static void
@@ -3399,19 +3393,6 @@ xdg_surface_set_parent(struct wl_client *client,
 }
 
 static void
-xdg_surface_set_margin(struct wl_client *client,
-                            struct wl_resource *resource,
-                            int32_t left,
-                            int32_t right,
-                            int32_t top,
-                            int32_t bottom)
-{
-       struct shell_surface *shsurf = wl_resource_get_user_data(resource);
-
-       set_margin(shsurf, left, right, top, bottom);
-}
-
-static void
 xdg_surface_set_app_id(struct wl_client *client,
                       struct wl_resource *resource,
                       const char *app_id)
@@ -3472,6 +3453,19 @@ xdg_surface_ack_configure(struct wl_client *client,
 }
 
 static void
+xdg_surface_set_window_geometry(struct wl_client *client,
+                               struct wl_resource *resource,
+                               int32_t x,
+                               int32_t y,
+                               int32_t width,
+                               int32_t height)
+{
+       struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+       set_window_geometry(shsurf, x, y, width, height);
+}
+
+static void
 xdg_surface_set_maximized(struct wl_client *client,
                          struct wl_resource *resource)
 {
@@ -3542,13 +3536,13 @@ xdg_surface_set_minimized(struct wl_client *client,
 static const struct xdg_surface_interface xdg_surface_implementation = {
        xdg_surface_destroy,
        xdg_surface_set_parent,
-       xdg_surface_set_margin,
        xdg_surface_set_title,
        xdg_surface_set_app_id,
        xdg_surface_show_window_menu,
        xdg_surface_move,
        xdg_surface_resize,
        xdg_surface_ack_configure,
+       xdg_surface_set_window_geometry,
        xdg_surface_set_maximized,
        xdg_surface_unset_maximized,
        xdg_surface_set_fullscreen,
@@ -5141,9 +5135,16 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
        if (es->width == 0)
                return;
 
-       if (shsurf->has_next_margin) {
-               shsurf->margin = shsurf->next_margin;
-               shsurf->has_next_margin = false;
+       if (shsurf->has_next_geometry) {
+               shsurf->geometry = shsurf->next_geometry;
+               shsurf->has_next_geometry = false;
+               shsurf->has_set_geometry = true;
+       } else if (!shsurf->has_set_geometry) {
+               surface_subsurfaces_boundingbox(shsurf->surface,
+                                               &shsurf->geometry.x,
+                                               &shsurf->geometry.y,
+                                               &shsurf->geometry.width,
+                                               &shsurf->geometry.height);
        }
 
        if (shsurf->state_changed) {
@@ -6200,7 +6201,7 @@ module_init(struct weston_compositor *ec,
        ec->shell_interface.move = shell_interface_move;
        ec->shell_interface.resize = surface_resize;
        ec->shell_interface.set_title = set_title;
-       ec->shell_interface.set_margin = set_margin;
+       ec->shell_interface.set_window_geometry = set_window_geometry;
 
        weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
        weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
index 0327f40..9532644 100644 (file)
       <arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
     </request>
 
-    <request name="set_margin">
-      <description summary="set the visible frame boundaries">
-        This tells the compositor what the visible size of the window
-        should be, so it can use it to determine what borders to use for
-        constrainment and alignment.
-
-        CSD often has invisible areas for decoration purposes, like drop
-        shadows. These "shadow" drawings need to be subtracted out of the
-        normal boundaries of the window when computing where to place
-        windows (e.g. to set this window so it's centered on top of another,
-        or to put it to the left or right of the screen.)
-
-        This value should change as little as possible at runtime, to
-        prevent flicker.
-
-        This value is also ignored when the window is maximized or
-        fullscreen, and assumed to be 0.
-
-        If never called, this value is assumed to be 0.
-      </description>
-      <arg name="left_margin" type="int"/>
-      <arg name="right_margin" type="int"/>
-      <arg name="top_margin" type="int"/>
-      <arg name="bottom_margin" type="int"/>
-    </request>
-
     <request name="set_title">
       <description summary="set surface title">
        Set a short title for the surface.
        The configure event asks the client to resize its surface.
 
        The width and height arguments specify a hint to the window
-        about how its surface should be resized in surface local
+        about how its surface should be resized in window geometry
         coordinates. The states listed in the event specify how the
         width/height arguments should be interpreted.
 
       <arg name="serial" type="uint" summary="a serial to configure for"/>
     </request>
 
+    <request name="set_window_geometry">
+      <description summary="set the new window geometry">
+        The window geometry of a window is its "visible bounds" from the
+        user's perspective. Client-side decorations often have invisible
+        portions like drop-shadows which should be ignored for the
+        purposes of aligning, placing and constraining windows.
+
+        The default value is the full bounds of the surface, including any
+        subsurfaces. Once the window geometry of the surface is set once,
+        it is not possible to unset it, and it will remain the same until
+        set_window_geometry is called again, even if a new subsurface or
+        buffer is attached.
+
+        If responding to a configure event, the window geometry in here
+        must respect the sizing negotiations specified by the states in
+        the configure event.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
     <request name="set_maximized" />
     <request name="unset_maximized" />
 
index bef5e1d..d4a2dbb 100644 (file)
@@ -110,9 +110,9 @@ struct weston_shell_interface {
                      struct weston_seat *ws, uint32_t edges);
        void (*set_title)(struct shell_surface *shsurf,
                          const char *title);
-       void (*set_margin)(struct shell_surface *shsurf,
-                          int32_t left, int32_t right,
-                          int32_t top, int32_t bottom);
+       void (*set_window_geometry)(struct shell_surface *shsurf,
+                                   int32_t x, int32_t y,
+                                   int32_t width, int32_t height);
 };
 
 struct weston_animation {
index 2fb65b1..625a0e6 100644 (file)
@@ -1007,12 +1007,9 @@ weston_wm_window_draw_decoration(void *data)
 
                pixman_region32_init_rect(&window->surface->pending.input,
                                          input_x, input_y, input_w, input_h);
-               
-               shell_interface->set_margin(window->shsurf,
-                                           input_x,
-                                           width - input_w - input_x,
-                                           input_y,
-                                           height - input_h - input_y);
+
+               shell_interface->set_window_geometry(window->shsurf,
+                                                    input_x, input_y, input_w, input_h);
        }
 }