diff --git a/libweston-desktop/xdg-shell-v5.c b/libweston-desktop/xdg-shell-v5.c index b32b7812..c91c2590 100644 --- a/libweston-desktop/xdg-shell-v5.c +++ b/libweston-desktop/xdg-shell-v5.c @@ -46,6 +46,13 @@ struct weston_desktop_xdg_surface_state { 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 @@ struct weston_desktop_xdg_surface { 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 @@ static void 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 @@ weston_desktop_xdg_surface_send_configure(void *data) surface->pending.size.width, surface->pending.size.height, &states, - surface->configure_serial); + configure->serial); wl_array_release(&states); }; @@ -325,6 +345,7 @@ weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface, 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 @@ weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface, 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 @@ weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client, wl_resource_get_user_data(resource); struct weston_desktop_xdg_surface *surface = weston_desktop_surface_get_implementation_data(dsurface); - - if (surface->configure_serial != serial) + struct weston_desktop_xdg_surface_configure *configure, *temp; + bool found = false; + + 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 = configure->state; + surface->next.size = configure->size; - surface->next.state = surface->pending.state; - surface->next.size = surface->pending.size; + free(configure); } static void diff --git a/libweston-desktop/xdg-shell-v6.c b/libweston-desktop/xdg-shell-v6.c index f5e46daa..de5d3e05 100644 --- a/libweston-desktop/xdg-shell-v6.c +++ b/libweston-desktop/xdg-shell-v6.c @@ -69,7 +69,7 @@ struct weston_desktop_xdg_surface { 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 @@ struct weston_desktop_xdg_surface { 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 @@ struct weston_desktop_xdg_toplevel_state { 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 @@ struct weston_desktop_xdg_popup { }; #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 @@ weston_desktop_xdg_toplevel_protocol_resize(struct wl_client *wl_client, } 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 @@ weston_desktop_xdg_toplevel_protocol_set_minimized(struct wl_client *wl_client, } 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 @@ static void 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 @@ weston_desktop_xdg_surface_send_configure(void *user_data) 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 @@ weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client, 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 @@ weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client, 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 @@ weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface, 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 @@ weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface, 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 @@ weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client, "xdg_surface must not have a buffer at creation"); return; } + + wl_list_init(&surface->configure_list); } static void