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:
parent
cf176df006
commit
73990f011f
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,9 @@ wayland_test_clients = [
|
||||
{
|
||||
'name': 'xdg-toplevel-bounds',
|
||||
},
|
||||
{
|
||||
'name': 'xdg-toplevel-suspended',
|
||||
},
|
||||
{
|
||||
'name': 'ycbcr',
|
||||
},
|
||||
|
175
src/tests/wayland-test-clients/xdg-toplevel-suspended.c
Normal file
175
src/tests/wayland-test-clients/xdg-toplevel-suspended.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user