[mutter] window-actor/wayland: Draw black background for fullscreen windows



commit 909616b20876478bc56932cd18c8e85e982645f6
Author: Sebastian Wick <sebastian wick redhat com>
Date:   Tue May 3 18:47:57 2022 +0200

    window-actor/wayland: Draw black background for fullscreen windows
    
    Fullscreen Wayland toplevel surfaces don't need to respect the
    configured size in which case it should be shown centered on the monitor
    with a black background. The black background becomes part of the window
    geometry.
    
    The surface container is responsible for correctly culling the surfaces
    and making sure the surface actors are removed from the actor tree to
    avoid destroying them.
    
    The window actor culling implementation assumes all surfaces to be direct
    children of said actor. The introduction of the surface_container actor
    broke that assumption. This implements the culling interface in
    MetaWindowActorWayland which is aware of the actor surface_container and
    fullscreen state.
    
    v2: Fix forwarding culling to surface even if there is a background.
    v2: Don't alter passed geometry.
    v2: Update window geometry code documentation to reflect these changes.
    v2: Only use constrained rect if we're acked fullscreen.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2338>

 src/compositor/meta-window-actor-private.h |   2 +
 src/compositor/meta-window-actor-wayland.c | 308 +++++++++++++++++++++++++----
 src/compositor/meta-window-actor-wayland.h |   6 +
 src/compositor/meta-window-actor-x11.c     |  11 ++
 src/compositor/meta-window-actor.c         |  19 +-
 src/wayland/meta-window-wayland.c          |  44 +++--
 src/wayland/meta-window-wayland.h          |   2 +
 7 files changed, 328 insertions(+), 64 deletions(-)
---
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index a2b8eb1942..477d0b3a5b 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -34,6 +34,8 @@ struct _MetaWindowActorClass
   void (*update_regions) (MetaWindowActor *actor);
   gboolean (*can_freeze_commits) (MetaWindowActor *actor);
 
+  void (*sync_geometry) (MetaWindowActor     *actor,
+                         const MetaRectangle *actor_rect);
   gboolean (*is_single_surface_actor) (MetaWindowActor *actor);
 };
 
diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c
index a135d2805e..3abe588c9b 100644
--- a/src/compositor/meta-window-actor-wayland.c
+++ b/src/compositor/meta-window-actor-wayland.c
@@ -22,15 +22,35 @@
 
 #include "config.h"
 
+#include "compositor/clutter-utils.h"
 #include "compositor/meta-cullable.h"
 #include "compositor/meta-surface-actor-wayland.h"
 #include "compositor/meta-window-actor-wayland.h"
+#include "compositor/region-utils.h"
 #include "meta/meta-window-actor.h"
 #include "wayland/meta-wayland-surface.h"
+#include "wayland/meta-window-wayland.h"
+
+struct _MetaSurfaceContainerActorWayland
+{
+  ClutterActor parent;
+
+  MetaWindowActor *window_actor;
+};
+
+static void surface_container_cullable_iface_init (MetaCullableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaSurfaceContainerActorWayland,
+                         meta_surface_container_actor_wayland,
+                         CLUTTER_TYPE_ACTOR,
+                         G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE,
+                                                surface_container_cullable_iface_init))
 
 struct _MetaWindowActorWayland
 {
   MetaWindowActor parent;
+  ClutterActor *background;
+  MetaSurfaceContainerActorWayland *surface_container;
 };
 
 static void cullable_iface_init (MetaCullableInterface *iface);
