window: Set the initial suspend state to 'hidden'

Instead of initializing to 'suspended', which will send the `SUSPENDED`
xdg_toplevel state, set it to hidden at first. If the window is placed
on an inactive workspace, it'll eventually enter the 'suspended' state,
but will have had some time in non-suspended state to get map, even if
not visibly.

This fixes inital suspended state when mapping a window maximized.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3229
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3475>
This commit is contained in:
Jonas Ådahl 2024-04-17 16:38:25 +02:00 committed by Marge Bot
parent cf176df006
commit 73990f011f
4 changed files with 269 additions and 9 deletions

View File

@ -168,6 +168,8 @@ static MetaWindow * meta_window_find_tile_match (MetaWindow *window,
MetaTileMode mode);
static void update_edge_constraints (MetaWindow *window);
static void set_hidden_suspended_state (MetaWindow *window);
static void initable_iface_init (GInitableIface *initable_iface);
typedef struct _MetaWindowPrivate
@ -713,9 +715,6 @@ meta_window_class_init (MetaWindowClass *klass)
static void
meta_window_init (MetaWindow *window)
{
MetaWindowPrivate *priv = meta_window_get_instance_private (window);
priv->suspend_state = META_WINDOW_SUSPEND_STATE_SUSPENDED;
window->stamp = next_window_stamp++;
meta_prefs_add_listener (prefs_changed_callback, window);
window->is_alive = TRUE;
@ -991,6 +990,7 @@ static void
meta_window_constructed (GObject *object)
{
MetaWindow *window = META_WINDOW (object);
MetaWindowPrivate *priv = meta_window_get_instance_private (window);
MetaDisplay *display = window->display;
MetaContext *context = meta_display_get_context (display);
MetaBackend *backend = meta_context_get_backend (context);
@ -1343,6 +1343,11 @@ meta_window_constructed (GObject *object)
!window->initially_iconic)
unminimize_window_and_all_transient_parents (window);
/* There is a slim chance we'll hit time out before a extremely slow client
* managed to become active, but unlikely enough. */
priv->suspend_state = META_WINDOW_SUSPEND_STATE_HIDDEN;
set_hidden_suspended_state (window);
window->constructing = FALSE;
}
@ -2164,6 +2169,19 @@ enter_suspend_state_cb (gpointer user_data)
return G_SOURCE_REMOVE;
}
static void
set_hidden_suspended_state (MetaWindow *window)
{
MetaWindowPrivate *priv = meta_window_get_instance_private (window);
priv->suspend_state = META_WINDOW_SUSPEND_STATE_HIDDEN;
g_return_if_fail (!priv->suspend_timoeut_id);
priv->suspend_timoeut_id =
g_timeout_add_seconds (SUSPEND_HIDDEN_TIMEOUT_S,
enter_suspend_state_cb,
window);
}
static void
update_suspend_state (MetaWindow *window)
{
@ -2181,13 +2199,8 @@ update_suspend_state (MetaWindow *window)
}
else if (priv->suspend_state == META_WINDOW_SUSPEND_STATE_ACTIVE)
{
priv->suspend_state = META_WINDOW_SUSPEND_STATE_HIDDEN;
set_hidden_suspended_state (window);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_SUSPEND_STATE]);
g_return_if_fail (!priv->suspend_timoeut_id);
priv->suspend_timoeut_id =
g_timeout_add_seconds (SUSPEND_HIDDEN_TIMEOUT_S,
enter_suspend_state_cb,
window);
}
}

View File

