From 586ee8e6991e67cc1e76a84804bce7c861e0c9bb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 6 May 2026 09:49:36 +0800 Subject: [PATCH] fix: update ext-workspace --- src/ext-protocol/ext-workspace.h | 108 ++++++++------ src/ext-protocol/wlr_ext_workspace_v1.c | 180 +++++++++++------------- src/ext-protocol/wlr_ext_workspace_v1.h | 74 ++++++++-- 3 files changed, 203 insertions(+), 159 deletions(-) diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 28aaeeeb..d938ce51 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -7,15 +7,11 @@ typedef struct Monitor Monitor; struct workspace { - struct wl_list link; // Link in global workspaces list - uint32_t tag; // Numeric identifier (1-9, 0=overview) - Monitor *m; // Associated monitor - struct wlr_ext_workspace_handle_v1 *ext_workspace; // Protocol object - /* Event listeners */ - struct wl_listener activate; - struct wl_listener deactivate; - struct wl_listener assign; - struct wl_listener remove; + struct wl_list link; + uint32_t tag; + Monitor *m; + struct wlr_ext_workspace_handle_v1 *ext_workspace; + struct wl_listener commit; }; struct wlr_ext_workspace_manager_v1 *ext_manager; @@ -43,30 +39,60 @@ void toggle_workspace(struct workspace *target) { } } -static void handle_ext_workspace_activate(struct wl_listener *listener, - void *data) { - struct workspace *workspace = - wl_container_of(listener, workspace, activate); +static void handle_ext_commit(struct wl_listener *listener, void *data) { + struct wlr_ext_workspace_v1_commit_event *event = data; + struct wlr_ext_workspace_v1_request *request; - if (workspace->m->isoverview) { - return; + wl_list_for_each(request, event->requests, link) { + switch (request->type) { + case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: { + if (!request->activate.workspace) { + break; + } + + struct workspace *workspace = NULL; + struct workspace *w; + wl_list_for_each(w, &workspaces, link) { + if (w->ext_workspace == request->activate.workspace) { + workspace = w; + break; + } + } + + if (!workspace || workspace->m->isoverview) { + break; + } + + goto_workspace(workspace); + wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); + break; + } + case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: { + if (!request->deactivate.workspace) { + break; + } + + struct workspace *workspace = NULL; + struct workspace *w; + wl_list_for_each(w, &workspaces, link) { + if (w->ext_workspace == request->deactivate.workspace) { + workspace = w; + break; + } + } + + if (!workspace || workspace->m->isoverview) { + break; + } + + toggle_workspace(workspace); + wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); + break; + } + default: + break; + } } - - goto_workspace(workspace); - wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); -} - -static void handle_ext_workspace_deactivate(struct wl_listener *listener, - void *data) { - struct workspace *workspace = - wl_container_of(listener, workspace, deactivate); - - if (workspace->m->isoverview) { - return; - } - - toggle_workspace(workspace); - wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); } static const char *get_name_from_tag(uint32_t tag) { @@ -76,8 +102,6 @@ static const char *get_name_from_tag(uint32_t tag) { } void destroy_workspace(struct workspace *workspace) { - wl_list_remove(&workspace->activate.link); - wl_list_remove(&workspace->deactivate.link); wlr_ext_workspace_handle_v1_destroy(workspace->ext_workspace); wl_list_remove(&workspace->link); free(workspace); @@ -112,17 +136,12 @@ static void add_workspace_by_tag(int32_t tag, Monitor *m) { workspace->m = m; workspace->ext_workspace = wlr_ext_workspace_handle_v1_create( ext_manager, name, EXT_WORKSPACE_ENABLE_CAPS); + + workspace->ext_workspace->data = workspace; + wlr_ext_workspace_handle_v1_set_group(workspace->ext_workspace, m->ext_group); wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, name); - - workspace->activate.notify = handle_ext_workspace_activate; - wl_signal_add(&workspace->ext_workspace->events.activate, - &workspace->activate); - - workspace->deactivate.notify = handle_ext_workspace_deactivate; - wl_signal_add(&workspace->ext_workspace->events.deactivate, - &workspace->deactivate); } void dwl_ext_workspace_printstatus(Monitor *m) { @@ -180,8 +199,11 @@ void refresh_monitors_workspaces_status(Monitor *m) { } void workspaces_init() { - /* Create the global workspace manager with activation capability */ ext_manager = wlr_ext_workspace_manager_v1_create(dpy, 1); - /* Initialize the global workspaces list */ + wl_list_init(&workspaces); + + static struct wl_listener commit_listener; + commit_listener.notify = handle_ext_commit; + wl_signal_add(&ext_manager->events.commit, &commit_listener); } \ No newline at end of file diff --git a/src/ext-protocol/wlr_ext_workspace_v1.c b/src/ext-protocol/wlr_ext_workspace_v1.c index 2d781b34..dca93e93 100644 --- a/src/ext-protocol/wlr_ext_workspace_v1.c +++ b/src/ext-protocol/wlr_ext_workspace_v1.c @@ -1,7 +1,3 @@ -// bash on: https://gitlab.freedesktop.org/tokyo4j/wlroots/-/tree/ext-workspace -// TODO: remove this file -// refer: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5115 - #include "wlr_ext_workspace_v1.h" #include "ext-workspace-v1-protocol.h" #include @@ -11,27 +7,6 @@ #define EXT_WORKSPACE_V1_VERSION 1 -enum wlr_ext_workspace_v1_request_type { - WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE, - WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN, - WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE, -}; - -struct wlr_ext_workspace_v1_request { - enum wlr_ext_workspace_v1_request_type type; - - // CREATE_WORKSPACE - char *name; - // CREATE_WORKSPACE / ASSIGN - struct wlr_ext_workspace_group_handle_v1 *group; - // ACTIVATE / DEACTIVATE / ASSIGN / REMOVE - struct wlr_ext_workspace_handle_v1 *workspace; - - struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests -}; - struct wlr_ext_workspace_v1_group_output { struct wlr_output *output; struct wlr_ext_workspace_group_handle_v1 *group; @@ -117,7 +92,7 @@ static void workspace_handle_activate(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE; - req->workspace = workspace_res->workspace; + req->activate.workspace = workspace_res->workspace; wl_list_insert(workspace_res->manager->requests.prev, &req->link); } @@ -136,7 +111,7 @@ workspace_handle_deactivate(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE; - req->workspace = workspace_res->workspace; + req->deactivate.workspace = workspace_res->workspace; wl_list_insert(workspace_res->manager->requests.prev, &req->link); } @@ -157,8 +132,8 @@ static void workspace_handle_assign(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN; - req->group = group_res->group; - req->workspace = workspace_res->workspace; + req->assign.group = group_res->group; + req->assign.workspace = workspace_res->workspace; wl_list_insert(workspace_res->manager->requests.prev, &req->link); } @@ -176,7 +151,7 @@ static void workspace_handle_remove(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE; - req->workspace = workspace_res->workspace; + req->remove.workspace = workspace_res->workspace; wl_list_insert(workspace_res->manager->requests.prev, &req->link); } @@ -202,14 +177,14 @@ static void group_handle_create_workspace(struct wl_client *client, wl_resource_post_no_memory(group_resource); return; } - req->name = strdup(name); - if (!req->name) { + req->create_workspace.name = strdup(name); + if (!req->create_workspace.name) { free(req); wl_resource_post_no_memory(group_resource); return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE; - req->group = group_res->group; + req->create_workspace.group = group_res->group; wl_list_insert(group_res->manager->requests.prev, &req->link); } @@ -313,10 +288,55 @@ static struct wlr_ext_workspace_group_v1_resource *create_group_resource( return group_res; } -static void destroy_request(struct wlr_ext_workspace_v1_request *req) { - wl_list_remove(&req->link); - free(req->name); - free(req); +static void +destroy_requests(struct wlr_ext_workspace_manager_v1_resource *manager_res) { + struct wlr_ext_workspace_v1_request *req, *tmp; + wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { + if (req->type == WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE) { + free(req->create_workspace.name); + } + wl_list_remove(&req->link); + free(req); + } +} + +static void +clear_requests_by(struct wlr_ext_workspace_manager_v1_resource *manager_res, + struct wlr_ext_workspace_group_handle_v1 *group, + struct wlr_ext_workspace_handle_v1 *workspace) { + struct wlr_ext_workspace_v1_request *req, *tmp; + wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { + switch (req->type) { + case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE: + if (group && req->create_workspace.group == group) { + req->create_workspace.group = NULL; + } + break; + case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: + if (workspace && req->activate.workspace == workspace) { + req->activate.workspace = NULL; + } + break; + case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: + if (workspace && req->deactivate.workspace == workspace) { + req->deactivate.workspace = NULL; + } + break; + case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN: + if (workspace && req->assign.workspace == workspace) { + req->assign.workspace = NULL; + } + if (group && req->assign.group == group) { + req->assign.group = NULL; + } + break; + case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE: + if (workspace && req->remove.workspace == workspace) { + req->remove.workspace = NULL; + } + break; + } + } } static void manager_handle_commit(struct wl_client *client, @@ -327,32 +347,11 @@ static void manager_handle_commit(struct wl_client *client, return; } - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - switch (req->type) { - case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE:; - struct wlr_ext_workspace_group_handle_v1_create_workspace_event - event = { - .name = req->name, - }; - wl_signal_emit_mutable(&req->group->events.create_workspace, - &event); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: - wl_signal_emit_mutable(&req->workspace->events.activate, NULL); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: - wl_signal_emit_mutable(&req->workspace->events.deactivate, NULL); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN: - wl_signal_emit_mutable(&req->workspace->events.assign, req->group); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE: - wl_signal_emit_mutable(&req->workspace->events.remove, NULL); - break; - } - destroy_request(req); - } + struct wlr_ext_workspace_v1_commit_event commit_event = { + .requests = &manager_res->requests, + }; + wl_signal_emit_mutable(&manager_res->manager->events.commit, &commit_event); + destroy_requests(manager_res); } static void handle_idle(void *data) { @@ -406,10 +405,8 @@ static const struct ext_workspace_manager_v1_interface manager_impl = { static void destroy_manager_resource( struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - destroy_request(req); - } + destroy_requests(manager_res); + struct wlr_ext_workspace_v1_resource *workspace_res, *tmp2; wl_list_for_each_safe(workspace_res, tmp2, &manager_res->workspace_resources, @@ -531,6 +528,7 @@ static void manager_handle_display_destroy(struct wl_listener *listener, wl_container_of(listener, manager, display_destroy); wl_signal_emit_mutable(&manager->events.destroy, NULL); + assert(wl_list_empty(&manager->events.commit.listener_list)); assert(wl_list_empty(&manager->events.destroy.listener_list)); struct wlr_ext_workspace_group_handle_v1 *group, *tmp; @@ -583,6 +581,7 @@ wlr_ext_workspace_manager_v1_create(struct wl_display *display, wl_list_init(&manager->groups); wl_list_init(&manager->workspaces); wl_list_init(&manager->resources); + wl_signal_init(&manager->events.commit); wl_signal_init(&manager->events.destroy); return manager; @@ -601,7 +600,6 @@ wlr_ext_workspace_group_handle_v1_create( wl_list_init(&group->outputs); wl_list_init(&group->resources); - wl_signal_init(&group->events.create_workspace); wl_signal_init(&group->events.destroy); wl_list_insert(manager->groups.prev, &group->link); @@ -689,7 +687,6 @@ void wlr_ext_workspace_group_handle_v1_destroy( wl_signal_emit_mutable(&group->events.destroy, NULL); - assert(wl_list_empty(&group->events.create_workspace.listener_list)); assert(wl_list_empty(&group->events.destroy.listener_list)); struct wlr_ext_workspace_handle_v1 *workspace; @@ -708,12 +705,7 @@ void wlr_ext_workspace_group_handle_v1_destroy( struct wlr_ext_workspace_manager_v1_resource *manager_res; wl_list_for_each(manager_res, &group->manager->resources, link) { - struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { - if (req->group == group) { - destroy_request(req); - } - } + clear_requests_by(manager_res, group, NULL); } struct wlr_ext_workspace_v1_group_output *group_output, *tmp3; @@ -822,13 +814,9 @@ wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, wl_list_init(&workspace->resources); wl_array_init(&workspace->coordinates); - wl_signal_init(&workspace->events.activate); - wl_signal_init(&workspace->events.deactivate); - wl_signal_init(&workspace->events.remove); - wl_signal_init(&workspace->events.assign); wl_signal_init(&workspace->events.destroy); - wl_list_insert(&manager->workspaces, &workspace->link); + wl_list_insert(manager->workspaces.prev, &workspace->link); struct wlr_ext_workspace_manager_v1_resource *manager_res; wl_list_for_each(manager_res, &manager->resources, link) { @@ -855,10 +843,6 @@ void wlr_ext_workspace_handle_v1_destroy( wl_signal_emit_mutable(&workspace->events.destroy, NULL); - assert(wl_list_empty(&workspace->events.activate.listener_list)); - assert(wl_list_empty(&workspace->events.deactivate.listener_list)); - assert(wl_list_empty(&workspace->events.remove.listener_list)); - assert(wl_list_empty(&workspace->events.assign.listener_list)); assert(wl_list_empty(&workspace->events.destroy.listener_list)); if (workspace->group) { @@ -873,12 +857,7 @@ void wlr_ext_workspace_handle_v1_destroy( struct wlr_ext_workspace_manager_v1_resource *manager_res; wl_list_for_each(manager_res, &workspace->manager->resources, link) { - struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { - if (req->workspace == workspace) { - destroy_request(req); - } - } + clear_requests_by(manager_res, NULL, workspace); } manager_schedule_done(workspace->manager); @@ -929,23 +908,22 @@ void wlr_ext_workspace_handle_v1_set_name( manager_schedule_done(workspace->manager); } -static bool array_equal(struct wl_array *a, struct wl_array *b) { - return (a->size == b->size) && - (a->size == 0 || memcmp(a->data, b->data, a->size) == 0); -} - void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wl_array *coordinates) { - assert(coordinates); - - if (array_equal(&workspace->coordinates, coordinates)) { + struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords, + size_t coords_len) { + size_t size = coords_len * sizeof(coords[0]); + if (size == workspace->coordinates.size && + (size == 0 || memcmp(workspace->coordinates.data, coords, size) == 0)) { return; } wl_array_release(&workspace->coordinates); wl_array_init(&workspace->coordinates); - wl_array_copy(&workspace->coordinates, coordinates); + struct wl_array arr = { + .data = (void *)coords, + .size = size, + }; + wl_array_copy(&workspace->coordinates, &arr); struct wlr_ext_workspace_v1_resource *workspace_res; wl_list_for_each(workspace_res, &workspace->resources, link) { diff --git a/src/ext-protocol/wlr_ext_workspace_v1.h b/src/ext-protocol/wlr_ext_workspace_v1.h index a2a733b3..183d5801 100644 --- a/src/ext-protocol/wlr_ext_workspace_v1.h +++ b/src/ext-protocol/wlr_ext_workspace_v1.h @@ -1,21 +1,69 @@ -// bash on: https://gitlab.freedesktop.org/tokyo4j/wlroots/-/tree/ext-workspace -// TODO: remove this file -// refer: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5115 +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_EXT_WORKSPACE_V1_H +#define WLR_TYPES_WLR_EXT_WORKSPACE_V1_H #include #include struct wlr_output; +enum wlr_ext_workspace_v1_request_type { + WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE, + WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE, + WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE, + WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN, + WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE, +}; + +struct wlr_ext_workspace_v1_request { + enum wlr_ext_workspace_v1_request_type type; + struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests + union { + struct { + char *name; + struct wlr_ext_workspace_group_handle_v1 + *group; // NULL if destroyed + } create_workspace; + struct { + struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed + } activate; + struct { + struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed + } deactivate; + struct { + struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed + struct wlr_ext_workspace_group_handle_v1 + *group; // NULL if destroyed + } assign; + struct { + struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed + } remove; + }; +}; + +struct wlr_ext_workspace_v1_commit_event { + struct wl_list *requests; // wlr_ext_workspace_v1_request.link +}; + struct wlr_ext_workspace_manager_v1 { struct wl_global *global; struct wl_list groups; // wlr_ext_workspace_group_handle_v1.link struct wl_list workspaces; // wlr_ext_workspace_handle_v1.link struct { + struct wl_signal commit; // wlr_ext_workspace_v1_commit_event struct wl_signal destroy; } events; + void *data; + struct { struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link struct wl_event_source *idle_source; @@ -24,21 +72,17 @@ struct wlr_ext_workspace_manager_v1 { }; }; -struct wlr_ext_workspace_group_handle_v1_create_workspace_event { - const char *name; -}; - struct wlr_ext_workspace_group_handle_v1 { struct wlr_ext_workspace_manager_v1 *manager; uint32_t caps; // ext_workspace_group_handle_v1_group_capabilities struct { - struct wl_signal - create_workspace; // wlr_ext_workspace_group_handle_v1_create_workspace_event struct wl_signal destroy; } events; struct wl_list link; // wlr_ext_workspace_manager_v1.groups + void *data; + struct { struct wl_list outputs; // wlr_ext_workspace_v1_group_output.link struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link @@ -55,15 +99,13 @@ struct wlr_ext_workspace_handle_v1 { uint32_t state; // ext_workspace_handle_v1_state struct { - struct wl_signal activate; - struct wl_signal deactivate; - struct wl_signal remove; - struct wl_signal assign; // wlr_ext_workspace_group_handle_v1 struct wl_signal destroy; } events; struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces + void *data; + struct { struct wl_list resources; // wlr_ext_workspace_v1_resource.link }; @@ -96,11 +138,13 @@ void wlr_ext_workspace_handle_v1_set_group( void wlr_ext_workspace_handle_v1_set_name( struct wlr_ext_workspace_handle_v1 *workspace, const char *name); void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wl_array *coordinates); + struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords, + size_t coords_len); void wlr_ext_workspace_handle_v1_set_active( struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); void wlr_ext_workspace_handle_v1_set_urgent( struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); void wlr_ext_workspace_handle_v1_set_hidden( struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); + +#endif