aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Primak <vyivel@posteo.net>2021-09-16 14:04:56 +0300
committerSimon Ser <contact@emersion.fr>2021-09-21 10:09:09 +0200
commitb72a217fcc9f8bb47788c2068093579ac893301c (patch)
treec9ce0cef4f3a0a6fdb42c54f3ed1c3df2845fd8a
parent9579d62a160821a107763325a515d3aee0a1e158 (diff)
xdg-toplevel: refactor configure/state flow
Previously, `wlr_xdg_toplevel` didn't follow the usual "current state + pending state" pattern and instead had confusingly named `client_pending` and `server_pending`. This commit removes them, and instead introduces `wlr_xdg_toplevel.scheduled` to store the properties that are yet to be sent to a client, and `wlr_xdg_toplevel.requested` to store the properties that a client has requested. They have different types to emphasize that they aren't actual states.
-rw-r--r--include/wlr/types/wlr_xdg_shell.h27
-rw-r--r--types/xdg_shell/wlr_xdg_surface.c11
-rw-r--r--types/xdg_shell/wlr_xdg_toplevel.c153
3 files changed, 104 insertions, 87 deletions
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index f80c6685..2ca7e203 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -105,10 +105,16 @@ struct wlr_xdg_toplevel_state {
uint32_t width, height;
uint32_t max_width, max_height;
uint32_t min_width, min_height;
+};
+
+struct wlr_xdg_toplevel_configure {
+ bool maximized, fullscreen, resizing, activated;
+ uint32_t tiled; // enum wlr_edges
+ uint32_t width, height;
+};
- // Since the fullscreen request may be made before the toplevel's surface
- // is mapped, this is used to store the requested fullscreen output (if
- // any) for wlr_xdg_toplevel::client_pending.
+struct wlr_xdg_toplevel_requested {
+ bool maximized, minimized, fullscreen;
struct wlr_output *fullscreen_output;
struct wl_listener fullscreen_output_destroy;
};
@@ -121,10 +127,15 @@ struct wlr_xdg_toplevel {
struct wlr_xdg_surface *parent;
struct wl_listener parent_unmap;
- 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;
+ struct wlr_xdg_toplevel_state current, pending;
+
+ // Properties to be sent to the client in the next configure event.
+ struct wlr_xdg_toplevel_configure scheduled;
+
+ // Properties that the client has requested. Intended to be checked
+ // by the compositor on surface map and handled accordingly
+ // (e.g. a client might want to start already in a fullscreen state).
+ struct wlr_xdg_toplevel_requested requested;
char *title;
char *app_id;
@@ -147,7 +158,7 @@ struct wlr_xdg_surface_configure {
struct wl_list link; // wlr_xdg_surface::configure_list
uint32_t serial;
- struct wlr_xdg_toplevel_state *toplevel_state;
+ struct wlr_xdg_toplevel_configure *toplevel_configure;
};
/**
diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c
index 2afa9dc5..8819fd15 100644
--- a/types/xdg_shell/wlr_xdg_surface.c
+++ b/types/xdg_shell/wlr_xdg_surface.c
@@ -23,7 +23,7 @@ static void xdg_surface_configure_destroy(
return;
}
wl_list_remove(&configure->link);
- free(configure->toplevel_state);
+ free(configure->toplevel_configure);
free(configure);
}
@@ -487,11 +487,10 @@ void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
wl_resource_set_user_data(xdg_surface->toplevel->resource, NULL);
xdg_surface->toplevel->resource = NULL;
-
- if (xdg_surface->toplevel->client_pending.fullscreen_output) {
- struct wlr_xdg_toplevel_state *client_pending =
- &xdg_surface->toplevel->client_pending;
- wl_list_remove(&client_pending->fullscreen_output_destroy.link);
+ struct wlr_xdg_toplevel_requested *req =
+ &xdg_surface->toplevel->requested;
+ if (req->fullscreen_output) {
+ wl_list_remove(&req->fullscreen_output_destroy.link);
}
free(xdg_surface->toplevel);
xdg_surface->toplevel = NULL;
diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c
index 03d31897..d94b92e5 100644
--- a/types/xdg_shell/wlr_xdg_toplevel.c
+++ b/types/xdg_shell/wlr_xdg_toplevel.c
@@ -11,50 +11,67 @@ void handle_xdg_toplevel_ack_configure(
struct wlr_xdg_surface *surface,
struct wlr_xdg_surface_configure *configure) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- assert(configure->toplevel_state != NULL);
- surface->toplevel->last_acked = *configure->toplevel_state;
+ struct wlr_xdg_toplevel_configure *acked = configure->toplevel_configure;
+ assert(acked != NULL);
+
+ surface->toplevel->pending.maximized = acked->maximized;
+ surface->toplevel->pending.fullscreen = acked->fullscreen;
+ surface->toplevel->pending.resizing = acked->resizing;
+ surface->toplevel->pending.activated = acked->activated;
+ surface->toplevel->pending.tiled = acked->tiled;
+
+ surface->toplevel->pending.width = acked->width;
+ surface->toplevel->pending.height = acked->height;
}
-bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) {
- // is pending state different from current state?
- if (!state->base->configured) {
+bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *toplevel) {
+ // Is the scheduled configure different from the last sent one?
+ if (!toplevel->base->configured) {
return false;
}
- struct wlr_xdg_toplevel_state *configured = NULL;
- if (wl_list_empty(&state->base->configure_list)) {
+ struct wlr_xdg_toplevel_configure last_acked;
+ struct wlr_xdg_toplevel_configure *configure = NULL;
+ if (wl_list_empty(&toplevel->base->configure_list)) {
// There are currently no pending configures, so check against the last
// state acked by the client.
- configured = &state->last_acked;
+ last_acked.maximized = toplevel->pending.maximized;
+ last_acked.fullscreen = toplevel->pending.fullscreen;
+ last_acked.resizing = toplevel->pending.resizing;
+ last_acked.activated = toplevel->pending.activated;
+ last_acked.tiled = toplevel->pending.tiled;
+ last_acked.width = toplevel->pending.width;
+ last_acked.height = toplevel->pending.height;
+ configure = &last_acked;
} else {
- struct wlr_xdg_surface_configure *configure =
- wl_container_of(state->base->configure_list.prev, configure, link);
- configured = configure->toplevel_state;
+ struct wlr_xdg_surface_configure *surface_configure =
+ wl_container_of(toplevel->base->configure_list.prev, surface_configure, link);
+ configure = surface_configure->toplevel_configure;
}
- if (state->server_pending.activated != configured->activated) {
+ if (toplevel->scheduled.activated != configure->activated) {
return false;
}
- if (state->server_pending.fullscreen != configured->fullscreen) {
+ if (toplevel->scheduled.fullscreen != configure->fullscreen) {
return false;
}
- if (state->server_pending.maximized != configured->maximized) {
+ if (toplevel->scheduled.maximized != configure->maximized) {
return false;
}
- if (state->server_pending.resizing != configured->resizing) {
+ if (toplevel->scheduled.resizing != configure->resizing) {
return false;
}
- if (state->server_pending.tiled != configured->tiled) {
+ if (toplevel->scheduled.tiled != configure->tiled) {
return false;
}
- if (state->server_pending.width == configured->width &&
- state->server_pending.height == configured->height) {
+ if (toplevel->scheduled.width == configure->width &&
+ toplevel->scheduled.height == configure->height) {
return true;
}
- if (state->server_pending.width == 0 && state->server_pending.height == 0) {
+ if (toplevel->scheduled.width == 0 && toplevel->scheduled.height == 0) {
return true;
}
@@ -65,17 +82,17 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
struct wlr_xdg_surface_configure *configure) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- configure->toplevel_state = malloc(sizeof(*configure->toplevel_state));
- if (configure->toplevel_state == NULL) {
+ configure->toplevel_configure = malloc(sizeof(*configure->toplevel_configure));
+ if (configure->toplevel_configure == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
wl_resource_post_no_memory(surface->toplevel->resource);
return;
}
- *configure->toplevel_state = surface->toplevel->server_pending;
+ *configure->toplevel_configure = surface->toplevel->scheduled;
struct wl_array states;
wl_array_init(&states);
- if (surface->toplevel->server_pending.maximized) {
+ if (surface->toplevel->scheduled.maximized) {
uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR, "Could not allocate state for maximized xdg_toplevel");
@@ -83,7 +100,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
*s = XDG_TOPLEVEL_STATE_MAXIMIZED;
}
- if (surface->toplevel->server_pending.fullscreen) {
+ if (surface->toplevel->scheduled.fullscreen) {
uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR, "Could not allocate state for fullscreen xdg_toplevel");
@@ -91,7 +108,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
*s = XDG_TOPLEVEL_STATE_FULLSCREEN;
}
- if (surface->toplevel->server_pending.resizing) {
+ if (surface->toplevel->scheduled.resizing) {
uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR, "Could not allocate state for resizing xdg_toplevel");
@@ -99,7 +116,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
*s = XDG_TOPLEVEL_STATE_RESIZING;
}
- if (surface->toplevel->server_pending.activated) {
+ if (surface->toplevel->scheduled.activated) {
uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR, "Could not allocate state for activated xdg_toplevel");
@@ -107,7 +124,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
*s = XDG_TOPLEVEL_STATE_ACTIVATED;
}
- if (surface->toplevel->server_pending.tiled) {
+ if (surface->toplevel->scheduled.tiled) {
if (wl_resource_get_version(surface->resource) >=
XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) {
const struct {
@@ -121,7 +138,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
};
for (size_t i = 0; i < sizeof(tiled)/sizeof(tiled[0]); ++i) {
- if ((surface->toplevel->server_pending.tiled &
+ if ((surface->toplevel->scheduled.tiled &
tiled[i].edge) == 0) {
continue;
}
@@ -134,7 +151,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
*s = tiled[i].state;
}
- } else if (!surface->toplevel->server_pending.maximized) {
+ } else if (!surface->toplevel->scheduled.maximized) {
// This version doesn't support tiling, best we can do is make the
// toplevel maximized
uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
@@ -147,8 +164,8 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
}
}
- uint32_t width = surface->toplevel->server_pending.width;
- uint32_t height = surface->toplevel->server_pending.height;
+ uint32_t width = surface->toplevel->scheduled.width;
+ uint32_t height = surface->toplevel->scheduled.height;
xdg_toplevel_send_configure(surface->toplevel->resource, width, height,
&states);
@@ -171,18 +188,7 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) {
return;
}
- // 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 =
- surface->toplevel->client_pending.min_width;
- surface->toplevel->current.max_height =
- surface->toplevel->client_pending.max_height;
- surface->toplevel->current.min_height =
- surface->toplevel->client_pending.min_height;
+ surface->toplevel->current = surface->toplevel->pending;
}
static const struct xdg_toplevel_interface xdg_toplevel_implementation;
@@ -359,23 +365,23 @@ static void xdg_toplevel_handle_set_max_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
- surface->toplevel->client_pending.max_width = width;
- surface->toplevel->client_pending.max_height = height;
+ surface->toplevel->pending.max_width = width;
+ surface->toplevel->pending.max_height = height;
}
static void xdg_toplevel_handle_set_min_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
- surface->toplevel->client_pending.min_width = width;
- surface->toplevel->client_pending.min_height = height;
+ surface->toplevel->pending.min_width = width;
+ surface->toplevel->pending.min_height = height;
}
static void xdg_toplevel_handle_set_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
- surface->toplevel->client_pending.maximized = true;
+ surface->toplevel->requested.maximized = true;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
@@ -383,31 +389,31 @@ static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
- surface->toplevel->client_pending.maximized = false;
+ surface->toplevel->requested.maximized = false;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void handle_fullscreen_output_destroy(struct wl_listener *listener,
void *data) {
- struct wlr_xdg_toplevel_state *state =
- wl_container_of(listener, state, fullscreen_output_destroy);
- state->fullscreen_output = NULL;
- wl_list_remove(&state->fullscreen_output_destroy.link);
+ struct wlr_xdg_toplevel_requested *req =
+ wl_container_of(listener, req, fullscreen_output_destroy);
+ req->fullscreen_output = NULL;
+ wl_list_remove(&req->fullscreen_output_destroy.link);
}
-static void store_fullscreen_pending(struct wlr_xdg_surface *surface,
+static void store_fullscreen_requested(struct wlr_xdg_surface *surface,
bool fullscreen, struct wlr_output *output) {
- struct wlr_xdg_toplevel_state *state = &surface->toplevel->client_pending;
- state->fullscreen = fullscreen;
- if (state->fullscreen_output) {
- wl_list_remove(&state->fullscreen_output_destroy.link);
- }
- state->fullscreen_output = output;
- if (state->fullscreen_output) {
- state->fullscreen_output_destroy.notify =
+ struct wlr_xdg_toplevel_requested *req = &surface->toplevel->requested;
+ req->fullscreen = fullscreen;
+ if (req->fullscreen_output) {
+ wl_list_remove(&req->fullscreen_output_destroy.link);
+ }
+ req->fullscreen_output = output;
+ if (req->fullscreen_output) {
+ req->fullscreen_output_destroy.notify =
handle_fullscreen_output_destroy;
- wl_signal_add(&state->fullscreen_output->events.destroy,
- &state->fullscreen_output_destroy);
+ wl_signal_add(&req->fullscreen_output->events.destroy,
+ &req->fullscreen_output_destroy);
}
}
@@ -421,7 +427,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
output = wlr_output_from_resource(output_resource);
}
- store_fullscreen_pending(surface, true, output);
+ store_fullscreen_requested(surface, true, output);
struct wlr_xdg_toplevel_set_fullscreen_event event = {
.surface = surface,
@@ -437,7 +443,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
- store_fullscreen_pending(surface, false, NULL);
+ store_fullscreen_requested(surface, false, NULL);
struct wlr_xdg_toplevel_set_fullscreen_event event = {
.surface = surface,
@@ -452,6 +458,7 @@ static void xdg_toplevel_handle_set_minimized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
wlr_xdg_surface_from_toplevel_resource(resource);
+ surface->toplevel->requested.minimized = true;
wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface);
}
@@ -547,8 +554,8 @@ void destroy_xdg_toplevel(struct wlr_xdg_surface *xdg_surface) {
uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,
uint32_t width, uint32_t height) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.width = width;
- surface->toplevel->server_pending.height = height;
+ surface->toplevel->scheduled.width = width;
+ surface->toplevel->scheduled.height = height;
return schedule_xdg_surface_configure(surface);
}
@@ -556,7 +563,7 @@ uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,
bool activated) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.activated = activated;
+ surface->toplevel->scheduled.activated = activated;
return schedule_xdg_surface_configure(surface);
}
@@ -564,7 +571,7 @@ uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,
bool maximized) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.maximized = maximized;
+ surface->toplevel->scheduled.maximized = maximized;
return schedule_xdg_surface_configure(surface);
}
@@ -572,7 +579,7 @@ uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,
bool fullscreen) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.fullscreen = fullscreen;
+ surface->toplevel->scheduled.fullscreen = fullscreen;
return schedule_xdg_surface_configure(surface);
}
@@ -580,7 +587,7 @@ uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface,
bool resizing) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.resizing = resizing;
+ surface->toplevel->scheduled.resizing = resizing;
return schedule_xdg_surface_configure(surface);
}
@@ -588,7 +595,7 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface,
uint32_t tiled) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
- surface->toplevel->server_pending.tiled = tiled;
+ surface->toplevel->scheduled.tiled = tiled;
return schedule_xdg_surface_configure(surface);
}