libweston-desktop/xdg-shell: Properly handle ack_configure
Now we keep track of serial->state association and we discard the states
that the client ignored.
Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
diff --git a/libweston-desktop/xdg-shell-v5.c b/libweston-desktop/xdg-shell-v5.c
index b32b781..c91c259 100644
--- a/libweston-desktop/xdg-shell-v5.c
+++ b/libweston-desktop/xdg-shell-v5.c
@@ -46,6 +46,13 @@
bool activated;
};
+struct weston_desktop_xdg_surface_configure {
+ struct wl_list link; /* weston_desktop_xdg_surface::configure_list */
+ uint32_t serial;
+ struct weston_desktop_xdg_surface_state state;
+ struct weston_size size;
+};
+
struct weston_desktop_xdg_surface {
struct wl_resource *resource;
struct weston_desktop_surface *surface;
@@ -53,7 +60,7 @@
bool added;
struct wl_event_source *add_idle;
struct wl_event_source *configure_idle;
- uint32_t configure_serial;
+ struct wl_list configure_list; /* weston_desktop_xdg_surface_configure::link */
struct {
struct weston_desktop_xdg_surface_state state;
struct weston_size size;
@@ -94,13 +101,26 @@
weston_desktop_xdg_surface_send_configure(void *data)
{
struct weston_desktop_xdg_surface *surface = data;
+ struct weston_desktop_xdg_surface_configure *configure;
uint32_t *s;
struct wl_array states;
surface->configure_idle = NULL;
- surface->configure_serial =
+ configure = zalloc(sizeof(struct weston_desktop_xdg_surface_configure));
+ if (configure == NULL) {
+ struct weston_desktop_client *client =
+ weston_desktop_surface_get_client(surface->surface);
+ struct wl_client *wl_client =
+ weston_desktop_client_get_client(client);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+ wl_list_insert(surface->configure_list.prev, &configure->link);
+ configure->serial =
wl_display_next_serial(weston_desktop_get_display(surface->desktop));
+ configure->state = surface->pending.state;
+ configure->size = surface->pending.size;
wl_array_init(&states);
if (surface->pending.state.maximized) {
@@ -124,7 +144,7 @@
surface->pending.size.width,
surface->pending.size.height,
&states,
- surface->configure_serial);
+ configure->serial);
wl_array_release(&states);
};
@@ -325,6 +345,7 @@
void *user_data)
{
struct weston_desktop_xdg_surface *surface = user_data;
+ struct weston_desktop_xdg_surface_configure *configure, *temp;
if (surface->added)
weston_desktop_api_surface_removed(surface->desktop,
@@ -336,6 +357,9 @@
if (surface->configure_idle != NULL)
wl_event_source_remove(surface->configure_idle);
+ wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
+ free(configure);
+
free(surface);
}
@@ -443,12 +467,34 @@
wl_resource_get_user_data(resource);
struct weston_desktop_xdg_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
+ struct weston_desktop_xdg_surface_configure *configure, *temp;
+ bool found = false;
- if (surface->configure_serial != serial)
+ wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
+ if (configure->serial < serial) {
+ wl_list_remove(&configure->link);
+ free(configure);
+ } else if (configure->serial == serial) {
+ wl_list_remove(&configure->link);
+ found = true;
+ }
+ break;
+ }
+ if (!found) {
+ struct weston_desktop_client *client =
+ weston_desktop_surface_get_client(dsurface);
+ struct wl_resource *client_resource =
+ weston_desktop_client_get_resource(client);
+ wl_resource_post_error(client_resource,
+ XDG_SHELL_ERROR_DEFUNCT_SURFACES,
+ "Wrong configure serial: %u", serial);
return;
+ }
- surface->next.state = surface->pending.state;
- surface->next.size = surface->pending.size;
+ surface->next.state = configure->state;
+ surface->next.size = configure->size;
+
+ free(configure);
}
static void
diff --git a/libweston-desktop/xdg-shell-v6.c b/libweston-desktop/xdg-shell-v6.c
index f5e46da..de5d3e0 100644
--- a/libweston-desktop/xdg-shell-v6.c
+++ b/libweston-desktop/xdg-shell-v6.c
@@ -69,7 +69,7 @@
struct weston_desktop_surface *desktop_surface;
bool configured;
struct wl_event_source *configure_idle;
- uint32_t configure_serial;
+ struct wl_list configure_list; /* weston_desktop_xdg_surface_configure::link */
bool has_next_geometry;
struct weston_geometry next_geometry;
@@ -77,6 +77,11 @@
enum weston_desktop_xdg_surface_role role;
};
+struct weston_desktop_xdg_surface_configure {
+ struct wl_list link; /* weston_desktop_xdg_surface::configure_list */
+ uint32_t serial;
+};
+
struct weston_desktop_xdg_toplevel_state {
bool maximized;
bool fullscreen;
@@ -84,6 +89,12 @@
bool activated;
};
+struct weston_desktop_xdg_toplevel_configure {
+ struct weston_desktop_xdg_surface_configure base;
+ struct weston_desktop_xdg_toplevel_state state;
+ struct weston_size size;
+};
+
struct weston_desktop_xdg_toplevel {
struct weston_desktop_xdg_surface base;
@@ -115,6 +126,7 @@
};
#define weston_desktop_surface_role_biggest_size (sizeof(struct weston_desktop_xdg_toplevel))
+#define weston_desktop_surface_configure_biggest_size (sizeof(struct weston_desktop_xdg_toplevel))
static struct weston_geometry
@@ -422,10 +434,11 @@
}
static void
-weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel *toplevel)
+weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel *toplevel,
+ struct weston_desktop_xdg_toplevel_configure *configure)
{
- toplevel->next.state = toplevel->pending.state;
- toplevel->next.size = toplevel->pending.size;
+ toplevel->next.state = configure->state;
+ toplevel->next.size = configure->size;
}
static void
@@ -529,11 +542,15 @@
}
static void
-weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel *toplevel)
+weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel *toplevel,
+ struct weston_desktop_xdg_toplevel_configure *configure)
{
uint32_t *s;
struct wl_array states;
+ configure->state = toplevel->pending.state;
+ configure->size = toplevel->pending.size;
+
wl_array_init(&states);
if (toplevel->pending.state.maximized) {
s = wl_array_add(&states, sizeof(uint32_t));
@@ -848,9 +865,21 @@
weston_desktop_xdg_surface_send_configure(void *user_data)
{
struct weston_desktop_xdg_surface *surface = user_data;
+ struct weston_desktop_xdg_surface_configure *configure;
surface->configure_idle = NULL;
- surface->configure_serial =
+
+ configure = zalloc(weston_desktop_surface_configure_biggest_size);
+ if (configure == NULL) {
+ struct weston_desktop_client *client =
+ weston_desktop_surface_get_client(surface->desktop_surface);
+ struct wl_client *wl_client =
+ weston_desktop_client_get_client(client);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+ wl_list_insert(surface->configure_list.prev, &configure->link);
+ configure->serial =
wl_display_next_serial(weston_desktop_get_display(surface->desktop));
switch (surface->role) {
@@ -858,14 +887,15 @@
assert(0 && "not reached");
break;
case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
- weston_desktop_xdg_toplevel_send_configure((struct weston_desktop_xdg_toplevel *) surface);
+ weston_desktop_xdg_toplevel_send_configure((struct weston_desktop_xdg_toplevel *) surface,
+ (struct weston_desktop_xdg_toplevel_configure *) configure);
break;
case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
weston_desktop_xdg_popup_send_configure((struct weston_desktop_xdg_popup *) surface);
break;
}
- zxdg_surface_v6_send_configure(surface->resource, surface->configure_serial);
+ zxdg_surface_v6_send_configure(surface->resource, configure->serial);
}
static bool
@@ -1060,12 +1090,32 @@
wl_resource_get_user_data(resource);
struct weston_desktop_xdg_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
+ struct weston_desktop_xdg_surface_configure *configure, *temp;
+ bool found = false;
if (!weston_desktop_xdg_surface_check_role(surface))
return;
- if (surface->configure_serial != serial)
+ wl_list_for_each_safe(configure, temp, &surface->configure_list, link) {
+ if (configure->serial < serial) {
+ wl_list_remove(&configure->link);
+ free(configure);
+ } else if (configure->serial == serial) {
+ wl_list_remove(&configure->link);
+ found = true;
+ }
+ break;
+ }
+ if (!found) {
+ struct weston_desktop_client *client =
+ weston_desktop_surface_get_client(dsurface);
+ struct wl_resource *client_resource =
+ weston_desktop_client_get_resource(client);
+ wl_resource_post_error(client_resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+ "Wrong configure serial: %u", serial);
return;
+ }
surface->configured = true;
@@ -1074,11 +1124,14 @@
assert(0 && "not reached");
break;
case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL:
- weston_desktop_xdg_toplevel_ack_configure((struct weston_desktop_xdg_toplevel *) surface);
+ weston_desktop_xdg_toplevel_ack_configure((struct weston_desktop_xdg_toplevel *) surface,
+ (struct weston_desktop_xdg_toplevel_configure *) configure);
break;
case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP:
break;
}
+
+ free(configure);
}
static void
@@ -1153,6 +1206,7 @@
void *user_data)
{
struct weston_desktop_xdg_surface *surface = user_data;
+ struct weston_desktop_xdg_surface_configure *configure, *temp;
switch (surface->role) {
case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE:
@@ -1168,6 +1222,9 @@
if (surface->configure_idle != NULL)
wl_event_source_remove(surface->configure_idle);
+ wl_list_for_each_safe(configure, temp, &surface->configure_list, link)
+ free(configure);
+
free(surface);
}
@@ -1290,6 +1347,8 @@
"xdg_surface must not have a buffer at creation");
return;
}
+
+ wl_list_init(&surface->configure_list);
}
static void