@@ -42,10 +62,90 @@ G_DEFINE_TYPE_WITH_CODE (MetaWindowActorWayland, meta_window_actor_wayland,
 
 typedef struct _SurfaceTreeTraverseData
 {
-  MetaWindowActor *window_actor;
+  ClutterActor *surface_container;
   int index;
 } SurfaceTreeTraverseData;
 
+static MetaSurfaceContainerActorWayland *
+surface_container_new (MetaWindowActor *window_actor)
+{
+  MetaSurfaceContainerActorWayland *surface_container;
+
+  surface_container = g_object_new (META_TYPE_SURFACE_CONTAINER_ACTOR_WAYLAND,
+                                    NULL);
+  surface_container->window_actor = window_actor;
+
+  return surface_container;
+}
+
+static void
+surface_container_cull_out (MetaCullable   *cullable,
+                            cairo_region_t *unobscured_region,
+                            cairo_region_t *clip_region)
+{
+  meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
+}
+
+static gboolean
+surface_container_is_untransformed (MetaCullable *cullable)
+{
+  MetaSurfaceContainerActorWayland *surface_container =
+    META_SURFACE_CONTAINER_ACTOR_WAYLAND (cullable);
+  ClutterActor *actor = CLUTTER_ACTOR (cullable);
+  MetaWindowActor *window_actor;
+  float width, height;
+  graphene_point3d_t verts[4];
+  int geometry_scale;
+
+  clutter_actor_get_size (actor, &width, &height);
+  clutter_actor_get_abs_allocation_vertices (actor, verts);
+
+  window_actor = surface_container->window_actor;
+  geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
+
+  return meta_actor_vertices_are_untransformed (verts,
+                                                width * geometry_scale,
+                                                height * geometry_scale,
+                                                NULL);
+}
+
+static void
+surface_container_reset_culling (MetaCullable *cullable)
+{
+  meta_cullable_reset_culling_children (cullable);
+}
+
+static void
+surface_container_cullable_iface_init (MetaCullableInterface *iface)
+{
+  iface->cull_out = surface_container_cull_out;
+  iface->is_untransformed = surface_container_is_untransformed;
+  iface->reset_culling = surface_container_reset_culling;
+}
+
+static void
+surface_container_dispose (GObject *object)
+{
+  MetaSurfaceContainerActorWayland *self = META_SURFACE_CONTAINER_ACTOR_WAYLAND (object);
+
+  clutter_actor_remove_all_children (CLUTTER_ACTOR (self));
+
+  G_OBJECT_CLASS (meta_surface_container_actor_wayland_parent_class)->dispose (object);
+}
+
+static void
+meta_surface_container_actor_wayland_class_init (MetaSurfaceContainerActorWaylandClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = surface_container_dispose;
+}
+
+static void
+meta_surface_container_actor_wayland_init (MetaSurfaceContainerActorWayland *self)
+{
+}
+
 static gboolean
 get_surface_actor_list (GNode    *node,
                         gpointer  data)
@@ -64,23 +164,23 @@ set_surface_actor_index (GNode    *node,
 {
   MetaWaylandSurface *surface = node->data;
   SurfaceTreeTraverseData *traverse_data = data;
-  ClutterActor *window_actor = CLUTTER_ACTOR (traverse_data->window_actor);
+  ClutterActor *container = traverse_data->surface_container;
   ClutterActor *surface_actor =
     CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface));
 
-  if (clutter_actor_contains (window_actor, surface_actor))
+  if (clutter_actor_contains (container, surface_actor))
     {
-      if (clutter_actor_get_child_at_index (window_actor, traverse_data->index) !=
+      if (clutter_actor_get_child_at_index (container, traverse_data->index) !=
           surface_actor)
         {
-          clutter_actor_set_child_at_index (window_actor,
+          clutter_actor_set_child_at_index (container,
                                             surface_actor,
                                             traverse_data->index);
         }
     }
   else
     {
-      clutter_actor_insert_child_at_index (window_actor,
+      clutter_actor_insert_child_at_index (container,
                                            surface_actor,
                                            traverse_data->index);
     }
@@ -92,6 +192,7 @@ set_surface_actor_index (GNode    *node,
 void
 meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor)
 {
+  MetaWindowActorWayland *self = META_WINDOW_ACTOR_WAYLAND (actor);
   MetaSurfaceActor *surface_actor =
     meta_window_actor_get_surface (actor);
   MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface (
@@ -109,18 +210,21 @@ meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor)
                    get_surface_actor_list,
                    &surface_actors);
 
-  children = clutter_actor_get_children (CLUTTER_ACTOR (actor));
+  children =
+    clutter_actor_get_children (CLUTTER_ACTOR (self->surface_container));
   for (l = children; l; l = l->next)
     {
       ClutterActor *child_actor = l->data;
 
-      if (META_IS_SURFACE_ACTOR_WAYLAND (child_actor) &&
-          !g_list_find (surface_actors, child_actor))
-        clutter_actor_remove_child (CLUTTER_ACTOR (actor), child_actor);
+      if (!g_list_find (surface_actors, child_actor))
+        {
+          clutter_actor_remove_child (CLUTTER_ACTOR (self->surface_container),
+                                      child_actor);
+        }
     }
 
   traverse_data = (SurfaceTreeTraverseData) {
-    .window_actor = actor,
+    .surface_container = CLUTTER_ACTOR (self->surface_container),
     .index = 0,
   };
   g_node_traverse (root_node,
@@ -131,14 +235,48 @@ meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor)
                    &traverse_data);
 }
 
+static cairo_region_t *
+calculate_background_cull_region (MetaWindowActorWayland *self)
+{
+  MetaWindowActor *window_actor = META_WINDOW_ACTOR (self);
+  int geometry_scale;
+  cairo_rectangle_int_t rect;
+
+  geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
+  rect = (cairo_rectangle_int_t) {
+    .x = 0,
+    .y = 0,
+    .width = clutter_actor_get_width (self->background) * geometry_scale,
+    .height = clutter_actor_get_height (self->background) * geometry_scale,
+  };
+
+  return cairo_region_create_rectangle (&rect);
+}
+
 static void
 meta_window_actor_wayland_cull_out (MetaCullable   *cullable,
                                     cairo_region_t *unobscured_region,
                                     cairo_region_t *clip_region)
 {
-  meta_cullable_cull_out_children (cullable,
+  MetaWindowActorWayland *self =
+    META_WINDOW_ACTOR_WAYLAND (cullable);
+
+  meta_cullable_cull_out_children (META_CULLABLE (self),
                                    unobscured_region,
                                    clip_region);
+  if (self->background)
+    {
+      cairo_region_t *background_cull_region;
+
+      background_cull_region = calculate_background_cull_region (self);
+
+      if (unobscured_region)
+        cairo_region_subtract (unobscured_region, background_cull_region);
+      if (clip_region)
+        cairo_region_subtract (clip_region, background_cull_region);
+
+      cairo_region_destroy (background_cull_region);
+    }
 }
 
 static void
@@ -157,19 +295,25 @@ cullable_iface_init (MetaCullableInterface *iface)
 static MetaSurfaceActor *
 meta_window_actor_wayland_get_scanout_candidate (MetaWindowActor *actor)
 {
+  MetaWindowActorWayland *self = META_WINDOW_ACTOR_WAYLAND (actor);
+  ClutterActor *surface_container = CLUTTER_ACTOR (self->surface_container);
   ClutterActor *child_actor;
   MetaSurfaceActor *topmost_surface_actor;
   MetaWindow *window;
 
-  child_actor = clutter_actor_get_last_child (CLUTTER_ACTOR (actor));
-  if (!child_actor || !META_IS_SURFACE_ACTOR_WAYLAND (child_actor))
+  if (clutter_actor_get_last_child (CLUTTER_ACTOR (self)) != surface_container)
+    return NULL;
+
+  child_actor = clutter_actor_get_last_child (surface_container);
+  if (!child_actor)
     return NULL;
 
   topmost_surface_actor = META_SURFACE_ACTOR (child_actor);
 
   window = meta_window_actor_get_meta_window (actor);
-  if (!meta_window_is_fullscreen (window) &&
-      !meta_surface_actor_is_opaque (topmost_surface_actor))
+  if (!meta_surface_actor_is_opaque (topmost_surface_actor) &&
+      !(meta_window_is_fullscreen (window) &&
+        clutter_actor_get_n_children (surface_container) == 1))
     return NULL;
 
   return topmost_surface_actor;
@@ -223,6 +367,13 @@ static void
 meta_window_actor_wayland_set_frozen (MetaWindowActor *actor,
                                       gboolean         frozen)
 {
+  MetaWindowActorWayland *self = META_WINDOW_ACTOR_WAYLAND (actor);
+  ClutterActor *child;
+  ClutterActorIter iter;
+
+  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self->surface_container));
+  while (clutter_actor_iter_next (&iter, &child))
+    meta_surface_actor_set_frozen (META_SURFACE_ACTOR (child), frozen);
 }
 
 static void
@@ -239,36 +390,122 @@ meta_window_actor_wayland_can_freeze_commits (MetaWindowActor *actor)
 static gboolean
 meta_window_actor_wayland_is_single_surface_actor (MetaWindowActor *actor)
 {
-  return clutter_actor_get_n_children (CLUTTER_ACTOR (actor)) == 1;
+  MetaWindowActorWayland *self = META_WINDOW_ACTOR_WAYLAND (actor);
+  ClutterActor *surface_container = CLUTTER_ACTOR (self->surface_container);
+
+  return clutter_actor_get_n_children (surface_container) == 1 &&
+         !self->background;
+}
+
+static gboolean
+maybe_configure_black_background (MetaWindowActorWayland *self,
+                                  float                  *surfaces_width,
+                                  float                  *surfaces_height,
+                                  float                  *background_width,
+                                  float                  *background_height)
+{
+  MetaWindowActor *window_actor = META_WINDOW_ACTOR (self);
+  MetaWindow *window = meta_window_actor_get_meta_window (window_actor);
+  MetaLogicalMonitor *logical_monitor;
+  int geometry_scale;
+  MetaRectangle fullscreen_layout;
+  ClutterActor *child;
+  ClutterActorIter iter;
+  float max_width = 0;
+  float max_height = 0;
+
+  if (!meta_window_wayland_is_acked_fullscreen (META_WINDOW_WAYLAND (window)))
+      return FALSE;
+
+  geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
+
+  logical_monitor = meta_window_get_main_logical_monitor (window);
+  fullscreen_layout = meta_logical_monitor_get_layout (logical_monitor);
+
+  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self->surface_container));
+  while (clutter_actor_iter_next (&iter, &child))
+    {
+      float child_width, child_height;
+
+      clutter_actor_get_size (child, &child_width, &child_height);
+
+      if (META_IS_SURFACE_ACTOR (child) &&
+          meta_surface_actor_is_opaque (META_SURFACE_ACTOR (child)) &&
+          G_APPROX_VALUE (clutter_actor_get_x (child), 0,
+                          CLUTTER_COORDINATE_EPSILON) &&
+          G_APPROX_VALUE (clutter_actor_get_y (child), 0,
+                          CLUTTER_COORDINATE_EPSILON) &&
+          G_APPROX_VALUE (child_width, fullscreen_layout.width,
+                          CLUTTER_COORDINATE_EPSILON) &&
+          G_APPROX_VALUE (child_height, fullscreen_layout.height,
+                          CLUTTER_COORDINATE_EPSILON))
+        return FALSE;
+
+      max_width = MAX (max_width, child_width);
+      max_height = MAX (max_height, child_height);
+    }
+
+  *surfaces_width = max_width;
+  *surfaces_height = max_height;
+  *background_width = window->rect.width / geometry_scale;
+  *background_height = window->rect.height / geometry_scale;
+  return TRUE;
 }
 
 static void