@ -81,6 +81,9 @@ wayland_test_clients = [
{
'name': 'xdg-toplevel-bounds',
},
{
'name': 'xdg-toplevel-suspended',
},
{
'name': 'ycbcr',
},

View File

@ -0,0 +1,175 @@
/*
* Copyright (C) 2024 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#include <wayland-client.h>
#include "wayland-test-client-utils.h"
enum
{
XDG_TOPLEVEL_SUSPENDED_COMMAND_NEXT_WORKSPACE = 0,
XDG_TOPLEVEL_SUSPENDED_COMMAND_PREV_WORKSPACE = 1,
XDG_TOPLEVEL_SUSPENDED_COMMAND_ACTIVATE_WINDOW = 2,
};
static void
wait_for_state (WaylandSurface *surface,
enum xdg_toplevel_state state)
{
while (!wayland_surface_has_state (surface, state))
wayland_display_dispatch (surface->display);
}
static void
wait_for_no_state (WaylandSurface *surface,
enum xdg_toplevel_state state)
{
while (wayland_surface_has_state (surface, state))
wayland_display_dispatch (surface->display);
}
static void
test_floating (WaylandDisplay *display)
{
g_autoptr (WaylandSurface) surface = NULL;
g_debug ("Testing suspended state when mapping floating");
surface = wayland_surface_new (display, __func__, 100, 100, 0xffffffff);
wl_surface_commit (surface->wl_surface);
wait_for_window_shown (display, surface->wl_surface);
g_assert_false (wayland_surface_has_state (surface,
XDG_TOPLEVEL_STATE_SUSPENDED));
}
static void
test_maximized (WaylandDisplay *display)
{
g_autoptr (WaylandSurface) surface = NULL;
g_debug ("Testing suspended state when mapping maximized");
surface = wayland_surface_new (display, __func__, 100, 100, 0xffffffff);
xdg_toplevel_set_maximized (surface->xdg_toplevel);
wl_surface_commit (surface->wl_surface);
wait_for_window_shown (display, surface->wl_surface);
g_assert_false (wayland_surface_has_state (surface,
XDG_TOPLEVEL_STATE_SUSPENDED));
}
static void
test_minimized (WaylandDisplay *display)
{
g_autoptr (WaylandSurface) surface = NULL;
g_debug ("Testing suspended state when mapping minimized");
surface = wayland_surface_new (display, __func__, 100, 100, 0xffffffff);
wl_surface_commit (surface->wl_surface);
wait_for_window_shown (display, surface->wl_surface);
g_assert_false (wayland_surface_has_state (surface,
XDG_TOPLEVEL_STATE_SUSPENDED));
xdg_toplevel_set_minimized (surface->xdg_toplevel);
wait_for_state (surface, XDG_TOPLEVEL_STATE_SUSPENDED);
}
static void
test_workspace_changes (WaylandDisplay *display)
{
g_autoptr (WaylandSurface) surface = NULL;
g_debug ("Testing suspended state when changing workspace");
surface = wayland_surface_new (display, __func__, 100, 100, 0xffffffff);
wl_surface_commit (surface->wl_surface);
wait_for_window_shown (display, surface->wl_surface);
g_assert_false (wayland_surface_has_state (surface,
XDG_TOPLEVEL_STATE_SUSPENDED));
test_driver_sync_point (display->test_driver,
XDG_TOPLEVEL_SUSPENDED_COMMAND_NEXT_WORKSPACE,
NULL);
wait_for_state (surface, XDG_TOPLEVEL_STATE_SUSPENDED);
test_driver_sync_point (display->test_driver,
XDG_TOPLEVEL_SUSPENDED_COMMAND_PREV_WORKSPACE,
NULL);
wait_for_no_state (surface, XDG_TOPLEVEL_STATE_SUSPENDED);
}
static void
test_obstructed (WaylandDisplay *display)
{
g_autoptr (WaylandSurface) surface = NULL;
g_autoptr (WaylandSurface) cover_surface = NULL;
g_debug ("Testing suspended state when obstructed");
surface = wayland_surface_new (display, __func__,
100, 100, 0xffffffff);
wl_surface_commit (surface->wl_surface);
wait_for_window_shown (display, surface->wl_surface);
g_assert_false (wayland_surface_has_state (surface,
XDG_TOPLEVEL_STATE_SUSPENDED));
cover_surface = wayland_surface_new (display, "obstruction",
100, 100, 0xffffffff);
xdg_toplevel_set_maximized (cover_surface->xdg_toplevel);
wl_surface_commit (cover_surface->wl_surface);
wait_for_window_shown (display, cover_surface->wl_surface);
test_driver_sync_point (display->test_driver,
XDG_TOPLEVEL_SUSPENDED_COMMAND_ACTIVATE_WINDOW,
cover_surface->wl_surface);
wait_for_state (surface, XDG_TOPLEVEL_STATE_SUSPENDED);
g_clear_object (&cover_surface);
wait_for_no_state (surface, XDG_TOPLEVEL_STATE_SUSPENDED);
}
int
main (int argc,
char **argv)
{
g_autoptr (WaylandDisplay) display = NULL;
g_autoptr (WaylandSurface) surface = NULL;
display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER |
WAYLAND_DISPLAY_CAPABILITY_XDG_SHELL_V6);
test_floating (display);
test_maximized (display);
test_minimized (display);
test_workspace_changes (display);
test_obstructed (display);
return EXIT_SUCCESS;
}

View File

@ -868,6 +868,73 @@ toplevel_show_states (void)
meta_wayland_test_client_finish (wayland_test_client);
}
enum
{
XDG_TOPLEVEL_SUSPENDED_COMMAND_NEXT_WORKSPACE = 0,
XDG_TOPLEVEL_SUSPENDED_COMMAND_PREV_WORKSPACE = 1,
XDG_TOPLEVEL_SUSPENDED_COMMAND_ACTIVATE_WINDOW = 2,
};
static void
on_toplevel_suspended_sync_point (MetaWaylandTestDriver *test_driver,
unsigned int sequence,
struct wl_resource *surface_resource,
struct wl_client *wl_client)
{
MetaDisplay *display = meta_context_get_display (test_context);
MetaWorkspaceManager *workspace_manager =
meta_display_get_workspace_manager (display);
MetaWorkspace *current_workspace;
int index;
MetaWorkspace *workspace;
MetaWaylandSurface *surface;
uint32_t now_ms;
current_workspace =
meta_workspace_manager_get_active_workspace (workspace_manager);
index = meta_workspace_index (current_workspace);
switch (sequence)
{
case XDG_TOPLEVEL_SUSPENDED_COMMAND_NEXT_WORKSPACE:
workspace =
meta_workspace_manager_get_workspace_by_index (workspace_manager,
index + 1);
now_ms = meta_display_get_current_time_roundtrip (display);
meta_workspace_activate (workspace, now_ms);
break;
case XDG_TOPLEVEL_SUSPENDED_COMMAND_PREV_WORKSPACE:
workspace =
meta_workspace_manager_get_workspace_by_index (workspace_manager,
index - 1);
now_ms = meta_display_get_current_time_roundtrip (display);
meta_workspace_activate (workspace, now_ms);
break;
case XDG_TOPLEVEL_SUSPENDED_COMMAND_ACTIVATE_WINDOW:
surface = wl_resource_get_user_data (surface_resource);
now_ms = meta_display_get_current_time_roundtrip (display);
meta_window_activate (meta_wayland_surface_get_window (surface), now_ms);
break;
}
}
static void
toplevel_suspended (void)
{
MetaWaylandTestClient *wayland_test_client;
gulong sync_point_id;
sync_point_id =
g_signal_connect (test_driver, "sync-point",
G_CALLBACK (on_toplevel_suspended_sync_point),
NULL);
wayland_test_client =
meta_wayland_test_client_new (test_context, "xdg-toplevel-suspended");
meta_wayland_test_client_finish (wayland_test_client);
g_signal_handler_disconnect (test_driver, sync_point_id);
}
static void
on_before_tests (void)
{
@ -947,6 +1014,8 @@ init_tests (void)
xdg_foreign_set_parent_of);
g_test_add_func ("/wayland/toplevel/show-states",
toplevel_show_states);
g_test_add_func ("/wayland/toplevel/suspended",
toplevel_suspended);
}
int