Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions src/backends/native/meta-cursor-renderer-native.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ typedef struct _MetaCursorNativeGpuState
guint active_bo;
MetaCursorGbmBoState pending_bo_state;
struct gbm_bo *bos[HW_CURSOR_BUFFER_COUNT];
int widths[HW_CURSOR_BUFFER_COUNT];
int heights[HW_CURSOR_BUFFER_COUNT];
} MetaCursorNativeGpuState;

typedef struct _MetaCursorNativePrivate
Expand Down Expand Up @@ -209,7 +211,9 @@ get_active_cursor_sprite_gbm_bo (MetaCursorNativeGpuState *cursor_gpu_state)
static void
set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
MetaGpuKms *gpu_kms,
struct gbm_bo *bo)
struct gbm_bo *bo,
int width,
int height)
{
MetaCursorNativePrivate *cursor_priv;
MetaCursorNativeGpuState *cursor_gpu_state;
Expand All @@ -220,6 +224,8 @@ set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,

pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
cursor_gpu_state->bos[pending_bo] = bo;
cursor_gpu_state->widths[pending_bo] = width;
cursor_gpu_state->heights[pending_bo] = height;
cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_SET;
}

Expand Down Expand Up @@ -260,8 +266,6 @@ set_crtc_cursor (MetaCursorRendererNative *native,
meta_cursor_renderer_native_get_instance_private (native);
MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
MetaCursorNativeGpuState *cursor_gpu_state =
get_cursor_gpu_state (cursor_priv, gpu_kms);
MetaKmsCrtc *kms_crtc;
Expand All @@ -278,9 +282,20 @@ set_crtc_cursor (MetaCursorRendererNative *native,
MetaKmsPlaneAssignment *plane_assignment;

if (cursor_gpu_state->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
bo = get_pending_cursor_sprite_gbm_bo (cursor_gpu_state);
{
guint pending_bo;

pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
bo = get_pending_cursor_sprite_gbm_bo (cursor_gpu_state);
cursor_width = cursor_gpu_state->widths[pending_bo];
cursor_height = cursor_gpu_state->heights[pending_bo];
}
else
bo = get_active_cursor_sprite_gbm_bo (cursor_gpu_state);
{
bo = get_active_cursor_sprite_gbm_bo (cursor_gpu_state);
cursor_width = cursor_gpu_state->widths[cursor_gpu_state->active_bo];
cursor_height = cursor_gpu_state->heights[cursor_gpu_state->active_bo];
}

kms_crtc = meta_crtc_kms_get_kms_crtc (crtc);
kms_device = meta_kms_crtc_get_device (kms_crtc);
Expand All @@ -289,8 +304,6 @@ set_crtc_cursor (MetaCursorRendererNative *native,

handle = gbm_bo_get_handle (bo);

cursor_width = cursor_renderer_gpu_data->cursor_width;
cursor_height = cursor_renderer_gpu_data->cursor_height;
src_rect = (MetaFixed16Rectangle) {
.x = meta_fixed_16_from_int (0),
.y = meta_fixed_16_from_int (0),
Expand Down Expand Up @@ -1109,6 +1122,8 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite)
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
gbm_bo_destroy);
cursor_gpu_state->widths[pending_bo] = 0;
cursor_gpu_state->heights[pending_bo] = 0;
cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
}
}
Expand Down Expand Up @@ -1194,10 +1209,10 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
struct gbm_bo *bo;
uint8_t buf[4 * cursor_width * cursor_height];
uint8_t buf[4 * width * height];
uint i;

bo = gbm_bo_create (gbm_device, cursor_width, cursor_height,
bo = gbm_bo_create (gbm_device, width, height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo)
{
Expand All @@ -1207,16 +1222,17 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,

memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
if (gbm_bo_write (bo, buf, cursor_width * cursor_height * 4) != 0)
memcpy (buf + i * 4 * width, pixels + i * rowstride, width * 4);
if (gbm_bo_write (bo, buf, width * height * 4) != 0)
{
meta_warning ("Failed to write cursors buffer data: %s",
g_strerror (errno));
gbm_bo_destroy (bo);
return;
}

set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo,
width, height);
}
else
{
Expand Down Expand Up @@ -1374,7 +1390,7 @@ load_scaled_and_transformed_cursor_sprite (MetaCursorRendererNative *native,
cursor_sprite,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface),
cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
cairo_image_surface_get_stride (surface),
gbm_format);

Expand Down Expand Up @@ -1526,7 +1542,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,

unset_can_preprocess (cursor_sprite);

set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo,
width, height);
}
}
#endif
Expand Down
7 changes: 6 additions & 1 deletion src/compositor/compositor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,12 @@ meta_compositor_size_change_window (MetaCompositor *compositor,
MetaRectangle *old_frame_rect,
MetaRectangle *old_buffer_rect)
{
MetaWindowActor *window_actor = meta_window_actor_from_window (window);
MetaWindowActor *window_actor;

if (window->compositor_skip_size_change)
return;

window_actor = meta_window_actor_from_window (window);

meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect);
}
Expand Down
6 changes: 6 additions & 0 deletions src/core/window-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ struct _MetaWindow
*/
guint pending_compositor_effect : 4; /* MetaCompEffect */