-meta_window_actor_wayland_dispose (GObject *object)
+meta_window_actor_wayland_sync_geometry (MetaWindowActor     *actor,
+                                         const MetaRectangle *actor_rect)
 {
-  MetaWindowActor *window_actor = META_WINDOW_ACTOR (object);
-  MetaSurfaceActor *surface_actor =
-    meta_window_actor_get_surface (window_actor);
-  g_autoptr (GList) children = NULL;
-  GList *l;
+  MetaWindowActorWayland *self = META_WINDOW_ACTOR_WAYLAND (actor);
+  ClutterActor *surface_container = CLUTTER_ACTOR (self->surface_container);
+  MetaWindow *window;
+  float surfaces_width, surfaces_height;
+  float background_width, background_height;
 
-  children = clutter_actor_get_children (CLUTTER_ACTOR (window_actor));
-  for (l = children; l; l = l->next)
+  window = meta_window_actor_get_meta_window (actor);
+  if (window->unmanaging)
+    return;
+
+  if (maybe_configure_black_background (self,
+                                        &surfaces_width, &surfaces_height,
+                                        &background_width, &background_height))
     {
-      ClutterActor *child_actor = l->data;
+      int geometry_scale;
+      int child_actor_width, child_actor_height;
 
-      if (META_IS_SURFACE_ACTOR_WAYLAND (child_actor) &&
-          child_actor != CLUTTER_ACTOR (surface_actor))
-        clutter_actor_remove_child (CLUTTER_ACTOR (window_actor), child_actor);
-    }
+      if (!self->background)
+        {
+          self->background = clutter_actor_new ();
+          clutter_actor_set_background_color (self->background,
+                                              CLUTTER_COLOR_Black);
+          clutter_actor_set_reactive (self->background, TRUE);
+          clutter_actor_insert_child_below (CLUTTER_ACTOR (self),
+                                            self->background,
+                                            NULL);
+        }
+
+      geometry_scale =
+        meta_window_actor_get_geometry_scale (actor);
+      child_actor_width = actor_rect->width / geometry_scale;
+      child_actor_height = actor_rect->height / geometry_scale;
 
-  G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->dispose (object);
+      clutter_actor_set_size (self->background,
+                              background_width, background_height);
+      clutter_actor_set_position (surface_container,
+                                  (child_actor_width - surfaces_width) / 2,
+                                  (child_actor_height - surfaces_height) / 2);
+    }
+  else if (self->background)
+    {
+      clutter_actor_set_position (surface_container, 0, 0);
+      g_clear_pointer (&self->background, clutter_actor_destroy);
+    }
 }
 
 static void
 meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
 {
   MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   window_actor_class->get_scanout_candidate = meta_window_actor_wayland_get_scanout_candidate;
   window_actor_class->assign_surface_actor = meta_window_actor_wayland_assign_surface_actor;
@@ -280,12 +517,15 @@ meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
   window_actor_class->set_frozen = meta_window_actor_wayland_set_frozen;
   window_actor_class->update_regions = meta_window_actor_wayland_update_regions;
   window_actor_class->can_freeze_commits = meta_window_actor_wayland_can_freeze_commits;
+  window_actor_class->sync_geometry = meta_window_actor_wayland_sync_geometry;
   window_actor_class->is_single_surface_actor = meta_window_actor_wayland_is_single_surface_actor;
-
-  object_class->dispose = meta_window_actor_wayland_dispose;
 }
 
 static void
 meta_window_actor_wayland_init (MetaWindowActorWayland *self)
 {
+  self->surface_container = surface_container_new (META_WINDOW_ACTOR (self));
+
+  clutter_actor_add_child (CLUTTER_ACTOR (self),
+                           CLUTTER_ACTOR (self->surface_container));
 }
