diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index da85e5531..12bb84038 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -307,6 +307,7 @@ GList * meta_monitor_manager_get_logical_monitors (MetaMonitorManage
MetaLogicalMonitor *meta_monitor_manager_get_logical_monitor_from_number (MetaMonitorManager *manager,
int number);
+META_EXPORT_TEST
MetaLogicalMonitor *meta_monitor_manager_get_primary_logical_monitor (MetaMonitorManager *manager);
MetaLogicalMonitor *meta_monitor_manager_get_logical_monitor_at (MetaMonitorManager *manager,
diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build
index 2b3c83389..48fad9afb 100644
--- a/src/tests/wayland-test-clients/meson.build
+++ b/src/tests/wayland-test-clients/meson.build
@@ -53,6 +53,7 @@ wayland_test_clients = [
'invalid-xdg-shell-actions',
'xdg-apply-limits',
'xdg-activation',
+ 'xdg-toplevel-bounds',
]
foreach test : wayland_test_clients
diff --git a/src/tests/wayland-test-clients/xdg-toplevel-bounds.c b/src/tests/wayland-test-clients/xdg-toplevel-bounds.c
new file mode 100644
index 000000000..f0fc47058
--- /dev/null
+++ b/src/tests/wayland-test-clients/xdg-toplevel-bounds.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2021 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 .
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+
+#include "wayland-test-client-utils.h"
+
+#include "test-driver-client-protocol.h"
+#include "xdg-shell-client-protocol.h"
+
+typedef enum _State
+{
+ STATE_INIT = 0,
+ STATE_WAIT_FOR_CONFIGURE_1,
+ STATE_WAIT_FOR_FRAME_1,
+} State;
+
+static struct wl_display *display;
+static struct wl_registry *registry;
+static struct wl_compositor *compositor;
+static struct xdg_wm_base *xdg_wm_base;
+static struct wl_shm *shm;
+static struct test_driver *test_driver;
+
+static struct wl_surface *surface;
+static struct xdg_surface *xdg_surface;
+static struct xdg_toplevel *xdg_toplevel;
+
+static struct wl_callback *frame_callback;
+
+static gboolean running;
+
+static State state;
+static int32_t pending_bounds_width;
+static int32_t pending_bounds_height;
+
+static void
+init_surface (void)
+{
+ xdg_toplevel_set_title (xdg_toplevel, "toplevel-bounds-test");
+ wl_surface_commit (surface);
+}
+
+static void
+handle_buffer_release (void *data,
+ struct wl_buffer *buffer)
+{
+ wl_buffer_destroy (buffer);
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ handle_buffer_release
+};
+
+static gboolean
+create_shm_buffer (int width,
+ int height,
+ struct wl_buffer **out_buffer,
+ void **out_data,
+ int *out_size)
+{
+ struct wl_shm_pool *pool;
+ static struct wl_buffer *buffer;
+ int fd, size, stride;
+ int bytes_per_pixel;
+ void *data;
+
+ bytes_per_pixel = 4;
+ stride = width * bytes_per_pixel;
+ size = stride * height;
+
+ fd = create_anonymous_file (size);
+ if (fd < 0)
+ {
+ fprintf (stderr, "Creating a buffer file for %d B failed: %m\n",
+ size);
+ return FALSE;
+ }
+
+ data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED)
+ {
+ fprintf (stderr, "mmap failed: %m\n");
+ close (fd);
+ return FALSE;
+ }
+
+ pool = wl_shm_create_pool (shm, fd, size);
+ buffer = wl_shm_pool_create_buffer (pool, 0,
+ width, height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_buffer_add_listener (buffer, &buffer_listener, buffer);
+ wl_shm_pool_destroy (pool);
+ close (fd);
+
+ *out_buffer = buffer;
+ *out_data = data;
+ *out_size = size;
+
+ return TRUE;
+}
+
+static void
+fill (void *buffer_data,
+ int width,
+ int height,
+ uint32_t color)
+{
+ uint32_t *pixels = buffer_data;
+ int x, y;
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ pixels[y * width + x] = color;
+ }
+}
+
+static void
+draw (struct wl_surface *surface,
+ int width,
+ int height,
+ uint32_t color)
+{
+ struct wl_buffer *buffer;
+ void *buffer_data;
+ int size;
+
+ if (!create_shm_buffer (width, height,
+ &buffer, &buffer_data, &size))
+ g_error ("Failed to create shm buffer");
+
+ fill (buffer_data, width, height, color);
+
+ wl_surface_attach (surface, buffer, 0, 0);
+}
+
+static void
+draw_main (int width,
+ int height)
+{
+ draw (surface, width, height, 0xff00ff00);
+}
+
+static void
+handle_xdg_toplevel_configure (void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *state)
+{
+}
+
+static void
+handle_xdg_toplevel_close(void *data,
+ struct xdg_toplevel *xdg_toplevel)
+{
+ g_assert_not_reached ();
+}
+
+static void
+handle_xdg_toplevel_configure_bounds (void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t bounds_width,
+ int32_t bounds_height)
+{
+ pending_bounds_width = bounds_width;
+ pending_bounds_height = bounds_height;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ handle_xdg_toplevel_configure,
+ handle_xdg_toplevel_close,
+ handle_xdg_toplevel_configure_bounds,
+};
+
+static void
+handle_frame_callback (void *data,
+ struct wl_callback *callback,
+ uint32_t time)
+{
+ switch (state)
+ {
+ case STATE_WAIT_FOR_FRAME_1:
+ test_driver_sync_point (test_driver, 1, NULL);
+ break;
+ case STATE_INIT:
+ case STATE_WAIT_FOR_CONFIGURE_1:
+ g_assert_not_reached ();
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ handle_frame_callback,
+};
+
+static void
+handle_xdg_surface_configure (void *data,
+ struct xdg_surface *xdg_surface,
+ uint32_t serial)
+{
+ switch (state)
+ {
+ case STATE_INIT:
+ g_assert_not_reached ();
+ case STATE_WAIT_FOR_CONFIGURE_1:
+ g_assert (pending_bounds_width > 0);
+ g_assert (pending_bounds_height > 0);
+
+ draw_main (pending_bounds_width - 10,
+ pending_bounds_height - 10);
+ state = STATE_WAIT_FOR_FRAME_1;
+ break;
+ case STATE_WAIT_FOR_FRAME_1:
+ break;
+ }
+
+ xdg_surface_ack_configure (xdg_surface, serial);
+ frame_callback = wl_surface_frame (surface);
+ wl_callback_add_listener (frame_callback, &frame_listener, NULL);
+ wl_surface_commit (surface);
+ wl_display_flush (display);
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_xdg_surface_configure,
+};
+
+static void
+handle_xdg_wm_base_ping (void *data,
+ struct xdg_wm_base *xdg_wm_base,
+ uint32_t serial)
+{
+ xdg_wm_base_pong (xdg_wm_base, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+ handle_xdg_wm_base_ping,
+};
+
+static void
+test_driver_handle_sync_event (void *data,
+ struct test_driver *test_driver,
+ uint32_t serial)
+{
+ g_assert (serial == 0);
+
+ exit (EXIT_SUCCESS);
+}
+
+static const struct test_driver_listener test_driver_listener = {
+ test_driver_handle_sync_event,
+};
+
+static void
+handle_registry_global (void *data,
+ struct wl_registry *registry,
+ uint32_t id,
+ const char *interface,
+ uint32_t version)
+{
+ if (strcmp (interface, "wl_compositor") == 0)
+ {
+ compositor = wl_registry_bind (registry, id, &wl_compositor_interface, 1);
+ }
+ else if (strcmp (interface, "xdg_wm_base") == 0)
+ {
+ xdg_wm_base = wl_registry_bind (registry, id,
+ &xdg_wm_base_interface, 4);
+ xdg_wm_base_add_listener (xdg_wm_base, &xdg_wm_base_listener, NULL);
+ }
+ else if (strcmp (interface, "wl_shm") == 0)
+ {
+ shm = wl_registry_bind (registry,
+ id, &wl_shm_interface, 1);
+ }
+ else if (strcmp (interface, "test_driver") == 0)
+ {
+ test_driver = wl_registry_bind (registry, id, &test_driver_interface, 1);
+ test_driver_add_listener (test_driver, &test_driver_listener, NULL);
+ }
+}
+
+static void
+handle_registry_global_remove (void *data,
+ struct wl_registry *registry,
+ uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+ handle_registry_global,
+ handle_registry_global_remove
+};
+
+int
+main (int argc,
+ char **argv)
+{
+ display = wl_display_connect (NULL);
+ registry = wl_display_get_registry (display);
+ wl_registry_add_listener (registry, ®istry_listener, NULL);
+ wl_display_roundtrip (display);
+
+ if (!shm)
+ {
+ fprintf (stderr, "No wl_shm global\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!xdg_wm_base)
+ {
+ fprintf (stderr, "No xdg_wm_base global\n");
+ return EXIT_FAILURE;
+ }
+
+ wl_display_roundtrip (display);
+
+ surface = wl_compositor_create_surface (compositor);
+ xdg_surface = xdg_wm_base_get_xdg_surface (xdg_wm_base, surface);
+ xdg_surface_add_listener (xdg_surface, &xdg_surface_listener, NULL);
+ xdg_toplevel = xdg_surface_get_toplevel (xdg_surface);
+ xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL);
+
+ init_surface ();
+ state = STATE_WAIT_FOR_CONFIGURE_1;
+
+ wl_surface_commit (surface);
+
+ running = TRUE;
+ while (running)
+ {
+ if (wl_display_dispatch (display) == -1)
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/tests/wayland-unit-tests.c b/src/tests/wayland-unit-tests.c
index 4e95ab4f5..9c42b1633 100644
--- a/src/tests/wayland-unit-tests.c
+++ b/src/tests/wayland-unit-tests.c
@@ -25,6 +25,8 @@
#include "core/window-private.h"
#include "meta-test/meta-context-test.h"
#include "tests/meta-test-utils.h"
+#include "meta/meta-later.h"
+#include "meta/meta-workspace-manager.h"
#include "tests/meta-wayland-test-driver.h"
#include "tests/meta-wayland-test-utils.h"
#include "wayland/meta-wayland-surface.h"
@@ -363,6 +365,276 @@ toplevel_activation (void)
meta_wayland_test_client_finish (data.wayland_test_client);
}
+static void
+on_sync_point (MetaWaylandTestDriver *test_driver,
+ unsigned int sequence,
+ struct wl_resource *surface_resource,
+ struct wl_client *wl_client,
+ unsigned int *latest_sequence)
+{
+ *latest_sequence = sequence;
+}
+
+static void
+wait_for_sync_point (unsigned int sync_point)
+{
+ gulong handler_id;
+ unsigned int latest_sequence = 0;
+
+ handler_id = g_signal_connect (test_driver, "sync-point",
+ G_CALLBACK (on_sync_point),
+ &latest_sequence);
+ while (latest_sequence != sync_point)
+ g_main_context_iteration (NULL, TRUE);
+ g_signal_handler_disconnect (test_driver, handler_id);
+}
+
+static gboolean
+mark_later_as_done (gpointer user_data)
+{
+ gboolean *done = user_data;
+
+ *done = TRUE;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+wait_until_after_paint (void)
+{
+ MetaDisplay *display = meta_context_get_display (test_context);
+ MetaCompositor *compositor = meta_display_get_compositor (display);
+ MetaLaters *laters = meta_compositor_get_laters (compositor);
+ gboolean done;
+
+ done = FALSE;
+ meta_laters_add (laters,
+ META_LATER_BEFORE_REDRAW,
+ mark_later_as_done,
+ &done,
+ NULL);
+ while (!done)
+ g_main_context_iteration (NULL, FALSE);
+
+ done = FALSE;
+ meta_laters_add (laters,
+ META_LATER_IDLE,
+ mark_later_as_done,
+ &done,
+ NULL);
+ while (!done)
+ g_main_context_iteration (NULL, FALSE);
+}
+
+static void
+set_struts (MetaRectangle rect,
+ MetaSide side)
+{
+ MetaDisplay *display = meta_context_get_display (test_context);
+ MetaWorkspaceManager *workspace_manager =
+ meta_display_get_workspace_manager (display);
+ GList *workspaces =
+ meta_workspace_manager_get_workspaces (workspace_manager);
+ MetaStrut strut;
+ g_autoptr (GSList) struts = NULL;
+ GList *l;
+
+ strut = (MetaStrut) { .rect = rect, .side = side };
+ struts = g_slist_append (NULL, &strut);
+
+ for (l = workspaces; l; l = l->next)
+ {
+ MetaWorkspace *workspace = l->data;
+
+ meta_workspace_set_builtin_struts (workspace, struts);
+ }
+}
+
+static void
+clear_struts (void)
+{
+ MetaDisplay *display = meta_context_get_display (test_context);
+ MetaWorkspaceManager *workspace_manager =
+ meta_display_get_workspace_manager (display);
+ GList *workspaces =
+ meta_workspace_manager_get_workspaces (workspace_manager);
+ GList *l;
+
+ for (l = workspaces; l; l = l->next)
+ {
+ MetaWorkspace *workspace = l->data;
+
+ meta_workspace_set_builtin_struts (workspace, NULL);
+ }
+}
+
+static MetaRectangle
+get_primary_logical_monitor_layout (void)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ MetaMonitorManager *monitor_manager =
+ meta_backend_get_monitor_manager (backend);
+ MetaLogicalMonitor *logical_monitor;
+
+ logical_monitor =
+ meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
+ return meta_logical_monitor_get_layout (logical_monitor);
+}
+
+static void
+toplevel_bounds_struts (void)
+{
+ MetaWaylandTestClient *wayland_test_client;
+ MetaWindow *window;
+ MetaRectangle logical_monitor_layout;
+ MetaRectangle work_area;
+
+ /*
+ * This test case makes sure that setting and changing struts result in the
+ * right bounds are sent.
+ */
+
+ logical_monitor_layout = get_primary_logical_monitor_layout ();
+ set_struts ((MetaRectangle) {
+ .x = 0,
+ .y = 0,
+ .width = logical_monitor_layout.width,
+ .height = 10,
+ },
+ META_SIDE_TOP);
+
+ wayland_test_client = meta_wayland_test_client_new ("xdg-toplevel-bounds");
+
+ wait_for_sync_point (1);
+ wait_until_after_paint ();
+
+ window = find_client_window ("toplevel-bounds-test");
+
+ g_assert_nonnull (window->monitor);
+ meta_window_get_work_area_current_monitor (window, &work_area);
+ g_assert_cmpint (work_area.width, ==, logical_monitor_layout.width);
+ g_assert_cmpint (work_area.height, ==, logical_monitor_layout.height - 10);
+
+ g_assert_cmpint (window->rect.width, ==, work_area.width - 10);
+ g_assert_cmpint (window->rect.height, ==, work_area.height - 10);
+
+ meta_wayland_test_driver_emit_sync_event (test_driver, 0);
+ meta_wayland_test_client_finish (wayland_test_client);
+
+ clear_struts ();
+
+ wayland_test_client = meta_wayland_test_client_new ("xdg-toplevel-bounds");
+
+ wait_for_sync_point (1);
+ wait_until_after_paint ();
+
+ window = find_client_window ("toplevel-bounds-test");
+ g_assert_nonnull (window->monitor);
+ meta_window_get_work_area_current_monitor (window, &work_area);
+ g_assert_cmpint (work_area.width, ==, logical_monitor_layout.width);
+ g_assert_cmpint (work_area.height, ==, logical_monitor_layout.height);
+
+ g_assert_cmpint (window->rect.width, ==, work_area.width - 10);
+ g_assert_cmpint (window->rect.height, ==, work_area.height - 10);
+
+ meta_wayland_test_driver_emit_sync_event (test_driver, 0);
+ meta_wayland_test_client_finish (wayland_test_client);
+}
+
+static void
+wait_for_cursor_position (float x,
+ float y)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
+ graphene_point_t point;
+
+ while (TRUE)
+ {
+ meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
+ if (G_APPROX_VALUE (x, point.x, FLT_EPSILON) &&
+ G_APPROX_VALUE (y, point.y, FLT_EPSILON))
+ break;
+
+ g_main_context_iteration (NULL, TRUE);
+ }
+}
+
+static void
+toplevel_bounds_monitors (void)
+{
+ MetaBackend *backend = meta_context_get_backend (test_context);
+ ClutterSeat *seat;
+ g_autoptr (MetaVirtualMonitor) second_virtual_monitor = NULL;
+ MetaWaylandTestClient *wayland_test_client;
+ MetaRectangle logical_monitor_layout;
+ MetaRectangle work_area;
+ MetaWindow *window;
+
+ /*
+ * This test case creates two monitors, with different sizes, with a fake
+ * panel on top of the primary monitor. It then makes sure launching on both
+ * monitors results in the correct bounds.
+ */
+
+ seat = meta_backend_get_default_seat (backend);
+ virtual_pointer = clutter_seat_create_virtual_device (seat,
+ CLUTTER_POINTER_DEVICE);
+
+ second_virtual_monitor = meta_create_test_monitor (test_context,
+ 300, 200, 60.0);
+
+ logical_monitor_layout = get_primary_logical_monitor_layout ();
+ set_struts ((MetaRectangle) {
+ .x = 0,
+ .y = 0,
+ .width = logical_monitor_layout.width,
+ .height = 10,
+ },
+ META_SIDE_TOP);
+
+ wayland_test_client = meta_wayland_test_client_new ("xdg-toplevel-bounds");
+
+ wait_for_sync_point (1);
+ wait_until_after_paint ();
+
+ window = find_client_window ("toplevel-bounds-test");
+
+ g_assert_nonnull (window->monitor);
+ meta_window_get_work_area_current_monitor (window, &work_area);
+ g_assert_cmpint (work_area.width, ==, logical_monitor_layout.width);
+ g_assert_cmpint (work_area.height, ==, logical_monitor_layout.height - 10);
+
+ g_assert_cmpint (window->rect.width, ==, work_area.width - 10);
+ g_assert_cmpint (window->rect.height, ==, work_area.height - 10);
+
+ meta_wayland_test_driver_emit_sync_event (test_driver, 0);
+ meta_wayland_test_client_finish (wayland_test_client);
+
+ clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
+ CLUTTER_CURRENT_TIME,
+ 550.0, 100.0);
+ wait_for_cursor_position (550.0, 100.0);
+
+ wayland_test_client = meta_wayland_test_client_new ("xdg-toplevel-bounds");
+
+ wait_for_sync_point (1);
+ wait_until_after_paint ();
+
+ window = find_client_window ("toplevel-bounds-test");
+
+ g_assert_nonnull (window->monitor);
+ meta_window_get_work_area_current_monitor (window, &work_area);
+ g_assert_cmpint (work_area.width, ==, 300);
+ g_assert_cmpint (work_area.height, ==, 200);
+
+ g_assert_cmpint (window->rect.width, ==, 300 - 10);
+ g_assert_cmpint (window->rect.height, ==, 200 - 10);
+
+ meta_wayland_test_driver_emit_sync_event (test_driver, 0);
+ meta_wayland_test_client_finish (wayland_test_client);
+}
+
static void
on_before_tests (void)
{
@@ -398,6 +670,10 @@ init_tests (void)
toplevel_apply_limits);
g_test_add_func ("/wayland/toplevel/activation",
toplevel_activation);
+ g_test_add_func ("/wayland/toplevel/bounds/struts",
+ toplevel_bounds_struts);
+ g_test_add_func ("/wayland/toplevel/bounds/monitors",
+ toplevel_bounds_monitors);
}
int
diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c
index cf822bcb6..b34a836c5 100644
--- a/src/wayland/meta-wayland-legacy-xdg-shell.c
+++ b/src/wayland/meta-wayland-legacy-xdg-shell.c
@@ -685,7 +685,7 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole *surface_role
{
MetaWaylandWindowConfiguration *configuration;
- configuration = meta_wayland_window_configuration_new_empty ();
+ configuration = meta_wayland_window_configuration_new_empty (0, 0);
meta_wayland_zxdg_toplevel_v6_send_configure (xdg_toplevel,
configuration);
meta_wayland_window_configuration_free (configuration);
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 598bdd2e5..cd1a73ea6 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -37,7 +37,7 @@
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
#define META_WL_COMPOSITOR_VERSION 4
#define META_WL_DATA_DEVICE_MANAGER_VERSION 3
-#define META_XDG_WM_BASE_VERSION 3
+#define META_XDG_WM_BASE_VERSION 4
#define META_ZXDG_SHELL_V6_VERSION 1
#define META_WL_SEAT_VERSION 5
#define META_WL_OUTPUT_VERSION 2
diff --git a/src/wayland/meta-wayland-window-configuration.c b/src/wayland/meta-wayland-window-configuration.c
index c1712136f..702c95a62 100644
--- a/src/wayland/meta-wayland-window-configuration.c
+++ b/src/wayland/meta-wayland-window-configuration.c
@@ -43,6 +43,8 @@ is_window_size_fixed (MetaWindow *window)
MetaWaylandWindowConfiguration *
meta_wayland_window_configuration_new (MetaWindow *window,
MetaRectangle rect,
+ int bounds_width,
+ int bounds_height,
int scale,
MetaMoveResizeFlags flags,
MetaGravity gravity)
@@ -53,6 +55,9 @@ meta_wayland_window_configuration_new (MetaWindow *window,
*configuration = (MetaWaylandWindowConfiguration) {
.serial = ++global_serial_counter,
+ .bounds_width = bounds_width,
+ .bounds_height = bounds_height,
+
.scale = scale,
.gravity = gravity,
.flags = flags,
@@ -108,7 +113,8 @@ meta_wayland_window_configuration_new_relative (int rel_x,
}
MetaWaylandWindowConfiguration *
-meta_wayland_window_configuration_new_empty (void)
+meta_wayland_window_configuration_new_empty (int bounds_width,
+ int bounds_height)
{
MetaWaylandWindowConfiguration *configuration;
@@ -116,6 +122,8 @@ meta_wayland_window_configuration_new_empty (void)
*configuration = (MetaWaylandWindowConfiguration) {
.serial = ++global_serial_counter,
.scale = 1,
+ .bounds_width = bounds_width,
+ .bounds_height = bounds_height,
};
return configuration;
diff --git a/src/wayland/meta-wayland-window-configuration.h b/src/wayland/meta-wayland-window-configuration.h
index 7e91a778e..c4c0f2e55 100644
--- a/src/wayland/meta-wayland-window-configuration.h
+++ b/src/wayland/meta-wayland-window-configuration.h
@@ -46,10 +46,15 @@ struct _MetaWaylandWindowConfiguration
int scale;
MetaGravity gravity;
MetaMoveResizeFlags flags;
+
+ int bounds_width;
+ int bounds_height;
};
MetaWaylandWindowConfiguration * meta_wayland_window_configuration_new (MetaWindow *window,
MetaRectangle rect,
+ int max_width,
+ int max_height,
int scale,
MetaMoveResizeFlags flags,
MetaGravity gravity);
@@ -60,7 +65,8 @@ MetaWaylandWindowConfiguration * meta_wayland_window_configuration_new_relative
int height,
int scale);
-MetaWaylandWindowConfiguration * meta_wayland_window_configuration_new_empty (void);
+MetaWaylandWindowConfiguration * meta_wayland_window_configuration_new_empty (int bounds_width,
+ int bounds_height);
void meta_wayland_window_configuration_free (MetaWaylandWindowConfiguration *configuration);
diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
index acd0913d1..59a0f443e 100644
--- a/src/wayland/meta-wayland-xdg-shell.c
+++ b/src/wayland/meta-wayland-xdg-shell.c
@@ -700,6 +700,18 @@ meta_wayland_xdg_toplevel_send_configure (MetaWaylandXdgToplevel *xdg_to
wl_array_init (&states);
fill_states (xdg_toplevel, &states);
+ if (wl_resource_get_version (xdg_toplevel->resource) >=
+ XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION &&
+ configuration->bounds_width > 0 &&
+ configuration->bounds_height > 0)
+ {
+ xdg_toplevel_send_configure_bounds (xdg_toplevel->resource,
+ (configuration->bounds_width /
+ configuration->scale),
+ (configuration->bounds_height /
+ configuration->scale));
+ }
+
xdg_toplevel_send_configure (xdg_toplevel->resource,
configuration->width / configuration->scale,
configuration->height / configuration->scale,
@@ -777,8 +789,18 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
if (!xdg_surface_priv->configure_sent)
{
MetaWaylandWindowConfiguration *configuration;
+ int bounds_width;
+ int bounds_height;
- configuration = meta_wayland_window_configuration_new_empty ();
+ if (!meta_window_calculate_bounds (window, &bounds_width, &bounds_height))
+ {
+ bounds_width = 0;
+ bounds_height = 0;
+ }
+
+ configuration =
+ meta_wayland_window_configuration_new_empty (bounds_width,
+ bounds_height);
meta_wayland_xdg_toplevel_send_configure (xdg_toplevel, configuration);
meta_wayland_window_configuration_free (configuration);
return;
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index 2a923ef8f..d0fbde843 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -181,6 +181,8 @@ surface_state_changed (MetaWindow *window)
{
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
MetaWaylandWindowConfiguration *configuration;
+ int bounds_width;
+ int bounds_height;
/* don't send notify when the window is being unmanaged */
if (window->unmanaging)
@@ -188,9 +190,16 @@ surface_state_changed (MetaWindow *window)
g_return_if_fail (wl_window->has_last_sent_configuration);
+ if (!meta_window_calculate_bounds (window, &bounds_width, &bounds_height))
+ {
+ bounds_width = 0;
+ bounds_height = 0;
+ }
+
configuration =
meta_wayland_window_configuration_new (window,
wl_window->last_sent_rect,
+ bounds_width, bounds_height,
wl_window->last_sent_geometry_scale,
META_MOVE_RESIZE_STATE_CHANGED,
wl_window->last_sent_gravity);
@@ -345,6 +354,8 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
flags & META_MOVE_RESIZE_STATE_CHANGED)
{
MetaWaylandWindowConfiguration *configuration;
+ int bounds_width;
+ int bounds_height;
if (!meta_wayland_surface_get_buffer (window->surface) &&
!META_WINDOW_MAXIMIZED (window) &&
@@ -352,9 +363,18 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
!meta_window_is_fullscreen (window))
return;
+ if (!meta_window_calculate_bounds (window,
+ &bounds_width,
+ &bounds_height))
+ {
+ bounds_width = 0;
+ bounds_height = 0;
+ }
+
configuration =
meta_wayland_window_configuration_new (window,
configured_rect,
+ bounds_width, bounds_height,
geometry_scale,
flags,
gravity);