/* Suppress compositor size-change effects for a synthetic state
* transition (e.g. an immediate unmaximize/maximize toggle) where there
* is no visible resize to animate.
*/
guint compositor_skip_size_change : 1;

/* Iconic is the state in WM_STATE; happens for workspaces/shading
* in addition to minimize
*/
Expand Down
24 changes: 20 additions & 4 deletions src/wayland/meta-wayland-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,26 @@ surface_process_damage (MetaWaylandSurface *surface,
}
else
{
src_rect = (graphene_rect_t) {
.size.width = surface_rect.width * surface->scale,
.size.height = surface_rect.height * surface->scale,
};
if (surface->viewport.has_dst_size)
{
/* When wp_viewport sets a destination without a source rect, the
* viewport maps the full buffer to the dst size. Surface damage
* (from wl_surface.damage) is in dst/logical coordinates and
* scaled_region is in dst * surface->scale coordinates. Use the
* full buffer as the source rectangle so meta_region_crop_and_scale()
* maps damage through the viewport transform to buffer coordinates. */
src_rect = (graphene_rect_t) {
.size.width = buffer_rect.width,
.size.height = buffer_rect.height,
};
Comment thread
Copilot marked this conversation as resolved.
}
else
{
src_rect = (graphene_rect_t) {
.size.width = surface_rect.width * surface->scale,
.size.height = surface_rect.height * surface->scale,
};
}
}
viewport_region = meta_region_crop_and_scale (scaled_region,
&src_rect,
Expand Down
30 changes: 30 additions & 0 deletions src/wayland/meta-wayland-xdg-shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ xdg_toplevel_set_maximized (struct wl_client *client,
{
MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
MetaWindow *window;
gboolean was_maximized;

window = meta_wayland_surface_get_window (surface);
if (!window)
Expand All @@ -446,8 +447,23 @@ xdg_toplevel_set_maximized (struct wl_client *client,
if (!window->has_maximize_func)
return;

was_maximized = META_WINDOW_MAXIMIZED (window);

meta_window_force_placement (window, TRUE);

/* If the window has not yet completed a configure-ack-commit cycle its
* renderer is not yet ready. Schedule a NOT_MAXIMIZED -> MAXIMIZED
* transition so clients that rely on an explicit transition update their
* maximize state. */
if (!was_maximized)
meta_window_wayland_schedule_maximize_transition (window);

meta_window_maximize (window, META_MAXIMIZE_BOTH);

/* meta_window_maximize() is a no-op when already maximized, but the client
* still expects a configure in reply. */
if (was_maximized)
meta_window_wayland_maybe_send_configure (window);
}

static void
Expand Down Expand Up @@ -1718,8 +1734,22 @@ meta_wayland_xdg_surface_post_apply_state (MetaWaylandSurfaceRole *surface_role
meta_wayland_shell_surface_determine_geometry (shell_surface,
&pending->new_geometry,
&priv->geometry);

if (priv->geometry.width == 0 || priv->geometry.height == 0)
{
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);

/* A client may commit window geometry before attaching its first
* buffer (e.g. answering an initial maximized configure). The
* geometry can't be resolved against an empty surface; defer
* silently until a buffer arrives rather than warning. */
if (!surface->buffer_ref->buffer)
{
priv->has_set_geometry = TRUE;
return;
}

g_warning ("Invalid window geometry for xdg_surface@%d. Ignoring "
"for now, but this will result in client termination "
"in the future.",
Expand Down
96 changes: 96 additions & 0 deletions src/wayland/meta-window-wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ struct _MetaWindowWayland

gboolean has_been_shown;

/* Set when a client requests maximization before it has completed a
* configure-ack-commit cycle. Cleared and consumed in finish_move_resize to
* force a NOT_MAXIMIZED -> MAXIMIZED transition for clients that only update
* their maximize state after seeing an explicit state transition. */
gboolean needs_maximize_transition;

/* Becomes TRUE the first time the client acks a tracked configure. */
gboolean client_has_acked_configure;

cairo_surface_t *icon;
cairo_surface_t *mini_icon;
gboolean icon_dirty;
Expand Down Expand Up @@ -995,6 +1004,7 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
MetaMoveResizeFlags flags;
MetaWaylandWindowConfiguration *acked_configuration;
gboolean is_window_being_resized;
gboolean needs_reconfigure = FALSE;

/* new_geom is in the logical pixel coordinate space, but MetaWindow wants its
* rects to represent what in turn will end up on the stage, i.e. we need to
Expand All @@ -1020,6 +1030,9 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,

acked_configuration = acquire_acked_configuration (wl_window, pending);

if (acked_configuration)
wl_window->client_has_acked_configure = TRUE;

/* x/y are ignored when we're doing interactive resizing */
is_window_being_resized = (meta_grab_op_is_resizing (display->grab_op) &&
display->grab_window == window);
Expand Down Expand Up @@ -1067,6 +1080,42 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
rect.x += dx;
rect.y += dy;

/* For fixed-size states the compositor controls the size; the client must
* use what was configured. If it committed different dimensions (e.g. a
* stale saved size from a previous session), override with the expected
* size so we don't corrupt last_sent_rect and trigger a wrong configure. */
if (META_WINDOW_MAXIMIZED (window) ||
meta_window_is_fullscreen (window) ||
window->tile_mode != META_TILE_NONE)
{
int expected_w, expected_h;

if (acked_configuration && acked_configuration->has_size)
{
expected_w = acked_configuration->width;
expected_h = acked_configuration->height;
}
else if (wl_window->has_last_sent_configuration)
{
expected_w = wl_window->last_sent_rect.width;
expected_h = wl_window->last_sent_rect.height;
}
else
{
expected_w = new_geom.width;
expected_h = new_geom.height;
}

if (new_geom.width != expected_w || new_geom.height != expected_h)
{
rect.x = wl_window->last_sent_rect.x;
rect.y = wl_window->last_sent_rect.y;
rect.width = expected_w;
rect.height = expected_h;
needs_reconfigure = TRUE;
}
}

if (rect.x != window->rect.x || rect.y != window->rect.y)
flags |= META_MOVE_RESIZE_MOVE_ACTION;

Expand All @@ -1085,6 +1134,33 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
gravity = META_GRAVITY_STATIC;
meta_window_move_resize_internal (window, flags, gravity, rect);

/* Force a NOT_MAXIMIZED -> MAXIMIZED configure transition for clients that
* need it to fire their 'maximize' event. Triggered when the client requested
* maximization before completing its first configure-ack-commit cycle. */
{
gboolean do_maximize_transition =
META_WINDOW_MAXIMIZED (window) && wl_window->needs_maximize_transition;

wl_window->needs_maximize_transition = FALSE;

if (do_maximize_transition)
{
/* This toggle exists only to emit a state transition; the window is
* already maximized and stays maximized, so there is nothing to
* animate. Suppress the compositor size-change effects, whose paired
* synchronous firing would otherwise corrupt the actor's size-change
* accounting before either effect gets a chance to run. */
window->compositor_skip_size_change = TRUE;
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
window->compositor_skip_size_change = FALSE;
}
else if (needs_reconfigure)
{
surface_state_changed (window);
}
}

g_clear_pointer (&acked_configuration, meta_wayland_window_configuration_free);
}

Expand Down Expand Up @@ -1279,3 +1355,23 @@ meta_window_wayland_get_max_size (MetaWindow *window,
scale = 1.0 / (float) meta_window_wayland_get_geometry_scale (window);
scale_size (width, height, scale);
}

void
meta_window_wayland_maybe_send_configure (MetaWindow *window)
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);

if (!wl_window->has_last_sent_configuration)
return;

surface_state_changed (window);
}

void
meta_window_wayland_schedule_maximize_transition (MetaWindow *window)
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);

if (!wl_window->client_has_acked_configure)
wl_window->needs_maximize_transition = TRUE;
}
3 changes: 3 additions & 0 deletions src/wayland/meta-window-wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,7 @@ void meta_window_wayland_set_custom_icon (MetaWindow *window,
cairo_surface_t *icon,
cairo_surface_t *mini_icon);

void meta_window_wayland_maybe_send_configure (MetaWindow *window);
void meta_window_wayland_schedule_maximize_transition (MetaWindow *window);

#endif
Loading