diff --git a/src/compositor/meta-window-actor-wayland.h b/src/compositor/meta-window-actor-wayland.h
index 4f38d41631..56c3f1241b 100644
--- a/src/compositor/meta-window-actor-wayland.h
+++ b/src/compositor/meta-window-actor-wayland.h
@@ -31,6 +31,12 @@ G_DECLARE_FINAL_TYPE (MetaWindowActorWayland,
                       META, WINDOW_ACTOR_WAYLAND,
                       MetaWindowActor)
 
+#define META_TYPE_SURFACE_CONTAINER_ACTOR_WAYLAND (meta_surface_container_actor_wayland_get_type())
+G_DECLARE_FINAL_TYPE (MetaSurfaceContainerActorWayland,
+                      meta_surface_container_actor_wayland,
+                      META, SURFACE_CONTAINER_ACTOR_WAYLAND,
+                      ClutterActor)
+
 void meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor);
 
 #endif /*META_WINDOW_ACTOR_WAYLAND_H */
diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c
index 158b912191..4f01a2c9bf 100644
--- a/src/compositor/meta-window-actor-x11.c
+++ b/src/compositor/meta-window-actor-x11.c
@@ -1511,6 +1511,7 @@ meta_window_actor_x11_set_frozen (MetaWindowActor *actor,
     return;
 
   actor_x11->is_frozen = frozen;
+  meta_surface_actor_set_frozen (meta_window_actor_get_surface (actor), frozen);
 
   if (frozen)
     meta_window_x11_freeze_commits (window);
@@ -1538,6 +1539,12 @@ meta_window_actor_x11_is_single_surface_actor (MetaWindowActor *actor)
   return clutter_actor_get_n_children (CLUTTER_ACTOR (actor)) == 1;
 }
 
