diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index a2b8eb194..477d0b3a5 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 a135d2805..3abe588c9 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; + + 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); } - - G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->dispose (object); } 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 4f38d4163..56c3f1241 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 158b91219..4f01a2c9b 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 85309eeb6..fcf97ae85 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 dcd9d5d39..ed6a7cfdb 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 154e9a6f2..709edc991 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