mutter/src/wayland/meta-wayland-shell-surface.c

347 lines
11 KiB
C
Raw Normal View History

/*
* Copyright (C) 2012,2013 Intel Corporation
* Copyright (C) 2013-2017 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include "config.h"
#include "wayland/meta-wayland-shell-surface.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "compositor/meta-window-actor-private.h"
#include "compositor/meta-window-actor-wayland.h"
#include "wayland/meta-wayland-actor-surface.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-subsurface.h"
#include "wayland/meta-wayland-surface.h"
#include "wayland/meta-window-wayland.h"
typedef struct _MetaWaylandShellSurfacePrivate
{
MetaWindow *window;
gulong unmanaging_handler_id;
} MetaWaylandShellSurfacePrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandShellSurface,
meta_wayland_shell_surface,
META_TYPE_WAYLAND_ACTOR_SURFACE)
void
meta_wayland_shell_surface_calculate_geometry (MetaWaylandShellSurface *shell_surface,
MetaRectangle *out_geometry)
{
MetaWaylandSurfaceRole *surface_role =
META_WAYLAND_SURFACE_ROLE (shell_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaRectangle geometry;
MetaWaylandSurface *subsurface_surface;
geometry = (MetaRectangle) {
.width = meta_wayland_surface_get_width (surface),
.height = meta_wayland_surface_get_height (surface),
};
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 14:01:37 +00:00
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state,
subsurface_surface)
{
MetaWaylandSubsurface *subsurface;
subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
meta_wayland_subsurface_union_geometry (subsurface,
0, 0,
&geometry);
}
*out_geometry = geometry;
}
void
meta_wayland_shell_surface_determine_geometry (MetaWaylandShellSurface *shell_surface,
MetaRectangle *set_geometry,
MetaRectangle *out_geometry)
{
MetaRectangle bounding_geometry = { 0 };
MetaRectangle intersected_geometry = { 0 };
meta_wayland_shell_surface_calculate_geometry (shell_surface,
&bounding_geometry);
meta_rectangle_intersect (set_geometry, &bounding_geometry,
&intersected_geometry);
*out_geometry = intersected_geometry;
}
static void
clear_window (MetaWaylandShellSurface *shell_surface)
{
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
MetaWaylandSurfaceRole *surface_role =
META_WAYLAND_SURFACE_ROLE (shell_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaSurfaceActor *surface_actor;
if (!priv->window)
return;
g_clear_signal_handler (&priv->unmanaging_handler_id,
priv->window);
priv->window = NULL;
surface_actor = meta_wayland_surface_get_actor (surface);
if (surface_actor)
clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), FALSE);
meta_wayland_surface_notify_unmapped (surface);
}
static void
window_unmanaging (MetaWindow *window,
MetaWaylandShellSurface *shell_surface)
{
clear_window (shell_surface);
}
void
meta_wayland_shell_surface_set_window (MetaWaylandShellSurface *shell_surface,
MetaWindow *window)
{
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
MetaWaylandSurfaceRole *surface_role =
META_WAYLAND_SURFACE_ROLE (shell_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaSurfaceActor *surface_actor;
g_assert (!priv->window);
priv->window = window;
surface_actor = meta_wayland_surface_get_actor (surface);
if (surface_actor)
clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), TRUE);
priv->unmanaging_handler_id =
g_signal_connect (window,
"unmanaging",
G_CALLBACK (window_unmanaging),
shell_surface);
meta_window_update_monitor (window, META_WINDOW_UPDATE_MONITOR_FLAGS_NONE);
}
void
meta_wayland_shell_surface_configure (MetaWaylandShellSurface *shell_surface,
MetaWaylandWindowConfiguration *configuration)
{
MetaWaylandShellSurfaceClass *shell_surface_class =
META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
shell_surface_class->configure (shell_surface, configuration);
}
void
meta_wayland_shell_surface_ping (MetaWaylandShellSurface *shell_surface,
uint32_t serial)
{
MetaWaylandShellSurfaceClass *shell_surface_class =
META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
shell_surface_class->ping (shell_surface, serial);
}
void
meta_wayland_shell_surface_close (MetaWaylandShellSurface *shell_surface)
{
MetaWaylandShellSurfaceClass *shell_surface_class =
META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
shell_surface_class->close (shell_surface);
}
void
meta_wayland_shell_surface_managed (MetaWaylandShellSurface *shell_surface,
MetaWindow *window)
{
MetaWaylandShellSurfaceClass *shell_surface_class =
META_WAYLAND_SHELL_SURFACE_GET_CLASS (shell_surface);
shell_surface_class->managed (shell_surface, window);
}
static void
meta_wayland_shell_surface_assigned (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
surface->dnd.funcs = meta_wayland_data_device_get_drag_dest_funcs ();
surface_role_class->assigned (surface_role);
}
static void
meta_wayland_shell_surface_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface_role);
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
if (pending->newly_attached &&
wayland/surface: Overhaul handling of buffer use count Move the use count from a separate MetaWaylandBufferRef struct to the MetaWaylandBuffer class, and remove the former. The buffer use count is now incremented already in meta_wayland_surface_commit, since the Wayland protocol defines the buffer to be in use by the compositor at that point. If the buffer attachment ends up being dropped again before it is applied to the surface state (e.g. because another buffer is committed to a synchronized sub-surface before the parent surface is committed), the use count is now decremented, and a buffer release event is sent if the use count drops to 0. Buffer release events were previously incorrectly not sent under these circumstances. Test case: Run the weston-subsurfaces demo with the -r1 and/or -t1 command line parameter. Resize the window. Before this change, weston-subsurfaces would freeze or abort after a few resize operations, because mutter failed to send release events and the client ran out of usable buffers. v2: * Handle NULL priv->buffer_ref in meta_wayland_cursor_surface_apply_state. v3: * Remove MetaWaylandBufferRef altogether, move the use count tracking to MetaWaylandBuffer itself. Much simpler, and doesn't run into lifetime issues when mutter shuts down. v4: * Warn if use count isn't 0 in meta_wayland_buffer_finalize. * Keep pending_buffer_resource_destroyed for attached but not yet committed buffers. If the client attaches a buffer and then destroys it before commit, we ignore the buffer attachement, same as before this MR. v5: * Rebase on top of new commit which splits up surface->texture. * MetaWaylandSurfaceState::buffer can only be non-NULL if ::newly_attached is TRUE, simplify accordingly. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2022-06-22 16:43:11 +00:00
!surface->buffer &&
priv->window)
meta_window_queue (priv->window, META_QUEUE_CALC_SHOWING);
}
static MetaWindow *
meta_wayland_shell_surface_get_window (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface_role);
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
return priv->window;
}
static void
meta_wayland_shell_surface_notify_subsurface_state_changed (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface_role);
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
MetaWindow *window;
MetaWindowActor *window_actor;
window = priv->window;
if (!window)
return;
window_actor = meta_window_actor_from_window (window);
meta_window_actor_wayland_rebuild_surface_tree (window_actor);
}
static int
meta_wayland_shell_surface_get_geometry_scale (MetaWaylandActorSurface *actor_surface)
{
MetaWaylandSurfaceRole *surface_role =
META_WAYLAND_SURFACE_ROLE (actor_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaContext *context =
meta_wayland_compositor_get_context (surface->compositor);
MetaBackend *backend = meta_context_get_backend (context);
MetaWindow *toplevel_window;
toplevel_window = meta_wayland_surface_get_toplevel_window (surface);
if (meta_backend_is_stage_views_scaled (backend) ||
!toplevel_window)
return 1;
else
return meta_window_wayland_get_geometry_scale (toplevel_window);
}
static void
meta_wayland_shell_surface_sync_actor_state (MetaWaylandActorSurface *actor_surface)
{
MetaWaylandSurfaceRole *surface_role =
META_WAYLAND_SURFACE_ROLE (actor_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandActorSurfaceClass *actor_surface_class =
META_WAYLAND_ACTOR_SURFACE_CLASS (meta_wayland_shell_surface_parent_class);
MetaWindow *toplevel_window;
toplevel_window = meta_wayland_surface_get_toplevel_window (surface);
if (!toplevel_window)
return;
actor_surface_class->sync_actor_state (actor_surface);
}
void
meta_wayland_shell_surface_destroy_window (MetaWaylandShellSurface *shell_surface)
{
MetaWaylandShellSurfacePrivate *priv =
meta_wayland_shell_surface_get_instance_private (shell_surface);
MetaWindow *window;
MetaDisplay *display;
uint32_t timestamp;
window = priv->window;
if (!window)
return;
display = meta_window_get_display (window);
timestamp = meta_display_get_current_time_roundtrip (display);
meta_window_unmanage (window, timestamp);
g_assert (!priv->window);
}
static void
meta_wayland_shell_surface_finalize (GObject *object)
{
MetaWaylandShellSurface *shell_surface = META_WAYLAND_SHELL_SURFACE (object);
meta_wayland_shell_surface_destroy_window (shell_surface);
G_OBJECT_CLASS (meta_wayland_shell_surface_parent_class)->finalize (object);
}
static void
meta_wayland_shell_surface_init (MetaWaylandShellSurface *role)
{
}
static void
meta_wayland_shell_surface_class_init (MetaWaylandShellSurfaceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
MetaWaylandActorSurfaceClass *actor_surface_class =
META_WAYLAND_ACTOR_SURFACE_CLASS (klass);
object_class->finalize = meta_wayland_shell_surface_finalize;
surface_role_class->assigned = meta_wayland_shell_surface_assigned;
surface_role_class->pre_apply_state =
meta_wayland_shell_surface_surface_pre_apply_state;
surface_role_class->notify_subsurface_state_changed =
meta_wayland_shell_surface_notify_subsurface_state_changed;
surface_role_class->get_window = meta_wayland_shell_surface_get_window;
actor_surface_class->get_geometry_scale =
meta_wayland_shell_surface_get_geometry_scale;
actor_surface_class->sync_actor_state =
meta_wayland_shell_surface_sync_actor_state;
}