+static void
+meta_window_actor_x11_sync_geometry (MetaWindowActor     *actor,
+                                     const MetaRectangle *actor_rect)
+{
+}
+
 static void
 meta_window_actor_x11_set_property (GObject      *object,
                                     guint         prop_id,
@@ -1672,6 +1679,9 @@ meta_window_actor_x11_dispose (GObject *object)
     {
       g_clear_signal_handler (&actor_x11->repaint_scheduled_id, surface_actor);
       g_clear_signal_handler (&actor_x11->size_changed_id, surface_actor);
+
+      clutter_actor_remove_child (CLUTTER_ACTOR (object),
+                                  CLUTTER_ACTOR (surface_actor));
     }
 
   g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy);
@@ -1714,6 +1724,7 @@ meta_window_actor_x11_class_init (MetaWindowActorX11Class *klass)
   window_actor_class->set_frozen = meta_window_actor_x11_set_frozen;
   window_actor_class->update_regions = meta_window_actor_x11_update_regions;
   window_actor_class->can_freeze_commits = meta_window_actor_x11_can_freeze_commits;
+  window_actor_class->sync_geometry = meta_window_actor_x11_sync_geometry;
   window_actor_class->is_single_surface_actor = meta_window_actor_x11_is_single_surface_actor;
 
   actor_class->paint = meta_window_actor_x11_paint;
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 85309eeb64..fcf97ae85f 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -270,16 +270,6 @@ static void
 meta_window_actor_set_frozen (MetaWindowActor *self,
                               gboolean         frozen)
 {
-  ClutterActor *child;
-  ClutterActorIter iter;
-
-  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self));
-  while (clutter_actor_iter_next (&iter, &child))
-    {
-      if (META_IS_SURFACE_ACTOR (child))
-        meta_surface_actor_set_frozen (META_SURFACE_ACTOR (child), frozen);
-    }
-
   META_WINDOW_ACTOR_GET_CLASS (self)->set_frozen (self, frozen);
 }
 
