aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <ifreund@ifreund.xyz>2020-07-20 23:43:03 +0200
committerSimon Ser <contact@emersion.fr>2020-08-27 12:36:29 +0200
commit2072d59da54ac772410271ad2219ca107a7fff48 (patch)
treed643a2d544ff0d5696822bee7d968af61305bb21
parent330c50b48dfe987d7894f5a92c1b084b2cc8c712 (diff)
xdg-shell: split last-acked and current state
These states are distinct in the time period between the ack_configure and the next commit on the surface. Splitting these states avoids the following race for example: - client starts at 1000x1000 - wlr_xdg_toplevel_set_size 500x500 - size is different -> configure sent - client acks the configure - wlr_xdg_toplevel_set_size 1000x1000 - compare_xdg_toplevel_state returns true since there is no pending configure and the currently committed size is still 1000x1000 - no new configure is sent - client commits at the size it last acked, 500x500
-rw-r--r--include/wlr/types/wlr_xdg_shell.h1
-rw-r--r--include/wlr/types/wlr_xdg_shell_v6.h1
-rw-r--r--types/xdg_shell/wlr_xdg_toplevel.c47
-rw-r--r--types/xdg_shell_v6/wlr_xdg_toplevel_v6.c43
4 files changed, 35 insertions, 57 deletions
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index 4bd286ce..45c5aee0 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -124,6 +124,7 @@ struct wlr_xdg_toplevel {
struct wlr_xdg_toplevel_state client_pending;
struct wlr_xdg_toplevel_state server_pending;
+ struct wlr_xdg_toplevel_state last_acked;
struct wlr_xdg_toplevel_state current;
char *title;
diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h
index 5a6cf72f..2e870aa5 100644
--- a/include/wlr/types/wlr_xdg_shell_v6.h
+++ b/include/wlr/types/wlr_xdg_shell_v6.h
@@ -139,6 +139,7 @@ struct wlr_xdg_toplevel_v6 {
struct wlr_xdg_toplevel_v6_state client_pending;
struct wlr_xdg_toplevel_v6_state server_pending;
+ struct wlr_xdg_toplevel_v6_state last_acked;
struct wlr_xdg_toplevel_v6_state current;
char *title;
diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c
index 3524bd34..51d0687b 100644
--- a/types/xdg_shell/wlr_xdg_toplevel.c
+++ b/types/xdg_shell/wlr_xdg_toplevel.c
@@ -13,60 +13,44 @@ void handle_xdg_toplevel_ack_configure(
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
assert(configure->toplevel_state != NULL);
- surface->toplevel->current.maximized =
- configure->toplevel_state->maximized;
- surface->toplevel->current.fullscreen =
- configure->toplevel_state->fullscreen;
- surface->toplevel->current.resizing =
- configure->toplevel_state->resizing;
- surface->toplevel->current.activated =
- configure->toplevel_state->activated;
- surface->toplevel->current.tiled =
- configure->toplevel_state->tiled;
+ surface->toplevel->last_acked = *configure->toplevel_state;
}
bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) {
- struct {
- struct wlr_xdg_toplevel_state state;
- uint32_t width, height;
- } configured;
-
// is pending state different from current state?
if (!state->base->configured) {
return false;
}
+ struct wlr_xdg_toplevel_state *configured = NULL;
if (wl_list_empty(&state->base->configure_list)) {
- // last configure is actually the current state, just use it
- configured.state = state->current;
- configured.width = state->base->surface->current.width;
- configured.height = state->base->surface->current.height;
+ // There are currently no pending configures, so check against the last
+ // state acked by the client.
+ configured = &state->last_acked;
} else {
struct wlr_xdg_surface_configure *configure =
wl_container_of(state->base->configure_list.prev, configure, link);
- configured.state = *configure->toplevel_state;
- configured.width = configure->toplevel_state->width;
- configured.height = configure->toplevel_state->height;
+ configured = configure->toplevel_state;
}
- if (state->server_pending.activated != configured.state.activated) {
+ if (state->server_pending.activated != configured->activated) {
return false;
}
- if (state->server_pending.fullscreen != configured.state.fullscreen) {
+ if (state->server_pending.fullscreen != configured->fullscreen) {
return false;
}
- if (state->server_pending.maximized != configured.state.maximized) {
+ if (state->server_pending.maximized != configured->maximized) {
return false;
}
- if (state->server_pending.resizing != configured.state.resizing) {
+ if (state->server_pending.resizing != configured->resizing) {
return false;
}
- if (state->server_pending.tiled != configured.state.tiled) {
+ if (state->server_pending.tiled != configured->tiled) {
return false;
}
- if (state->server_pending.width == configured.width &&
- state->server_pending.height == configured.height) {
+ if (state->server_pending.width == configured->width &&
+ state->server_pending.height == configured->height) {
return true;
}
@@ -187,7 +171,10 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) {
return;
}
- // update state that doesn't need compositor approval
+ // apply state from the last acked configure now that the client committed
+ surface->toplevel->current = surface->toplevel->last_acked;
+
+ // update state from the client that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =
diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c
index a7a7d12b..2c626f83 100644
--- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c
+++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c
@@ -295,55 +295,41 @@ void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface,
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
assert(configure->toplevel_state != NULL);
- surface->toplevel->current.maximized =
- configure->toplevel_state->maximized;
- surface->toplevel->current.fullscreen =
- configure->toplevel_state->fullscreen;
- surface->toplevel->current.resizing =
- configure->toplevel_state->resizing;
- surface->toplevel->current.activated =
- configure->toplevel_state->activated;
+ surface->toplevel->last_acked = *configure->toplevel_state;
}
bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) {
- struct {
- struct wlr_xdg_toplevel_v6_state state;
- uint32_t width, height;
- } configured;
-
// is pending state different from current state?
if (!state->base->configured) {
return false;
}
+ struct wlr_xdg_toplevel_v6_state *configured = NULL;
if (wl_list_empty(&state->base->configure_list)) {
- // last configure is actually the current state, just use it
- configured.state = state->current;
- configured.width = state->base->surface->current.width;
- configured.height = state->base->surface->current.height;
+ // There are currently no pending configures, so check against the last
+ // state acked by the client.
+ configured = &state->last_acked;
} else {
struct wlr_xdg_surface_v6_configure *configure =
wl_container_of(state->base->configure_list.prev, configure, link);
- configured.state = *configure->toplevel_state;
- configured.width = configure->toplevel_state->width;
- configured.height = configure->toplevel_state->height;
+ configured = configure->toplevel_state;
}
- if (state->server_pending.activated != configured.state.activated) {
+ if (state->server_pending.activated != configured->activated) {
return false;
}
- if (state->server_pending.fullscreen != configured.state.fullscreen) {
+ if (state->server_pending.fullscreen != configured->fullscreen) {
return false;
}
- if (state->server_pending.maximized != configured.state.maximized) {
+ if (state->server_pending.maximized != configured->maximized) {
return false;
}
- if (state->server_pending.resizing != configured.state.resizing) {
+ if (state->server_pending.resizing != configured->resizing) {
return false;
}
- if (state->server_pending.width == configured.width &&
- state->server_pending.height == configured.height) {
+ if (state->server_pending.width == configured->width &&
+ state->server_pending.height == configured->height) {
return true;
}
@@ -430,7 +416,10 @@ void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface
return;
}
- // update state that doesn't need compositor approval
+ // apply state from the last acked configure now that the client committed
+ surface->toplevel->current = surface->toplevel->last_acked;
+
+ // update state from the client that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =