From 46620d4fecd6aa484a35a41d9e8c213a316b4343 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:26:58 +0100 Subject: [PATCH 1/5] protocols: add generic output tracker Follow-up patches will use the new generic output tracker for - ext-workspaces - cosmic-workspaces - ext-foreign-toplevel-info --- include/protocols/output-tracker.h | 26 +++++ src/protocols/meson.build | 1 + src/protocols/output-tracker.c | 178 +++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 include/protocols/output-tracker.h create mode 100644 src/protocols/output-tracker.c diff --git a/include/protocols/output-tracker.h b/include/protocols/output-tracker.h new file mode 100644 index 00000000..99a67655 --- /dev/null +++ b/include/protocols/output-tracker.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LABWC_PROTOCOLS_OUTPUT_TRACKER_H +#define LABWC_PROTOCOLS_OUTPUT_TRACKER_H + +struct wl_client; +struct wl_resource; +struct wlr_output; + +struct output_tracker_impl { + void (*send_output_enter)(struct wl_resource *object, struct wl_resource *output); + void (*send_output_leave)(struct wl_resource *object, struct wl_resource *output); + /* If only_to_client is NULL, broadcast done event to all resources of object */ + void (*send_done)(void *object, struct wl_client *only_to_client); +}; + +void output_tracker_enter(void *object, struct wl_list *object_resources, + struct wlr_output *wlr_output, const struct output_tracker_impl *impl); + +void output_tracker_leave(void *object, struct wlr_output *wlr_output); + +void output_tracker_send_initial_state_to_resource( + void *object, struct wl_resource *object_resource); + +void output_tracker_destroy(void *object); + +#endif // LABWC_PROTOCOLS_OUTPUT_TRACKER_H diff --git a/src/protocols/meson.build b/src/protocols/meson.build index d9d17bf5..72f1e8fc 100644 --- a/src/protocols/meson.build +++ b/src/protocols/meson.build @@ -1,5 +1,6 @@ labwc_sources += files( 'transaction-addon.c', + 'output-tracker.c', ) subdir('cosmic_workspaces') diff --git a/src/protocols/output-tracker.c b/src/protocols/output-tracker.c new file mode 100644 index 00000000..de42fcbe --- /dev/null +++ b/src/protocols/output-tracker.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include "common/mem.h" +#include "common/list.h" +#include "protocols/output-tracker.h" + +struct object_output { + void *object; + struct wl_list *object_resources; + struct wlr_output *wlr_output; + const struct output_tracker_impl *impl; + + struct { + struct wl_listener output_bind; + struct wl_listener output_destroy; + } on; + struct wl_list link; +}; + +static struct wl_list objects = WL_LIST_INIT(&objects); + +/* Internal helpers */ +static bool +object_output_send_event(struct wl_list *object_resources, struct wl_list *output_resources, + void (*notifier)(struct wl_resource *object, struct wl_resource *output)) +{ + bool sent = false; + struct wl_client *client; + struct wl_resource *object_resource, *output_resource; + wl_resource_for_each(object_resource, object_resources) { + client = wl_resource_get_client(object_resource); + wl_resource_for_each(output_resource, output_resources) { + if (wl_resource_get_client(output_resource) == client) { + notifier(object_resource, output_resource); + sent = true; + } + } + } + return sent; +} + +static void +_object_output_destroy(struct object_output *object_output) +{ + object_output_send_event( + object_output->object_resources, + &object_output->wlr_output->resources, + object_output->impl->send_output_leave); + + wl_list_remove(&object_output->link); + wl_list_remove(&object_output->on.output_bind.link); + wl_list_remove(&object_output->on.output_destroy.link); + + if (object_output->impl->send_done) { + object_output->impl->send_done(object_output->object, /*client*/ NULL); + } + + free(object_output); +} + +/* Internal handlers */ +static void +handle_output_destroy(struct wl_listener *listener, void *data) +{ + struct object_output *object_output = + wl_container_of(listener, object_output, on.output_destroy); + _object_output_destroy(object_output); +} + +static void +handle_output_bind(struct wl_listener *listener, void *data) +{ + struct object_output *object_output = + wl_container_of(listener, object_output, on.output_bind); + + struct wlr_output_event_bind *event = data; + struct wl_client *client = wl_resource_get_client(event->resource); + + bool sent = false; + struct wl_resource *object_resource; + wl_resource_for_each(object_resource, object_output->object_resources) { + if (wl_resource_get_client(object_resource) == client) { + object_output->impl->send_output_enter(object_resource, event->resource); + sent = true; + } + } + if (!sent || !object_output->impl->send_done) { + return; + } + + object_output->impl->send_done(object_output->object, client); +} + +/* Public API */ +void +output_tracker_send_initial_state_to_resource(void *object, struct wl_resource *object_resource) +{ + struct object_output *object_output; + struct wl_client *client = wl_resource_get_client(object_resource); + wl_list_for_each(object_output, &objects, link) { + if (object_output->object != object) { + continue; + } + struct wl_resource *output_resource; + wl_resource_for_each(output_resource, &object_output->wlr_output->resources) { + if (wl_resource_get_client(output_resource) != client) { + continue; + } + object_output->impl->send_output_enter(object_resource, output_resource); + } + } +} + +void +output_tracker_enter(void *object, struct wl_list *object_resources, + struct wlr_output *wlr_output, const struct output_tracker_impl *impl) +{ + assert(impl); + assert(impl->send_output_enter); + assert(impl->send_output_leave); + struct object_output *object_output; + wl_list_for_each(object_output, &objects, link) { + if (object_output->wlr_output == wlr_output + && object_output->object == object) { + /* Object already on given output */ + return; + } + } + object_output = znew(*object_output); + object_output->object = object; + object_output->object_resources = object_resources; + object_output->wlr_output = wlr_output; + object_output->impl = impl; + + object_output->on.output_bind.notify = handle_output_bind; + wl_signal_add(&wlr_output->events.bind, &object_output->on.output_bind); + + object_output->on.output_destroy.notify = handle_output_destroy; + wl_signal_add(&wlr_output->events.destroy, &object_output->on.output_destroy); + + wl_list_insert(&objects, &object_output->link); + + bool sent = object_output_send_event( + object_resources, &wlr_output->resources, impl->send_output_enter); + + if (sent && impl->send_done) { + impl->send_done(object, /*client*/ NULL); + } +} + +void +output_tracker_destroy(void *object) +{ + struct object_output *object_output, *tmp; + wl_list_for_each_safe(object_output, tmp, &objects, link) { + if (object_output->object == object) { + _object_output_destroy(object_output); + } + } +} + +void +output_tracker_leave(void *object, struct wlr_output *wlr_output) +{ + struct object_output *tmp; + struct object_output *object_output = NULL; + wl_list_for_each(tmp, &objects, link) { + if (tmp->object == object && tmp->wlr_output == wlr_output) { + object_output = tmp; + break; + } + } + if (object_output) { + _object_output_destroy(object_output); + } +} From 1283b2e803bf60769a8b791fd4109ddbbce946e8 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:44:34 +0100 Subject: [PATCH 2/5] protocols/cosmic-workspace: use output tracker --- .../protocols/cosmic-workspaces-internal.h | 24 --- include/protocols/cosmic-workspaces.h | 2 +- .../cosmic_workspaces/cosmic-workspaces.c | 61 +++++- src/protocols/cosmic_workspaces/meson.build | 1 - src/protocols/cosmic_workspaces/output.c | 174 ------------------ 5 files changed, 58 insertions(+), 204 deletions(-) delete mode 100644 include/protocols/cosmic-workspaces-internal.h delete mode 100644 src/protocols/cosmic_workspaces/output.c diff --git a/include/protocols/cosmic-workspaces-internal.h b/include/protocols/cosmic-workspaces-internal.h deleted file mode 100644 index 50c7e75b..00000000 --- a/include/protocols/cosmic-workspaces-internal.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef LABWC_PROTOCOLS_COSMIC_WORKSPACES_INTERNAL_H -#define LABWC_PROTOCOLS_COSMIC_WORKSPACES_INTERNAL_H - -struct lab_cosmic_workspace; -struct lab_cosmic_workspace_group; -struct lab_cosmic_workspace_manager; - -enum pending_change { - /* group events */ - CW_PENDING_WS_CREATE = 1 << 0, - - /* ws events*/ - CW_PENDING_WS_ACTIVATE = 1 << 1, - CW_PENDING_WS_DEACTIVATE = 1 << 2, - CW_PENDING_WS_REMOVE = 1 << 3, -}; - -void cosmic_group_output_send_initial_state(struct lab_cosmic_workspace_group *group, - struct wl_resource *group_resource); - -void cosmic_manager_schedule_done_event(struct lab_cosmic_workspace_manager *manager); - -#endif /* LABWC_PROTOCOLS_COSMIC_WORKSPACES_INTERNAL_H */ diff --git a/include/protocols/cosmic-workspaces.h b/include/protocols/cosmic-workspaces.h index 8776bfad..55f81469 100644 --- a/include/protocols/cosmic-workspaces.h +++ b/include/protocols/cosmic-workspaces.h @@ -78,8 +78,8 @@ void lab_cosmic_workspace_group_output_enter( struct lab_cosmic_workspace_group *group, struct wlr_output *output); void lab_cosmic_workspace_group_output_leave( - struct lab_cosmic_workspace_group *group, struct wlr_output *output); + void lab_cosmic_workspace_group_destroy(struct lab_cosmic_workspace_group *group); struct lab_cosmic_workspace *lab_cosmic_workspace_create(struct lab_cosmic_workspace_group *group); diff --git a/src/protocols/cosmic_workspaces/cosmic-workspaces.c b/src/protocols/cosmic_workspaces/cosmic-workspaces.c index b39e2d17..41d24605 100644 --- a/src/protocols/cosmic_workspaces/cosmic-workspaces.c +++ b/src/protocols/cosmic_workspaces/cosmic-workspaces.c @@ -7,7 +7,7 @@ #include "common/list.h" #include "cosmic-workspace-unstable-v1-protocol.h" #include "protocols/cosmic-workspaces.h" -#include "protocols/cosmic-workspaces-internal.h" +#include "protocols/output-tracker.h" #include "protocols/transaction-addon.h" /* @@ -50,6 +50,16 @@ enum workspace_state { CW_WS_STATE_INVALID = 1 << 31, }; +enum pending_change { + /* group events */ + CW_PENDING_WS_CREATE = 1 << 0, + + /* ws events*/ + CW_PENDING_WS_ACTIVATE = 1 << 1, + CW_PENDING_WS_DEACTIVATE = 1 << 2, + CW_PENDING_WS_REMOVE = 1 << 3, +}; + struct ws_create_workspace_event { char *name; struct { @@ -57,6 +67,8 @@ struct ws_create_workspace_event { } on; }; +static void cosmic_manager_schedule_done_event(struct lab_cosmic_workspace_manager *manager); + static void add_caps(struct wl_array *caps_arr, uint32_t caps) { @@ -306,7 +318,7 @@ group_send_state(struct lab_cosmic_workspace_group *group, struct wl_resource *r zcosmic_workspace_group_handle_v1_send_capabilities( resource, &group->capabilities); - cosmic_group_output_send_initial_state(group, resource); + output_tracker_send_initial_state_to_resource(group, resource); } /* Manager itself */ @@ -461,8 +473,7 @@ manager_idle_send_done(void *data) manager->idle_source = NULL; } -/* Internal API */ -void +static void cosmic_manager_schedule_done_event(struct lab_cosmic_workspace_manager *manager) { if (manager->idle_source) { @@ -475,6 +486,31 @@ cosmic_manager_schedule_done_event(struct lab_cosmic_workspace_manager *manager) manager->event_loop, manager_idle_send_done, manager); } +/* Output tracker */ +static void +handle_output_tracker_send_done(void *object, struct wl_client *client) +{ + struct lab_cosmic_workspace_group *group = object; + if (!client) { + cosmic_manager_schedule_done_event(group->manager); + return; + } + + struct wl_resource *manager_resource; + struct wl_list *manager_resources = &group->manager->resources; + wl_resource_for_each(manager_resource, manager_resources) { + if (wl_resource_get_client(manager_resource) == client) { + zcosmic_workspace_manager_v1_send_done(manager_resource); + } + } +} + +static const struct output_tracker_impl output_tracker_impl = { + .send_output_enter = zcosmic_workspace_group_handle_v1_send_output_enter, + .send_output_leave = zcosmic_workspace_group_handle_v1_send_output_leave, + .send_done = handle_output_tracker_send_done, +}; + /* Public API */ struct lab_cosmic_workspace_manager * lab_cosmic_workspace_manager_create(struct wl_display *display, uint32_t caps, uint32_t version) @@ -535,6 +571,20 @@ lab_cosmic_workspace_group_create(struct lab_cosmic_workspace_manager *manager) return group; } +void +lab_cosmic_workspace_group_output_enter(struct lab_cosmic_workspace_group *group, + struct wlr_output *wlr_output) +{ + output_tracker_enter(group, &group->resources, wlr_output, &output_tracker_impl); +} + +void +lab_cosmic_workspace_group_output_leave(struct lab_cosmic_workspace_group *group, + struct wlr_output *wlr_output) +{ + output_tracker_leave(group, wlr_output); +} + void lab_cosmic_workspace_group_destroy(struct lab_cosmic_workspace_group *group) { @@ -543,6 +593,9 @@ lab_cosmic_workspace_group_destroy(struct lab_cosmic_workspace_group *group) } wl_signal_emit_mutable(&group->events.destroy, NULL); + /* Ensure output leave events are sent and tracker resources are destroyed */ + output_tracker_destroy(group); + struct lab_cosmic_workspace *ws, *ws_tmp; wl_list_for_each_safe(ws, ws_tmp, &group->workspaces, link) { lab_cosmic_workspace_destroy(ws); diff --git a/src/protocols/cosmic_workspaces/meson.build b/src/protocols/cosmic_workspaces/meson.build index 31ce18b8..3b704f95 100644 --- a/src/protocols/cosmic_workspaces/meson.build +++ b/src/protocols/cosmic_workspaces/meson.build @@ -1,4 +1,3 @@ labwc_sources += files( 'cosmic-workspaces.c', - 'output.c', ) diff --git a/src/protocols/cosmic_workspaces/output.c b/src/protocols/cosmic_workspaces/output.c deleted file mode 100644 index 1e170e85..00000000 --- a/src/protocols/cosmic_workspaces/output.c +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include "common/mem.h" -#include "cosmic-workspace-unstable-v1-protocol.h" -#include "protocols/cosmic-workspaces.h" -#include "protocols/cosmic-workspaces-internal.h" - -struct group_output { - struct wlr_output *wlr_output; - struct lab_cosmic_workspace_group *group; - struct { - struct wl_listener group_destroy; - struct wl_listener output_bind; - struct wl_listener output_destroy; - } on; - - struct wl_list link; -}; - -/* Internal helpers */ -static void -group_output_send_event(struct wl_list *group_resources, struct wl_list *output_resources, - void (*notifier)(struct wl_resource *group, struct wl_resource *output)) -{ - struct wl_client *client; - struct wl_resource *group_resource, *output_resource; - wl_resource_for_each(group_resource, group_resources) { - client = wl_resource_get_client(group_resource); - wl_resource_for_each(output_resource, output_resources) { - if (wl_resource_get_client(output_resource) == client) { - notifier(group_resource, output_resource); - } - } - } -} - -static void -group_output_destroy(struct group_output *group_output) -{ - group_output_send_event( - &group_output->group->resources, - &group_output->wlr_output->resources, - zcosmic_workspace_group_handle_v1_send_output_leave); - - cosmic_manager_schedule_done_event(group_output->group->manager); - - wl_list_remove(&group_output->link); - wl_list_remove(&group_output->on.group_destroy.link); - wl_list_remove(&group_output->on.output_bind.link); - wl_list_remove(&group_output->on.output_destroy.link); - free(group_output); -} - -/* Event handlers */ -static void -handle_output_bind(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.output_bind); - - struct wlr_output_event_bind *event = data; - struct wl_client *client = wl_resource_get_client(event->resource); - - bool sent = false; - struct wl_resource *group_resource; - wl_resource_for_each(group_resource, &group_output->group->resources) { - if (wl_resource_get_client(group_resource) == client) { - zcosmic_workspace_group_handle_v1_send_output_enter( - group_resource, event->resource); - sent = true; - } - } - if (!sent) { - return; - } - - struct wl_resource *manager_resource; - struct wl_list *manager_resources = &group_output->group->manager->resources; - wl_resource_for_each(manager_resource, manager_resources) { - if (wl_resource_get_client(manager_resource) == client) { - zcosmic_workspace_manager_v1_send_done(manager_resource); - } - } -} - -static void -handle_output_destroy(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.output_destroy); - group_output_destroy(group_output); -} - -static void -handle_group_destroy(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.group_destroy); - group_output_destroy(group_output); -} - -/* Internal API*/ -void -cosmic_group_output_send_initial_state(struct lab_cosmic_workspace_group *group, - struct wl_resource *group_resource) -{ - struct group_output *group_output; - struct wl_resource *output_resource; - struct wl_client *client = wl_resource_get_client(group_resource); - wl_list_for_each(group_output, &group->outputs, link) { - wl_resource_for_each(output_resource, &group_output->wlr_output->resources) { - if (wl_resource_get_client(output_resource) == client) { - zcosmic_workspace_group_handle_v1_send_output_enter( - group_resource, output_resource); - } - } - } -} - -/* Public API */ -void -lab_cosmic_workspace_group_output_enter(struct lab_cosmic_workspace_group *group, - struct wlr_output *wlr_output) -{ - struct group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - if (group_output->wlr_output == wlr_output) { - return; - } - } - group_output = znew(*group_output); - group_output->wlr_output = wlr_output; - group_output->group = group; - - group_output->on.group_destroy.notify = handle_group_destroy; - wl_signal_add(&group->events.destroy, &group_output->on.group_destroy); - - group_output->on.output_bind.notify = handle_output_bind; - wl_signal_add(&wlr_output->events.bind, &group_output->on.output_bind); - - group_output->on.output_destroy.notify = handle_output_destroy; - wl_signal_add(&wlr_output->events.destroy, &group_output->on.output_destroy); - - wl_list_insert(&group->outputs, &group_output->link); - - group_output_send_event( - &group_output->group->resources, - &group_output->wlr_output->resources, - zcosmic_workspace_group_handle_v1_send_output_enter); - - cosmic_manager_schedule_done_event(group->manager); -} - -void -lab_cosmic_workspace_group_output_leave(struct lab_cosmic_workspace_group *group, - struct wlr_output *wlr_output) -{ - struct group_output *tmp; - struct group_output *group_output = NULL; - wl_list_for_each(tmp, &group->outputs, link) { - if (tmp->wlr_output == wlr_output) { - group_output = tmp; - break; - } - } - if (!group_output) { - wlr_log(WLR_ERROR, "output %s was never entered", wlr_output->name); - return; - } - - group_output_destroy(group_output); -} From 5004f181bf1550e83bcf2a33a6e951109af11985 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:54:12 +0100 Subject: [PATCH 3/5] protocols/ext-workspace: use output tracker --- include/protocols/ext-workspace-internal.h | 25 --- src/protocols/ext-workspace/ext-workspace.c | 62 ++++++- src/protocols/ext-workspace/meson.build | 1 - src/protocols/ext-workspace/output.c | 174 -------------------- 4 files changed, 58 insertions(+), 204 deletions(-) delete mode 100644 include/protocols/ext-workspace-internal.h delete mode 100644 src/protocols/ext-workspace/output.c diff --git a/include/protocols/ext-workspace-internal.h b/include/protocols/ext-workspace-internal.h deleted file mode 100644 index c5e7575f..00000000 --- a/include/protocols/ext-workspace-internal.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef LABWC_PROTOCOLS_EXT_WORKSPACES_INTERNAL_H -#define LABWC_PROTOCOLS_EXT_WORKSPACES_INTERNAL_H - -struct wl_resource; -struct lab_ext_workspace_group; -struct lab_ext_workspace_manager; - -enum pending_ext_workspaces_change { - /* group events */ - WS_PENDING_WS_CREATE = 1 << 0, - - /* ws events*/ - WS_PENDING_WS_ACTIVATE = 1 << 1, - WS_PENDING_WS_DEACTIVATE = 1 << 2, - WS_PENDING_WS_REMOVE = 1 << 3, - WS_PENDING_WS_ASSIGN = 1 << 4, -}; - -void ext_group_output_send_initial_state(struct lab_ext_workspace_group *group, - struct wl_resource *group_resource); - -void ext_manager_schedule_done_event(struct lab_ext_workspace_manager *manager); - -#endif /* LABWC_PROTOCOLS_EXT_WORKSPACES_INTERNAL_H */ diff --git a/src/protocols/ext-workspace/ext-workspace.c b/src/protocols/ext-workspace/ext-workspace.c index 92032375..03858c78 100644 --- a/src/protocols/ext-workspace/ext-workspace.c +++ b/src/protocols/ext-workspace/ext-workspace.c @@ -7,7 +7,7 @@ #include "common/list.h" #include "ext-workspace-v1-protocol.h" #include "protocols/ext-workspace.h" -#include "protocols/ext-workspace-internal.h" +#include "protocols/output-tracker.h" #include "protocols/transaction-addon.h" /* @@ -32,6 +32,17 @@ */ #define WS_STATE_INVALID 0xffffffff +enum pending_ext_workspaces_change { + /* group events */ + WS_PENDING_WS_CREATE = 1 << 0, + + /* ws events*/ + WS_PENDING_WS_ACTIVATE = 1 << 1, + WS_PENDING_WS_DEACTIVATE = 1 << 2, + WS_PENDING_WS_REMOVE = 1 << 3, + WS_PENDING_WS_ASSIGN = 1 << 4, +}; + struct ws_create_workspace_event { char *name; struct { @@ -39,6 +50,8 @@ struct ws_create_workspace_event { } on; }; +static void ext_manager_schedule_done_event(struct lab_ext_workspace_manager *manager); + /* Workspace */ static void workspace_handle_destroy(struct wl_client *client, struct wl_resource *resource) @@ -278,7 +291,7 @@ group_send_state(struct lab_ext_workspace_group *group, struct wl_resource *reso ext_workspace_group_handle_v1_send_capabilities( resource, group->capabilities); - ext_group_output_send_initial_state(group, resource); + output_tracker_send_initial_state_to_resource(group, resource); } /* Manager itself */ @@ -453,8 +466,7 @@ manager_idle_send_done(void *data) manager->idle_source = NULL; } -/* Internal API */ -void +static void ext_manager_schedule_done_event(struct lab_ext_workspace_manager *manager) { if (manager->idle_source) { @@ -467,6 +479,31 @@ ext_manager_schedule_done_event(struct lab_ext_workspace_manager *manager) manager->event_loop, manager_idle_send_done, manager); } +/* Output tracker */ +static void +handle_output_tracker_send_done(void *object, struct wl_client *client) +{ + struct lab_ext_workspace_group *group = object; + if (!client) { + ext_manager_schedule_done_event(group->manager); + return; + } + + struct wl_resource *manager_resource; + struct wl_list *manager_resources = &group->manager->resources; + wl_resource_for_each(manager_resource, manager_resources) { + if (wl_resource_get_client(manager_resource) == client) { + ext_workspace_manager_v1_send_done(manager_resource); + } + } +} + +static const struct output_tracker_impl output_tracker_impl = { + .send_output_enter = ext_workspace_group_handle_v1_send_output_enter, + .send_output_leave = ext_workspace_group_handle_v1_send_output_leave, + .send_done = handle_output_tracker_send_done, +}; + static void send_group_workspace_event(struct lab_ext_workspace_group *group, struct lab_ext_workspace *workspace, @@ -546,12 +583,29 @@ lab_ext_workspace_group_create(struct lab_ext_workspace_manager *manager) return group; } +void +lab_ext_workspace_group_output_enter(struct lab_ext_workspace_group *group, + struct wlr_output *wlr_output) +{ + output_tracker_enter(group, &group->resources, wlr_output, &output_tracker_impl); +} + +void +lab_ext_workspace_group_output_leave(struct lab_ext_workspace_group *group, + struct wlr_output *wlr_output) +{ + output_tracker_leave(group, wlr_output); +} + void lab_ext_workspace_group_destroy(struct lab_ext_workspace_group *group) { assert(group); wl_signal_emit_mutable(&group->events.destroy, NULL); + /* Ensure output leave events are sent and tracker resources are destroyed */ + output_tracker_destroy(group); + struct lab_ext_workspace *workspace; wl_list_for_each(workspace, &group->manager->workspaces, link) { if (workspace->group == group) { diff --git a/src/protocols/ext-workspace/meson.build b/src/protocols/ext-workspace/meson.build index e781d13a..b21a17c3 100644 --- a/src/protocols/ext-workspace/meson.build +++ b/src/protocols/ext-workspace/meson.build @@ -1,4 +1,3 @@ labwc_sources += files( 'ext-workspace.c', - 'output.c', ) diff --git a/src/protocols/ext-workspace/output.c b/src/protocols/ext-workspace/output.c deleted file mode 100644 index 0d6a2a44..00000000 --- a/src/protocols/ext-workspace/output.c +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include -#include -#include -#include "common/mem.h" -#include "ext-workspace-v1-protocol.h" -#include "protocols/ext-workspace.h" -#include "protocols/ext-workspace-internal.h" - -struct group_output { - struct wlr_output *wlr_output; - struct lab_ext_workspace_group *group; - struct { - struct wl_listener group_destroy; - struct wl_listener output_bind; - struct wl_listener output_destroy; - } on; - - struct wl_list link; -}; - -/* Internal helpers */ -static void -group_output_send_event(struct wl_list *group_resources, struct wl_list *output_resources, - void (*notifier)(struct wl_resource *group, struct wl_resource *output)) -{ - struct wl_client *client; - struct wl_resource *group_resource, *output_resource; - wl_resource_for_each(group_resource, group_resources) { - client = wl_resource_get_client(group_resource); - wl_resource_for_each(output_resource, output_resources) { - if (wl_resource_get_client(output_resource) == client) { - notifier(group_resource, output_resource); - } - } - } -} - -static void -group_output_destroy(struct group_output *group_output) -{ - group_output_send_event( - &group_output->group->resources, - &group_output->wlr_output->resources, - ext_workspace_group_handle_v1_send_output_leave); - - ext_manager_schedule_done_event(group_output->group->manager); - - wl_list_remove(&group_output->link); - wl_list_remove(&group_output->on.group_destroy.link); - wl_list_remove(&group_output->on.output_bind.link); - wl_list_remove(&group_output->on.output_destroy.link); - free(group_output); -} - -/* Event handlers */ -static void -handle_output_bind(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.output_bind); - - struct wlr_output_event_bind *event = data; - struct wl_client *client = wl_resource_get_client(event->resource); - - bool sent = false; - struct wl_resource *group_resource; - wl_resource_for_each(group_resource, &group_output->group->resources) { - if (wl_resource_get_client(group_resource) == client) { - ext_workspace_group_handle_v1_send_output_enter( - group_resource, event->resource); - sent = true; - } - } - if (!sent) { - return; - } - - struct wl_resource *manager_resource; - struct wl_list *manager_resources = &group_output->group->manager->resources; - wl_resource_for_each(manager_resource, manager_resources) { - if (wl_resource_get_client(manager_resource) == client) { - ext_workspace_manager_v1_send_done(manager_resource); - } - } -} - -static void -handle_output_destroy(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.output_destroy); - group_output_destroy(group_output); -} - -static void -handle_group_destroy(struct wl_listener *listener, void *data) -{ - struct group_output *group_output = - wl_container_of(listener, group_output, on.group_destroy); - group_output_destroy(group_output); -} - -/* Internal API*/ -void -ext_group_output_send_initial_state(struct lab_ext_workspace_group *group, - struct wl_resource *group_resource) -{ - struct group_output *group_output; - struct wl_resource *output_resource; - struct wl_client *client = wl_resource_get_client(group_resource); - wl_list_for_each(group_output, &group->outputs, link) { - wl_resource_for_each(output_resource, &group_output->wlr_output->resources) { - if (wl_resource_get_client(output_resource) == client) { - ext_workspace_group_handle_v1_send_output_enter( - group_resource, output_resource); - } - } - } -} - -/* Public API */ -void -lab_ext_workspace_group_output_enter(struct lab_ext_workspace_group *group, - struct wlr_output *wlr_output) -{ - struct group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - if (group_output->wlr_output == wlr_output) { - return; - } - } - group_output = znew(*group_output); - group_output->wlr_output = wlr_output; - group_output->group = group; - - group_output->on.group_destroy.notify = handle_group_destroy; - wl_signal_add(&group->events.destroy, &group_output->on.group_destroy); - - group_output->on.output_bind.notify = handle_output_bind; - wl_signal_add(&wlr_output->events.bind, &group_output->on.output_bind); - - group_output->on.output_destroy.notify = handle_output_destroy; - wl_signal_add(&wlr_output->events.destroy, &group_output->on.output_destroy); - - wl_list_insert(&group->outputs, &group_output->link); - - group_output_send_event( - &group_output->group->resources, - &group_output->wlr_output->resources, - ext_workspace_group_handle_v1_send_output_enter); - - ext_manager_schedule_done_event(group->manager); -} - -void -lab_ext_workspace_group_output_leave(struct lab_ext_workspace_group *group, - struct wlr_output *wlr_output) -{ - struct group_output *tmp; - struct group_output *group_output = NULL; - wl_list_for_each(tmp, &group->outputs, link) { - if (tmp->wlr_output == wlr_output) { - group_output = tmp; - break; - } - } - if (!group_output) { - wlr_log(WLR_ERROR, "output %s was never entered", wlr_output->name); - return; - } - - group_output_destroy(group_output); -} From ed6172c9218c53534ea217d47a5079c73b4af9fe Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Mon, 10 Feb 2025 03:11:01 +0100 Subject: [PATCH 4/5] [fixup] output tracker readability --- src/protocols/output-tracker.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/protocols/output-tracker.c b/src/protocols/output-tracker.c index de42fcbe..5a5e5d95 100644 --- a/src/protocols/output-tracker.c +++ b/src/protocols/output-tracker.c @@ -86,11 +86,9 @@ handle_output_bind(struct wl_listener *listener, void *data) sent = true; } } - if (!sent || !object_output->impl->send_done) { - return; + if (sent && object_output->impl->send_done) { + object_output->impl->send_done(object_output->object, client); } - - object_output->impl->send_done(object_output->object, client); } /* Public API */ @@ -142,8 +140,8 @@ output_tracker_enter(void *object, struct wl_list *object_resources, wl_list_insert(&objects, &object_output->link); - bool sent = object_output_send_event( - object_resources, &wlr_output->resources, impl->send_output_enter); + bool sent = object_output_send_event(object_resources, + &wlr_output->resources, impl->send_output_enter); if (sent && impl->send_done) { impl->send_done(object, /*client*/ NULL); From ee18ad1f064a412f30d2de76ecbc5ae394320d67 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Mon, 10 Feb 2025 03:12:12 +0100 Subject: [PATCH 5/5] [fixup] output tracker outdated include --- src/protocols/output-tracker.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/protocols/output-tracker.c b/src/protocols/output-tracker.c index 5a5e5d95..50ef0436 100644 --- a/src/protocols/output-tracker.c +++ b/src/protocols/output-tracker.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include -#include #include "common/mem.h" #include "common/list.h" #include "protocols/output-tracker.h"