@@ -464,12 +454,7 @@ meta_window_actor_dispose (GObject *object)
 
   g_clear_object (&priv->window);
 
-  if (priv->surface)
-    {
-      clutter_actor_remove_child (CLUTTER_ACTOR (self),
-                                  CLUTTER_ACTOR (priv->surface));
-      g_clear_object (&priv->surface);
-    }
+  g_clear_object (&priv->surface);
 
   G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
 }
@@ -861,6 +846,8 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
   if (meta_window_actor_is_frozen (self) && !did_placement)
     return META_WINDOW_ACTOR_CHANGE_POSITION | META_WINDOW_ACTOR_CHANGE_SIZE;
 
+  META_WINDOW_ACTOR_GET_CLASS (self)->sync_geometry (self, &actor_rect);
+
   if (clutter_actor_has_allocation (actor))
     {
       ClutterActorBox box;
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index dcd9d5d393..ed6a7cfdbd 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -267,14 +267,13 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
   configured_rect.width = constrained_rect.width;
   configured_rect.height = constrained_rect.height;
 
-  /* For wayland clients, the size is completely determined by the client,
-   * and while this allows to avoid some trickery with frames and the resulting
-   * lagging, we also need to insist a bit when the constraints would apply
-   * a different size than the client decides.
+  /* The size is determined by the client, except when the client is explicitly
+   * fullscreen, in which case the compositor compensates for the size
+   * difference between what surface configuration the client provided, and the
+   * size of the area a fullscreen window state is expected to fill.
    *
-   * Note that this is not generally a problem for normal toplevel windows (the
-   * constraints don't see the size hints, or just change the position), but
-   * it can be for maximized or fullscreen.
+   * For non-explicit-fullscreen states, since the size is always determined by
+   * the client, the we cannot use the size calculated by the constraints.
    */
 
   if (flags & META_MOVE_RESIZE_FORCE_MOVE)
@@ -283,16 +282,26 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
     }
   else if (flags & META_MOVE_RESIZE_WAYLAND_FINISH_MOVE_RESIZE)
     {
-      /* This is a call to wl_surface_commit(), ignore the constrained_rect and
-       * update the real client size to match the buffer size.
-       */
+      MetaWaylandWindowConfiguration *configuration;
+      int new_width, new_height;
 
-      if (window->rect.width != unconstrained_rect.width ||
-          window->rect.height != unconstrained_rect.height)
+      configuration = wl_window->last_acked_configuration;
+      if (configuration && configuration->is_fullscreen)
+        {
+          new_width = constrained_rect.width;
+          new_height = constrained_rect.height;
+        }
+      else
+        {
+          new_width = unconstrained_rect.width;
+          new_height = unconstrained_rect.height;
+        }
+      if (window->rect.width != new_width ||
+          window->rect.height != new_height)
         {
           *result |= META_MOVE_RESIZE_RESULT_RESIZED;
-          window->rect.width = unconstrained_rect.width;
-          window->rect.height = unconstrained_rect.height;
+          window->rect.width = new_width;
+          window->rect.height = new_height;
         }
 
       window->buffer_rect.width =
@@ -1290,3 +1299,10 @@ meta_window_wayland_get_max_size (MetaWindow *window,
   scale = 1.0 / (float) meta_window_wayland_get_geometry_scale (window);
   scale_size (width, height, scale);
 }
+
+gboolean
+meta_window_wayland_is_acked_fullscreen (MetaWindowWayland *wl_window)
+{
+  return (wl_window->last_acked_configuration &&
+          wl_window->last_acked_configuration->is_fullscreen);
+}
diff --git a/src/wayland/meta-window-wayland.h b/src/wayland/meta-window-wayland.h
index 154e9a6f21..709edc991e 100644
--- a/src/wayland/meta-window-wayland.h
+++ b/src/wayland/meta-window-wayland.h
@@ -81,4 +81,6 @@ gboolean meta_window_wayland_is_resize (MetaWindowWayland *wl_window,
                                         int                width,
                                         int                height);
 
+gboolean meta_window_wayland_is_acked_fullscreen (MetaWindowWayland *wl_window);
+
 #endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]