From 754fb31f047521b90805e00a0bd28094eece48f4 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 7 Apr 2020 12:55:59 +0200 Subject: [PATCH 1/6] wlr-workspace: first version add wlr-workspace header start wlr_workspace impl by copying from wlr_foreign_toplevel add more stubs workspace: implement output_enter/leave add create methods start with impl destroy finish impelmenttation of workspace-unstable implement wlr-workspace example small fixes to the example client fix names as requested in review --- examples/meson.build | 5 + examples/wlr-workspace.c | 338 +++++++++++++++ include/wlr/types/wlr_workspace_v1.h | 122 ++++++ protocol/meson.build | 1 + protocol/wlr-workspace-unstable-v1.xml | 270 ++++++++++++ types/meson.build | 1 + types/wlr_workspace_v1.c | 544 +++++++++++++++++++++++++ 7 files changed, 1281 insertions(+) create mode 100644 examples/wlr-workspace.c create mode 100644 include/wlr/types/wlr_workspace_v1.h create mode 100644 protocol/wlr-workspace-unstable-v1.xml create mode 100644 types/wlr_workspace_v1.c diff --git a/examples/meson.build b/examples/meson.build index 1ce02f0d4..e9d79a5a6 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -185,6 +185,11 @@ clients = { 'input-method-unstable-v2', ], }, + 'wlr-workspace': { + 'src': 'wlr-workspace.c', + 'dep': [wlroots], + 'proto': ['wlr-workspace-unstable-v1'], + }, } foreach name, info : compositors diff --git a/examples/wlr-workspace.c b/examples/wlr-workspace.c new file mode 100644 index 000000000..eab65a28c --- /dev/null +++ b/examples/wlr-workspace.c @@ -0,0 +1,338 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include "wlr-workspace-unstable-v1-client-protocol.h" + +#define WLR_WORKSPACE_VERSION 1 + +/** + * Usage: + * 1. wlr-workspace + * List all workspace groups and their workspaces + * 2. wlr-workspace -w X + * Focus workspace with name X + * 3. wlr-workspace -m + * Continuously monitor for changes and print new state. + */ + +enum workspace_state_field { + WORKSPACE_FOCUSED = (1 << 0), +}; + +struct workspace_state { + char *name; + struct wl_array coordinates; + uint32_t state; +}; + +static void copy_state(struct workspace_state *current, + struct workspace_state *pending) { + + current->state = pending->state; + wl_array_copy(¤t->coordinates, &pending->coordinates); + + if (pending->name) { + free(current->name); + current->name = pending->name; + pending->name = NULL; + } +} + +struct workspace_v1 { + struct wl_list link; + struct zwlr_workspace_handle_v1 *handle; + struct workspace_state current, pending; +}; + +static void print_workspace(struct workspace_v1 *workspace) { + printf("--> workspace name=%s, focused=%d, coordinates=(", + workspace->current.name ?: "(n/a)", + !!(workspace->current.state & WORKSPACE_FOCUSED)); + + bool is_first = true; + int32_t *pos; + wl_array_for_each(pos, &workspace->current.coordinates) { + if (!is_first) { + printf(","); + } + printf("%d", *pos); + is_first = false; + } + + printf(")\n"); +} + +static uint32_t array_to_state(struct wl_array *array) { + uint32_t state = 0; + uint32_t *entry; + wl_array_for_each(entry, array) { + if (*entry == ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) + state |= WORKSPACE_FOCUSED; + } + + return state; +} + + +static void workspace_handle_name(void *data, + struct zwlr_workspace_handle_v1 *workspace_handle_v1, + const char *name) { + struct workspace_v1 *workspace = (struct workspace_v1*) + zwlr_workspace_handle_v1_get_user_data(workspace_handle_v1); + + free(workspace->pending.name); + workspace->pending.name = strdup(name); +} + +static void workspace_handle_coordinates(void *data, + struct zwlr_workspace_handle_v1 *workspace_handle, + struct wl_array *coordinates) { + struct workspace_v1 *workspace = (struct workspace_v1*) + zwlr_workspace_handle_v1_get_user_data(workspace_handle); + wl_array_copy(&workspace->pending.coordinates, coordinates); +} + +static void workspace_handle_state(void *data, + struct zwlr_workspace_handle_v1 *workspace_handle, + struct wl_array *state) { + struct workspace_v1 *workspace = (struct workspace_v1*) + zwlr_workspace_handle_v1_get_user_data(workspace_handle); + workspace->pending.state = array_to_state(state); +} + +static void workspace_handle_remove(void *data, + struct zwlr_workspace_handle_v1 *workspace_handle) { + struct workspace_v1 *workspace = (struct workspace_v1*) + zwlr_workspace_handle_v1_get_user_data(workspace_handle); + zwlr_workspace_handle_v1_destroy(workspace_handle); + + wl_list_remove(&workspace->link); + free(workspace->current.name); + free(workspace->pending.name); + wl_array_release(&workspace->pending.coordinates); + wl_array_release(&workspace->current.coordinates); + free(workspace); +} + +static const struct zwlr_workspace_handle_v1_listener workspace_listener = { + .name = workspace_handle_name, + .coordinates = workspace_handle_coordinates, + .state = workspace_handle_state, + .remove = workspace_handle_remove, +}; + +struct group_v1 { + struct wl_list link; + + int32_t id; + struct wl_list workspaces; +}; + +static void group_handle_output_enter(void *data, + struct zwlr_workspace_group_handle_v1 *group_handle, + struct wl_output *output) { + struct group_v1 *group = (struct group_v1*) + zwlr_workspace_group_handle_v1_get_user_data(group_handle); + printf("Group %d output_enter %u\n", group->id, + (uint32_t)(size_t)wl_output_get_user_data(output)); +} + +static void group_handle_output_leave(void *data, + struct zwlr_workspace_group_handle_v1 *group_handle, + struct wl_output *output) { + struct group_v1 *group = (struct group_v1*) + zwlr_workspace_group_handle_v1_get_user_data(group_handle); + printf("Group %d output_leave %u\n", group->id, + (uint32_t)(size_t)wl_output_get_user_data(output)); +} + +static void group_handle_workspace(void *data, + struct zwlr_workspace_group_handle_v1 *group_handle, + struct zwlr_workspace_handle_v1 *workspace_handle) { + struct group_v1 *group = (struct group_v1*) + zwlr_workspace_group_handle_v1_get_user_data(group_handle); + struct workspace_v1 *workspace = (struct workspace_v1*) + calloc(1, sizeof(struct workspace_v1)); + + wl_list_insert(&group->workspaces, &workspace->link); + wl_array_init(&workspace->pending.coordinates); + wl_array_init(&workspace->current.coordinates); + + workspace->handle = workspace_handle; + zwlr_workspace_handle_v1_add_listener(workspace_handle, + &workspace_listener, NULL); + zwlr_workspace_handle_v1_set_user_data(workspace_handle, workspace); +} + +static void group_handle_remove(void *data, + struct zwlr_workspace_group_handle_v1 *group_handle) { + struct group_v1 *group = (struct group_v1*) + zwlr_workspace_group_handle_v1_get_user_data(group_handle); + wl_list_remove(&group->link); + if (!wl_list_empty(&group->workspaces)) { + printf("Compositor bug! Group destroyed before its workspaces.\n"); + } + + free(group); +} + +static const struct zwlr_workspace_group_handle_v1_listener group_listener = { + .output_enter = group_handle_output_enter, + .output_leave = group_handle_output_leave, + .workspace = group_handle_workspace, + .remove = group_handle_remove, +}; + +static struct zwlr_workspace_manager_v1 *workspace_manager = NULL; +static struct wl_list group_list; +static int32_t last_group_id = 0; + +static void workspace_manager_handle_workspace_group(void *data, + struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1, + struct zwlr_workspace_group_handle_v1 *workspace_group) { + struct group_v1 *group = (struct group_v1*) + calloc(1, sizeof(struct group_v1)); + group->id = last_group_id++; + wl_list_init(&group->workspaces); + wl_list_insert(&group_list, &group->link); + + zwlr_workspace_group_handle_v1_add_listener(workspace_group, + &group_listener, NULL); + zwlr_workspace_group_handle_v1_set_user_data(workspace_group, group); +} + +static void workspace_manager_handle_done(void *data, + struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1) { + + printf("*** Workspace configuration ***\n"); + struct group_v1 *group; + wl_list_for_each(group, &group_list, link) { + printf("> Group id=%d\n", group->id); + struct workspace_v1 *workspace; + wl_list_for_each(workspace, &group->workspaces, link) { + copy_state(&workspace->current, &workspace->pending); + print_workspace(workspace); + } + } +} + +static void workspace_manager_handle_finished(void *data, + struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1) { + zwlr_workspace_manager_v1_destroy(zwlr_workspace_manager_v1); +} + +static const struct zwlr_workspace_manager_v1_listener workspace_manager_impl = { + .workspace_group = workspace_manager_handle_workspace_group, + .done = workspace_manager_handle_done, + .finished = workspace_manager_handle_finished, +}; + +struct wl_seat *seat = NULL; +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct wl_output *output = wl_registry_bind(registry, name, + &wl_output_interface, version); + wl_output_set_user_data(output, (void*)(size_t)name); // assign some ID to the output + } else if (strcmp(interface, + zwlr_workspace_manager_v1_interface.name) == 0) { + workspace_manager = wl_registry_bind(registry, name, + &zwlr_workspace_manager_v1_interface, WLR_WORKSPACE_VERSION); + + wl_list_init(&group_list); + zwlr_workspace_manager_v1_add_listener(workspace_manager, + &workspace_manager_impl, NULL); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static struct workspace_v1 *workspace_by_name_or_bail(const char *name) { + struct workspace_v1 *workspace; + struct group_v1 *group; + + wl_list_for_each(group, &group_list, link) { + wl_list_for_each(workspace, &group->workspaces, link) { + if (workspace->current.name && + strcmp(workspace->current.name, name) == 0) { + return workspace; + } + } + } + + fprintf(stderr, "No workspace with the given name: %s\n", name); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + int c; + char *focus_name = NULL; + bool monitor = false; + + while ((c = getopt(argc, argv, "w:m")) != -1) { + switch (c) { + case 'w': + focus_name = strdup(optarg); + break; + case 'm': + monitor = true; + break; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (workspace_manager == NULL) { + fprintf(stderr, "wlr-workspace not available\n"); + return EXIT_FAILURE; + } + wl_display_roundtrip(display); // load workspace groups + wl_display_roundtrip(display); // load details + + if (focus_name != NULL) { + struct workspace_v1 *focus = workspace_by_name_or_bail(focus_name); + + // unfocus all workspaces + struct workspace_v1 *workspace; + struct group_v1 *group; + + wl_list_for_each(group, &group_list, link) { + wl_list_for_each(workspace, &group->workspaces, link) { + zwlr_workspace_handle_v1_deactivate(workspace->handle); + } + } + zwlr_workspace_handle_v1_activate(focus->handle); + zwlr_workspace_manager_v1_commit(workspace_manager); + } + + wl_display_flush(display); + + if (monitor != false) { + while (wl_display_dispatch(display) != -1) { + // This space intentionally left blank + } + } + + return EXIT_SUCCESS; +} diff --git a/include/wlr/types/wlr_workspace_v1.h b/include/wlr/types/wlr_workspace_v1.h new file mode 100644 index 000000000..0e6d6a0fb --- /dev/null +++ b/include/wlr/types/wlr_workspace_v1.h @@ -0,0 +1,122 @@ +/* + * 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_WORKSPACE_V1_H +#define WLR_TYPES_WLR_WORKSPACE_V1_H + +#include +#include + +struct wlr_workspace_manager_v1 { + struct wl_event_loop *event_loop; + struct wl_event_source *idle_source; + + struct wl_global *global; + struct wl_list resources; // wl_resource_get_link + struct wl_list groups; // wlr_workspace_group_handle_v1::link + + struct wl_listener display_destroy; + + struct { + struct wl_signal commit; // wlr_workspace_manager_v1 + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_workspace_group_handle_v1 { + struct wl_list link; // wlr_workspace_manager_v1::groups + struct wl_list resources; // wl_resource_get_link + + struct wl_list workspaces; // wlr_workspace_handle_v1::link + struct wl_list outputs; // wlr_workspace_group_handle_v1_output::link + + struct wlr_workspace_manager_v1 *manager; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_workspace_group_handle_v1_output { + struct wl_list link; // wlr_workspace_group_handle_v1::outputs + struct wl_listener output_destroy; + struct wlr_output *output; + + struct wlr_workspace_group_handle_v1 *group_handle; +}; + +enum wlr_workspace_handle_v1_state +{ + WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE = 1 << 0, +}; + +struct wlr_workspace_handle_v1 { + struct wl_list link; // wlr_workspace_group_handle_v1::workspaces + struct wl_list resources; + + struct wlr_workspace_group_handle_v1 *group; + + // request from the client + uint32_t pending, current; + + // set by the compositor + uint32_t server_state; + + char *name; + struct wl_array coordinates; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_workspace_manager_v1 *wlr_workspace_manager_v1_create( + struct wl_display *display); + +struct wlr_workspace_group_handle_v1 *wlr_workspace_group_handle_v1_create( + struct wlr_workspace_manager_v1 *manager); + +/** + * Destroy the workspace group and all workspaces inside it. + */ +void wlr_workspace_group_handle_v1_destroy( + struct wlr_workspace_group_handle_v1 *group); + +/** + * Create a new workspace in the workspace group. + * Note that the compositor must set the workspace name immediately after + * creating it. + */ +struct wlr_workspace_handle_v1 *wlr_workspace_handle_v1_create( + struct wlr_workspace_group_handle_v1 *group); + +void wlr_workspace_handle_v1_destroy( + struct wlr_workspace_handle_v1 *workspace); + +void wlr_workspace_group_handle_v1_output_enter( + struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output); + +void wlr_workspace_group_handle_v1_output_leave( + struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output); + +void wlr_workspace_handle_v1_set_name(struct wlr_workspace_handle_v1 *workspace, + const char* name); + +void wlr_workspace_handle_v1_set_coordinates( + struct wlr_workspace_handle_v1 *workspace, struct wl_array *coordinates); + +void wlr_workspace_handle_v1_set_active( + struct wlr_workspace_handle_v1 *workspace, bool active); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 87d944a1a..fc05bc61a 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -43,6 +43,7 @@ protocols = { 'wlr-output-power-management-unstable-v1': 'wlr-output-power-management-unstable-v1.xml', 'wlr-screencopy-unstable-v1': 'wlr-screencopy-unstable-v1.xml', 'wlr-virtual-pointer-unstable-v1': 'wlr-virtual-pointer-unstable-v1.xml', + 'wlr-workspace-unstable-v1': 'wlr-workspace-unstable-v1.xml', } protocols_code = {} diff --git a/protocol/wlr-workspace-unstable-v1.xml b/protocol/wlr-workspace-unstable-v1.xml new file mode 100644 index 000000000..ae0e44dbb --- /dev/null +++ b/protocol/wlr-workspace-unstable-v1.xml @@ -0,0 +1,270 @@ + + + + Copyright © 2019 Christopher Billington + Copyright © 2020 Ilia Bozhinov + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Workspaces, also called virtual desktops, are groups of surfaces. A + compositor with a concept of workspaces may only show some such groups of + surfaces (those of 'active' workspaces) at a time. 'Activating' a + workspace is a request for the compositor to display that workspace's + surfaces as normal, whereas the compositor may hide or otherwise + de-emphasise surfaces that are associated only with 'inactive' workspaces. + Workspaces are grouped by which sets of outputs they correspond to, and + may contain surfaces only from those outputs. In this way, it is possible + for each output to have its own set of workspaces, or for all outputs (or + any other arbitrary grouping) to share workspaces. Compositors may + optionally conceptually arrange each group of workspaces in an + N-dimensional grid. + + The purpose of this protocol is to enable the creation of taskbars and + docks by providing them with a list of workspaces and their properties, + and allowing them to activate and deactivate workspaces. + + After a client binds the zwlr_workspace_manager_v1, each workspace will be + sent via the workspace event. + + + + + This event is emitted whenever a new workspace group has been created. + + All initial details of the workspace group (workspaces, outputs) will be + sent immediately after this event via the corresponding events in + zwlr_workspace_group_handle_v1. + + + + + + + The client must send this request after it has finished sending other + requests. The compositor must process a series of requests preceding a + commit request atomically. + + This allows changes to the workspace properties to be seen as atomic, + even if they happen via multiple events, and even if they involve + multiple zwlr_workspace_handle_v1 objects, for example, deactivating one + workspace and activating another. + + + + + + This event is sent after all changes in all workspace groups have been + sent. + + This allows changes to one or more zwlr_workspace_group_handle_v1 + properties to be seen as atomic, even if they happen via multiple + events. In particular, an output moving from one workspace group to + another sends an output_enter event and an output_leave event to the two + zwlr_workspace_group_handle_v1 objects in question. The compositor sends + the done event only after updating the output information in both + workspace groups. + + + + + + This event indicates that the compositor is done sending events to the + zwlr_workspace_manager_v1. The server will destroy the object + immediately after sending this request, so it will become invalid and + the client should free any resources associated with it. + + + + + + Indicates the client no longer wishes to receive events for new + workspace groups. However the compositor may emit further workspace + events, until the finished event is emitted. + + The client must not send any more requests after this one. + + + + + + + A zwlr_workspace_group_handle_v1 object represents a a workspace group + that is assigned a set of outputs and contains a number of workspaces. + + The set of outputs assigned to the workspace group is conveyed to the client via + output_enter and output_leave events, and its workspaces are conveyed with + workspace events. + + + + + This event is emitted whenever an output is assigned to the workspace + group. + + + + + + + This event is emitted whenever an output is removed from the workspace + group. + + + + + + + This event is emitted whenever a new workspace has been created. + + All initial details of the workspace (name, coordinates, state) will + be sent immediately after this event via the corresponding events in + zwlr_workspace_handle_v1. + + + + + + + This event means the zwlr_workspace_group_handle_v1 has been destroyed. + It is guaranteed there won't be any more events for this + zwlr_workspace_group_handle_v1. The zwlr_workspace_group_handle_v1 becomes + inert so any requests will be ignored except the destroy request. + + The compositor must remove all workspaces belonging to a workspace group + before removing the workspace group. + + + + + + Destroys the zwlr_workspace_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + + A zwlr_workspace_handle_v1 object represents a a workspace that handles a + group of surfaces. + + Each workspace has a name, conveyed to the client with the name event; a + list of states, conveyed to the client with the state event; and + optionally a set of coordinates, conveyed to the client with the + coordinates event. The client may request that the compositor activate or + deactivate the workspace. + + + + + This event is emitted immediately after the zwlr_workspace_handle_v1 is + created and whenever the name of the workspace changes. + + + + + + + This event is used to organize workspaces into an N-dimensional grid + within a workspace group, and if supported, is emitted immediately after + the zwlr_workspace_handle_v1 is created and whenever the coordinates of + the workspace change. Compositors may not send this event if they do not + conceptually arrange workspaces in this way. If compositors simply + number workspaces, without any geometric interpretation, they may send + 1D coordinates, which clients should not interpret as implying any + geometry. Sending an empty array means that the compositor no longer + orders the workspace geometrically. + + Coordinates have an arbitrary number of dimensions N with an uint32 + position along each dimension. By convention if N > 1, the first + dimension is X, the second Y, the third Z, and so on. The compositor may + chose to utilize these events for a more novel workspace layout + convention, however. No guarantee is made about the grid being filled or + bounded; there may be a workspace at coordinate 1 and another at + coordinate 1000 and none in between. Within a workspace group, however, + workspaces must have unique coordinates of equal dimensionality. + + + + + + + This event is emitted immediately after the zwlr_workspace_handle_v1 is + created and each time the workspace state changes, either because of a + compositor action or because of a request in this protocol. + + + + + + + The different states that a workspace can have. + + + + + + + + This event means the zwlr_workspace_handle_v1 has been destroyed. It is + guaranteed there won't be any more events for this + zwlr_workspace_handle_v1. The zwlr_workspace_handle_v1 becomes inert so + any requests will be ignored except the destroy request. + + + + + + Destroys the zwlr_workspace_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + Request that this workspace be activated. + + There is no guarantee the workspace will be actually activated, and + behaviour may be compositor-dependent. For example, activating a + workspace may or may not deactivate all other workspaces in the same + group. + + + + + + Request that this workspace be deactivated. + + There is no guarantee the workspace will be actually deactivated. + + + + diff --git a/types/meson.build b/types/meson.build index 47431429b..d1d832c58 100644 --- a/types/meson.build +++ b/types/meson.build @@ -61,6 +61,7 @@ wlr_files += files( 'wlr_viewporter.c', 'wlr_virtual_keyboard_v1.c', 'wlr_virtual_pointer_v1.c', + 'wlr_workspace_v1.c', 'wlr_xcursor_manager.c', 'wlr_xdg_decoration_v1.c', 'wlr_xdg_foreign_v1.c', diff --git a/types/wlr_workspace_v1.c b/types/wlr_workspace_v1.c new file mode 100644 index 000000000..240b40bf2 --- /dev/null +++ b/types/wlr_workspace_v1.c @@ -0,0 +1,544 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include "util/signal.h" + +#include "wlr-workspace-unstable-v1-protocol.h" + +#define WORKSPACE_V1_VERSION 1 + +static void workspace_manager_idle_send_done(void *data) { + struct wlr_workspace_manager_v1 *manager = data; + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &manager->resources) { + zwlr_workspace_manager_v1_send_done(resource); + } + + manager->idle_source = NULL; +} + +static void workspace_manager_update_idle_source( + struct wlr_workspace_manager_v1 *manager) { + if (manager->idle_source) { + return; + } + + manager->idle_source = wl_event_loop_add_idle(manager->event_loop, + workspace_manager_idle_send_done, manager); +} + +static const struct zwlr_workspace_handle_v1_interface workspace_handle_impl; +static struct wlr_workspace_handle_v1 *workspace_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_workspace_handle_v1_interface, + &workspace_handle_impl)); + return wl_resource_get_user_data(resource); +} + +static void workspace_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void workspace_handle_activate(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_workspace_handle_v1 *workspace = workspace_from_resource(resource); + if (!workspace) { + return; + } + + workspace->pending |= WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; +} + +static void workspace_handle_deactivate(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_workspace_handle_v1 *workspace = workspace_from_resource(resource); + if (!workspace) { + return; + } + + workspace->pending &= ~WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; +} + +static void workspace_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static bool fill_array_from_workspace_state(struct wl_array *array, + uint32_t state) { + if (state & WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { + uint32_t *index = wl_array_add(array, sizeof(uint32_t)); + if (index == NULL) { + return false; + } + *index = ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + } + + return true; +} + +static void workspace_handle_send_details_to_resource( + struct wlr_workspace_handle_v1 *workspace, struct wl_resource *resource) { + if (workspace->name) { + zwlr_workspace_handle_v1_send_name(resource, workspace->name); + } + + if (workspace->coordinates.size > 0) { + zwlr_workspace_handle_v1_send_coordinates(resource, + &workspace->coordinates); + } + + struct wl_array state; + wl_array_init(&state); + if (!fill_array_from_workspace_state(&state, workspace->server_state)) { + wl_resource_post_no_memory(resource); + wl_array_release(&state); + return; + } + + zwlr_workspace_handle_v1_send_state(resource, &state); +} + +static const struct zwlr_workspace_handle_v1_interface workspace_handle_impl = { + .destroy = workspace_handle_destroy, + .activate = workspace_handle_activate, + .deactivate = workspace_handle_deactivate, +}; + +void wlr_workspace_handle_v1_set_name(struct wlr_workspace_handle_v1 *workspace, + const char* name) { + free(workspace->name); + workspace->name = strdup(name); + + struct wl_resource *tmp, *resource; + wl_resource_for_each_safe(resource, tmp, &workspace->resources) { + zwlr_workspace_handle_v1_send_name(resource, name); + } + + workspace_manager_update_idle_source(workspace->group->manager); +} + +void wlr_workspace_handle_v1_set_coordinates( + struct wlr_workspace_handle_v1 *workspace, struct wl_array *coordinates) { + wl_array_copy(&workspace->coordinates, coordinates); + + struct wl_resource *tmp, *resource; + wl_resource_for_each_safe(resource, tmp, &workspace->resources) { + zwlr_workspace_handle_v1_send_coordinates(resource, coordinates); + } + + workspace_manager_update_idle_source(workspace->group->manager); +} + +void wlr_workspace_handle_v1_set_active( + struct wlr_workspace_handle_v1 *workspace, bool activate) { + if (activate) { + workspace->server_state |= WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + } else { + workspace->server_state &= ~WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + } + + struct wl_array state; + wl_array_init(&state); + + if (!fill_array_from_workspace_state(&state, workspace->server_state)) { + struct wl_resource *resource; + wl_resource_for_each(resource, &workspace->resources) { + wl_resource_post_no_memory(resource); + } + + wl_array_release(&state); + return; + } + + struct wl_resource *tmp, *resource; + wl_resource_for_each_safe(resource, tmp, &workspace->resources) { + zwlr_workspace_handle_v1_send_state(resource, &state); + } + + wl_array_release(&state); + workspace_manager_update_idle_source(workspace->group->manager); +} + +static struct wl_resource *create_workspace_resource_for_group_resource( + struct wlr_workspace_handle_v1 *workspace, + struct wl_resource *group_resource) { + + struct wl_client *client = wl_resource_get_client(group_resource); + struct wl_resource *resource = wl_resource_create(client, + &zwlr_workspace_handle_v1_interface, + wl_resource_get_version(group_resource), 0); + if (!resource) { + wl_client_post_no_memory(client); + return NULL; + } + + wl_resource_set_implementation(resource, &workspace_handle_impl, workspace, + workspace_handle_resource_destroy); + + wl_list_insert(&workspace->resources, wl_resource_get_link(resource)); + zwlr_workspace_group_handle_v1_send_workspace(group_resource, resource); + + return resource; +} + +struct wlr_workspace_handle_v1 *wlr_workspace_handle_v1_create( + struct wlr_workspace_group_handle_v1 *group) { + struct wlr_workspace_handle_v1 *workspace = calloc(1, + sizeof(struct wlr_workspace_handle_v1)); + if (!workspace) { + return NULL; + } + + workspace->group = group; + wl_list_insert(&group->workspaces, &workspace->link); + wl_array_init(&workspace->coordinates); + wl_list_init(&workspace->resources); + wl_signal_init(&workspace->events.destroy); + + struct wl_resource *tmp, *group_resource; + wl_resource_for_each_safe(group_resource, tmp, &group->resources) { + create_workspace_resource_for_group_resource(workspace, group_resource); + } + + return workspace; +} + +void wlr_workspace_handle_v1_destroy( + struct wlr_workspace_handle_v1 *workspace) { + if (!workspace) { + return; + } + + wlr_signal_emit_safe(&workspace->events.destroy, workspace); + + workspace_manager_update_idle_source(workspace->group->manager); + + struct wl_resource *tmp, *resource; + wl_resource_for_each_safe(resource, tmp, &workspace->resources) { + zwlr_workspace_handle_v1_send_remove(resource); + + wl_resource_set_user_data(resource, NULL); + wl_list_remove(&resource->link); + wl_list_init(&resource->link); + } + + wl_array_release(&workspace->coordinates); + wl_list_remove(&workspace->link); + free(workspace->name); +} + +static void workspace_group_handle_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +const struct zwlr_workspace_group_handle_v1_interface workspace_group_impl = { + .destroy = workspace_group_handle_handle_destroy, +}; + +static void workspace_group_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +/** + * Create the workspace group resource and child workspace resources as well. + */ +static struct wl_resource *create_workspace_group_resource_for_resource( + struct wlr_workspace_group_handle_v1 *group, + struct wl_resource *manager_resource) { + struct wl_client *client = wl_resource_get_client(manager_resource); + struct wl_resource *resource = wl_resource_create(client, + &zwlr_workspace_group_handle_v1_interface, + wl_resource_get_version(manager_resource), 0); + if (!resource) { + wl_client_post_no_memory(client); + return NULL; + } + + wl_resource_set_implementation(resource, &workspace_group_impl, group, + workspace_group_resource_destroy); + + wl_list_insert(&group->resources, wl_resource_get_link(resource)); + zwlr_workspace_manager_v1_send_workspace_group(manager_resource, resource); + + struct wlr_workspace_handle_v1 *tmp, *workspace; + wl_list_for_each_safe(workspace, tmp, &group->workspaces, link) { + struct wl_resource *workspace_resource = + create_workspace_resource_for_group_resource(workspace, resource); + workspace_handle_send_details_to_resource(workspace, workspace_resource); + } + + return resource; +} + +static void send_output_to_group_resource(struct wl_resource *group_resource, + struct wlr_output *output, bool enter) { + struct wl_client *client = wl_resource_get_client(group_resource); + struct wl_resource *output_resource, *tmp; + + wl_resource_for_each_safe(output_resource, tmp, &output->resources) { + if (wl_resource_get_client(output_resource) == client) { + if (enter) { + zwlr_workspace_group_handle_v1_send_output_enter(group_resource, + output_resource); + } else { + zwlr_workspace_group_handle_v1_send_output_leave(group_resource, + output_resource); + } + } + } +} + +static void group_send_output(struct wlr_workspace_group_handle_v1 *group, + struct wlr_output *output, bool enter) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &group->resources) { + send_output_to_group_resource(resource, output, enter); + } +} + +static void workspace_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_workspace_group_handle_v1_output *output = + wl_container_of(listener, output, output_destroy); + wlr_workspace_group_handle_v1_output_leave(output->group_handle, + output->output); +} + +void wlr_workspace_group_handle_v1_output_enter( + struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output) { + struct wlr_workspace_group_handle_v1_output *group_output; + wl_list_for_each(group_output, &group->outputs, link) { + if (group_output->output == output) { + return; // we have already sent output_enter event + } + } + + group_output = calloc(1, sizeof(struct wlr_workspace_group_handle_v1_output)); + if (!group_output) { + wlr_log(WLR_ERROR, "failed to allocate memory for workspace output"); + return; + } + + group_output->output = output; + group_output->group_handle = group; + wl_list_insert(&group->outputs, &group_output->link); + + group_output->output_destroy.notify = workspace_handle_output_destroy; + wl_signal_add(&output->events.destroy, &group_output->output_destroy); + + group_send_output(group, output, true); +} + +static void group_output_destroy( + struct wlr_workspace_group_handle_v1_output *output) { + wl_list_remove(&output->link); + wl_list_remove(&output->output_destroy.link); + free(output); +} + +void wlr_workspace_group_handle_v1_output_leave( + struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output) { + struct wlr_workspace_group_handle_v1_output *group_output_iterator; + struct wlr_workspace_group_handle_v1_output *group_output = NULL; + + wl_list_for_each(group_output_iterator, &group->outputs, link) { + if (group_output_iterator->output == output) { + group_output = group_output_iterator; + break; + } + } + + if (group_output) { + group_send_output(group, output, false); + group_output_destroy(group_output); + } else { + // XXX: log an error? crash? + } +} + +static void group_send_details_to_resource( + struct wlr_workspace_group_handle_v1 *group, + struct wl_resource *resource) { + struct wlr_workspace_group_handle_v1_output *output; + wl_list_for_each(output, &group->outputs, link) { + send_output_to_group_resource(resource, output->output, true); + } +} + +struct wlr_workspace_group_handle_v1 *wlr_workspace_group_handle_v1_create( + struct wlr_workspace_manager_v1 *manager) { + + struct wlr_workspace_group_handle_v1 *group = calloc(1, + sizeof(struct wlr_workspace_group_handle_v1)); + if (!group) { + return NULL; + } + + group->manager = manager; + wl_list_insert(&manager->groups, &group->link); + + wl_list_init(&group->outputs); + wl_list_init(&group->resources); + wl_list_init(&group->workspaces); + wl_signal_init(&group->events.destroy); + + struct wl_resource *tmp, *manager_resource; + wl_resource_for_each_safe(manager_resource, tmp, &manager->resources) { + create_workspace_group_resource_for_resource(group, manager_resource); + } + + return group; +} + +void wlr_workspace_group_handle_v1_destroy( + struct wlr_workspace_group_handle_v1 *group) { + if (!group) { + return; + } + + struct wlr_workspace_handle_v1 *workspace, *tmp; + wl_list_for_each_safe(workspace, tmp, &group->workspaces, link) { + wlr_workspace_handle_v1_destroy(workspace); + } + + wlr_signal_emit_safe(&group->events.destroy, group); + workspace_manager_update_idle_source(group->manager); + + struct wlr_workspace_group_handle_v1_output *output, *tmp2; + wl_list_for_each_safe(output, tmp2, &group->outputs, link) { + group_output_destroy(output); + } + + struct wl_resource *tmp3, *resource; + wl_resource_for_each_safe(resource, tmp3, &group->resources) { + zwlr_workspace_group_handle_v1_send_remove(resource); + + wl_resource_set_user_data(resource, NULL); + wl_list_remove(&resource->link); + wl_list_init(&resource->link); + } + + free(group); +} + +static const struct zwlr_workspace_manager_v1_interface workspace_manager_impl; + +static struct wlr_workspace_manager_v1 *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_workspace_manager_v1_interface, + &workspace_manager_impl)); + return wl_resource_get_user_data(resource); +} + +static void workspace_manager_commit(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_workspace_manager_v1 *manager = manager_from_resource(resource); + if (!manager) { + return; + } + + struct wlr_workspace_group_handle_v1 *group; + struct wlr_workspace_handle_v1 *workspace; + wl_list_for_each(group, &manager->groups, link) { + wl_list_for_each(workspace, &group->workspaces, link) { + workspace->current = workspace->pending; + } + } + + wlr_signal_emit_safe(&manager->events.commit, manager); +} + +static void workspace_manager_stop(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_workspace_manager_v1 *manager = manager_from_resource(resource); + if (!manager) { + return; + } + + zwlr_workspace_manager_v1_send_finished(resource); + wl_resource_destroy(resource); +} + +static const struct zwlr_workspace_manager_v1_interface + workspace_manager_impl = { + .commit = workspace_manager_commit, + .stop = workspace_manager_stop, +}; + +static void workspace_manager_resource_destroy( struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void workspace_manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_workspace_manager_v1 *manager = data; + struct wl_resource *resource = wl_resource_create(client, + &zwlr_workspace_manager_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &workspace_manager_impl, + manager, workspace_manager_resource_destroy); + + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); + + struct wlr_workspace_group_handle_v1 *group, *tmp; + wl_list_for_each_safe(group, tmp, &manager->groups, link) { + struct wl_resource *group_resource = + create_workspace_group_resource_for_resource(group, resource); + group_send_details_to_resource(group, group_resource); + } + + zwlr_workspace_manager_v1_send_done(resource); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_workspace_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + + wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_list_remove(&manager->display_destroy.link); + wl_global_destroy(manager->global); + + free(manager); +} + +struct wlr_workspace_manager_v1 *wlr_workspace_manager_v1_create( + struct wl_display *display) { + + struct wlr_workspace_manager_v1 *manager = calloc(1, + sizeof(struct wlr_workspace_manager_v1)); + if (!manager) { + return NULL; + } + + manager->event_loop = wl_display_get_event_loop(display); + manager->global = wl_global_create(display, + &zwlr_workspace_manager_v1_interface, + WORKSPACE_V1_VERSION, manager, + workspace_manager_bind); + if (!manager->global) { + free(manager); + return NULL; + } + + wl_signal_init(&manager->events.destroy); + wl_signal_init(&manager->events.commit); + wl_list_init(&manager->resources); + wl_list_init(&manager->groups); + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} From 284dc3d251a6fc6cf9b5f91a50e26a116d466a38 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 17 Feb 2021 07:54:06 +0100 Subject: [PATCH 2/6] take newest ext-workspace version --- ...e-v1.xml => ext-workspace-unstable-v1.xml} | 104 ++++++++++++------ protocol/meson.build | 2 +- 2 files changed, 71 insertions(+), 35 deletions(-) rename protocol/{wlr-workspace-unstable-v1.xml => ext-workspace-unstable-v1.xml} (73%) diff --git a/protocol/wlr-workspace-unstable-v1.xml b/protocol/ext-workspace-unstable-v1.xml similarity index 73% rename from protocol/wlr-workspace-unstable-v1.xml rename to protocol/ext-workspace-unstable-v1.xml index ae0e44dbb..24410b628 100644 --- a/protocol/wlr-workspace-unstable-v1.xml +++ b/protocol/ext-workspace-unstable-v1.xml @@ -1,5 +1,5 @@ - + Copyright © 2019 Christopher Billington Copyright © 2020 Ilia Bozhinov @@ -26,7 +26,7 @@ THIS SOFTWARE. - + Workspaces, also called virtual desktops, are groups of surfaces. A compositor with a concept of workspaces may only show some such groups of @@ -45,7 +45,7 @@ docks by providing them with a list of workspaces and their properties, and allowing them to activate and deactivate workspaces. - After a client binds the zwlr_workspace_manager_v1, each workspace will be + After a client binds the zext_workspace_manager_v1, each workspace will be sent via the workspace event. @@ -55,9 +55,9 @@ All initial details of the workspace group (workspaces, outputs) will be sent immediately after this event via the corresponding events in - zwlr_workspace_group_handle_v1. + zext_workspace_group_handle_v1. - + @@ -68,21 +68,21 @@ This allows changes to the workspace properties to be seen as atomic, even if they happen via multiple events, and even if they involve - multiple zwlr_workspace_handle_v1 objects, for example, deactivating one + multiple zext_workspace_handle_v1 objects, for example, deactivating one workspace and activating another. - This event is sent after all changes in all workspace groups have been - sent. + This event is sent after all changes in all workspace groups have been + sent. - This allows changes to one or more zwlr_workspace_group_handle_v1 + This allows changes to one or more zext_workspace_group_handle_v1 properties to be seen as atomic, even if they happen via multiple events. In particular, an output moving from one workspace group to another sends an output_enter event and an output_leave event to the two - zwlr_workspace_group_handle_v1 objects in question. The compositor sends + zext_workspace_group_handle_v1 objects in question. The compositor sends the done event only after updating the output information in both workspace groups. @@ -91,7 +91,7 @@ This event indicates that the compositor is done sending events to the - zwlr_workspace_manager_v1. The server will destroy the object + zext_workspace_manager_v1. The server will destroy the object immediately after sending this request, so it will become invalid and the client should free any resources associated with it. @@ -108,14 +108,19 @@ - + - A zwlr_workspace_group_handle_v1 object represents a a workspace group + A zext_workspace_group_handle_v1 object represents a a workspace group that is assigned a set of outputs and contains a number of workspaces. The set of outputs assigned to the workspace group is conveyed to the client via output_enter and output_leave events, and its workspaces are conveyed with workspace events. + + For example, a compositor which has a set of workspaces for each output may + advertise a workspace group (and its workspaces) per output, whereas a compositor + where a workspace spans all outputs may advertise a single workspace group for all + outputs. @@ -140,26 +145,36 @@ All initial details of the workspace (name, coordinates, state) will be sent immediately after this event via the corresponding events in - zwlr_workspace_handle_v1. + zext_workspace_handle_v1. - + - This event means the zwlr_workspace_group_handle_v1 has been destroyed. - It is guaranteed there won't be any more events for this - zwlr_workspace_group_handle_v1. The zwlr_workspace_group_handle_v1 becomes - inert so any requests will be ignored except the destroy request. + This event means the zext_workspace_group_handle_v1 has been destroyed. + It is guaranteed there won't be any more events for this + zext_workspace_group_handle_v1. The zext_workspace_group_handle_v1 becomes + inert so any requests will be ignored except the destroy request. - The compositor must remove all workspaces belonging to a workspace group - before removing the workspace group. + The compositor must remove all workspaces belonging to a workspace group + before removing the workspace group. + + + Request that the compositor create a new workspace with the given name. + + There is no guarantee that the compositor will create a new workspace, + or that the created workspace will have the provided name. + + + + - - Destroys the zwlr_workspace_handle_v1 object. + + Destroys the zext_workspace_handle_v1 object. This request should be called either when the client does not want to use the workspace object any more or after the remove event to finalize @@ -168,9 +183,9 @@ - + - A zwlr_workspace_handle_v1 object represents a a workspace that handles a + A zext_workspace_handle_v1 object represents a a workspace that handles a group of surfaces. Each workspace has a name, conveyed to the client with the name event; a @@ -178,11 +193,16 @@ optionally a set of coordinates, conveyed to the client with the coordinates event. The client may request that the compositor activate or deactivate the workspace. + + Each workspace can belong to only a single workspace group. + Depepending on the compositor policy, there might be workspaces with + the same name in different workspace groups, but these workspaces are still + separate (e.g. one of them might be active while the other is not). - This event is emitted immediately after the zwlr_workspace_handle_v1 is + This event is emitted immediately after the zext_workspace_handle_v1 is created and whenever the name of the workspace changes. @@ -192,13 +212,13 @@ This event is used to organize workspaces into an N-dimensional grid within a workspace group, and if supported, is emitted immediately after - the zwlr_workspace_handle_v1 is created and whenever the coordinates of + the zext_workspace_handle_v1 is created and whenever the coordinates of the workspace change. Compositors may not send this event if they do not conceptually arrange workspaces in this way. If compositors simply number workspaces, without any geometric interpretation, they may send 1D coordinates, which clients should not interpret as implying any - geometry. Sending an empty array means that the compositor no longer - orders the workspace geometrically. + geometry. Sending an empty array means that the compositor no longer + orders the workspace geometrically. Coordinates have an arbitrary number of dimensions N with an uint32 position along each dimension. By convention if N > 1, the first @@ -214,7 +234,7 @@ - This event is emitted immediately after the zwlr_workspace_handle_v1 is + This event is emitted immediately after the zext_workspace_handle_v1 is created and each time the workspace state changes, either because of a compositor action or because of a request in this protocol. @@ -227,20 +247,28 @@ + + + + The workspace is not visible in its workspace group, and clients + attempting to visualize the compositor workspace state should not + display such workspaces. + + - This event means the zwlr_workspace_handle_v1 has been destroyed. It is + This event means the zext_workspace_handle_v1 has been destroyed. It is guaranteed there won't be any more events for this - zwlr_workspace_handle_v1. The zwlr_workspace_handle_v1 becomes inert so + zext_workspace_handle_v1. The zext_workspace_handle_v1 becomes inert so any requests will be ignored except the destroy request. - - Destroys the zwlr_workspace_handle_v1 object. + + Destroys the zext_workspace_handle_v1 object. This request should be called either when the client does not want to use the workspace object any more or after the remove event to finalize @@ -266,5 +294,13 @@ There is no guarantee the workspace will be actually deactivated. + + + + Request that this workspace be removed. + + There is no guarantee the workspace will be actually removed. + + diff --git a/protocol/meson.build b/protocol/meson.build index fc05bc61a..b830286b2 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -43,7 +43,7 @@ protocols = { 'wlr-output-power-management-unstable-v1': 'wlr-output-power-management-unstable-v1.xml', 'wlr-screencopy-unstable-v1': 'wlr-screencopy-unstable-v1.xml', 'wlr-virtual-pointer-unstable-v1': 'wlr-virtual-pointer-unstable-v1.xml', - 'wlr-workspace-unstable-v1': 'wlr-workspace-unstable-v1.xml', + 'ext-workspace-unstable-v1': 'ext-workspace-unstable-v1.xml', } protocols_code = {} From be327234a84053b575e64aa53f23e6e9aa90cd86 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 17 Feb 2021 07:55:19 +0100 Subject: [PATCH 3/6] rename wlr_workspace -> wlr_ext_workspace --- .../wlr/types/{wlr_workspace_v1.h => wlr_ext_workspace_v1.h} | 0 types/meson.build | 2 +- types/{wlr_workspace_v1.c => wlr_ext_workspace_v1.c} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename include/wlr/types/{wlr_workspace_v1.h => wlr_ext_workspace_v1.h} (100%) rename types/{wlr_workspace_v1.c => wlr_ext_workspace_v1.c} (100%) diff --git a/include/wlr/types/wlr_workspace_v1.h b/include/wlr/types/wlr_ext_workspace_v1.h similarity index 100% rename from include/wlr/types/wlr_workspace_v1.h rename to include/wlr/types/wlr_ext_workspace_v1.h diff --git a/types/meson.build b/types/meson.build index d1d832c58..2090b7cd1 100644 --- a/types/meson.build +++ b/types/meson.build @@ -22,6 +22,7 @@ wlr_files += files( 'wlr_cursor.c', 'wlr_data_control_v1.c', 'wlr_export_dmabuf_v1.c', + 'wlr_ext_workspace_v1.c', 'wlr_foreign_toplevel_management_v1.c', 'wlr_fullscreen_shell_v1.c', 'wlr_gamma_control_v1.c', @@ -61,7 +62,6 @@ wlr_files += files( 'wlr_viewporter.c', 'wlr_virtual_keyboard_v1.c', 'wlr_virtual_pointer_v1.c', - 'wlr_workspace_v1.c', 'wlr_xcursor_manager.c', 'wlr_xdg_decoration_v1.c', 'wlr_xdg_foreign_v1.c', diff --git a/types/wlr_workspace_v1.c b/types/wlr_ext_workspace_v1.c similarity index 100% rename from types/wlr_workspace_v1.c rename to types/wlr_ext_workspace_v1.c From d711c3c440b2ad70eec894dddc554a40cbb51850 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 17 Feb 2021 08:07:07 +0100 Subject: [PATCH 4/6] rename sources to ext too --- examples/meson.build | 2 +- include/wlr/types/wlr_ext_workspace_v1.h | 72 +++++----- types/wlr_ext_workspace_v1.c | 176 +++++++++++------------ 3 files changed, 125 insertions(+), 125 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index e9d79a5a6..e3d113fda 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -188,7 +188,7 @@ clients = { 'wlr-workspace': { 'src': 'wlr-workspace.c', 'dep': [wlroots], - 'proto': ['wlr-workspace-unstable-v1'], + 'proto': ['ext-workspace-unstable-v1'], }, } diff --git a/include/wlr/types/wlr_ext_workspace_v1.h b/include/wlr/types/wlr_ext_workspace_v1.h index 0e6d6a0fb..8a01b7e91 100644 --- a/include/wlr/types/wlr_ext_workspace_v1.h +++ b/include/wlr/types/wlr_ext_workspace_v1.h @@ -12,32 +12,32 @@ #include #include -struct wlr_workspace_manager_v1 { +struct wlr_ext_workspace_manager_v1 { struct wl_event_loop *event_loop; struct wl_event_source *idle_source; struct wl_global *global; struct wl_list resources; // wl_resource_get_link - struct wl_list groups; // wlr_workspace_group_handle_v1::link + struct wl_list groups; // wlr_ext_workspace_group_handle_v1::link struct wl_listener display_destroy; struct { - struct wl_signal commit; // wlr_workspace_manager_v1 + struct wl_signal commit; // wlr_ext_workspace_manager_v1 struct wl_signal destroy; } events; void *data; }; -struct wlr_workspace_group_handle_v1 { - struct wl_list link; // wlr_workspace_manager_v1::groups - struct wl_list resources; // wl_resource_get_link +struct wlr_ext_workspace_group_handle_v1 { + struct wl_list link; // wlr_ext_workspace_manager_v1::groups + struct wl_list resources; // wl_ext_resource_get_link - struct wl_list workspaces; // wlr_workspace_handle_v1::link - struct wl_list outputs; // wlr_workspace_group_handle_v1_output::link + struct wl_list workspaces; // wlr_ext_workspace_handle_v1::link + struct wl_list outputs; // wlr_ext_workspace_group_handle_v1_output::link - struct wlr_workspace_manager_v1 *manager; + struct wlr_ext_workspace_manager_v1 *manager; struct { struct wl_signal destroy; @@ -46,24 +46,24 @@ struct wlr_workspace_group_handle_v1 { void *data; }; -struct wlr_workspace_group_handle_v1_output { - struct wl_list link; // wlr_workspace_group_handle_v1::outputs +struct wlr_ext_workspace_group_handle_v1_output { + struct wl_list link; // wlr_ext_workspace_group_handle_v1::outputs struct wl_listener output_destroy; struct wlr_output *output; - struct wlr_workspace_group_handle_v1 *group_handle; + struct wlr_ext_workspace_group_handle_v1 *group_handle; }; -enum wlr_workspace_handle_v1_state +enum wlr_ext_workspace_handle_v1_state { - WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE = 1 << 0, + WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE = 1 << 0, }; -struct wlr_workspace_handle_v1 { - struct wl_list link; // wlr_workspace_group_handle_v1::workspaces +struct wlr_ext_workspace_handle_v1 { + struct wl_list link; // wlr_ext_workspace_group_handle_v1::workspaces struct wl_list resources; - struct wlr_workspace_group_handle_v1 *group; + struct wlr_ext_workspace_group_handle_v1 *group; // request from the client uint32_t pending, current; @@ -81,42 +81,42 @@ struct wlr_workspace_handle_v1 { void *data; }; -struct wlr_workspace_manager_v1 *wlr_workspace_manager_v1_create( +struct wlr_ext_workspace_manager_v1 *wlr_ext_workspace_manager_v1_create( struct wl_display *display); -struct wlr_workspace_group_handle_v1 *wlr_workspace_group_handle_v1_create( - struct wlr_workspace_manager_v1 *manager); +struct wlr_ext_workspace_group_handle_v1 *wlr_ext_workspace_group_handle_v1_create( + struct wlr_ext_workspace_manager_v1 *manager); /** * Destroy the workspace group and all workspaces inside it. */ -void wlr_workspace_group_handle_v1_destroy( - struct wlr_workspace_group_handle_v1 *group); +void wlr_ext_workspace_group_handle_v1_destroy( + struct wlr_ext_workspace_group_handle_v1 *group); /** * Create a new workspace in the workspace group. * Note that the compositor must set the workspace name immediately after * creating it. */ -struct wlr_workspace_handle_v1 *wlr_workspace_handle_v1_create( - struct wlr_workspace_group_handle_v1 *group); +struct wlr_ext_workspace_handle_v1 *wlr_ext_workspace_handle_v1_create( + struct wlr_ext_workspace_group_handle_v1 *group); -void wlr_workspace_handle_v1_destroy( - struct wlr_workspace_handle_v1 *workspace); +void wlr_ext_workspace_handle_v1_destroy( + struct wlr_ext_workspace_handle_v1 *workspace); -void wlr_workspace_group_handle_v1_output_enter( - struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output); +void wlr_ext_workspace_group_handle_v1_output_enter( + struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); -void wlr_workspace_group_handle_v1_output_leave( - struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output); +void wlr_ext_workspace_group_handle_v1_output_leave( + struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); -void wlr_workspace_handle_v1_set_name(struct wlr_workspace_handle_v1 *workspace, - const char* name); +void wlr_ext_workspace_handle_v1_set_name( + struct wlr_ext_workspace_handle_v1 *workspace, const char* name); -void wlr_workspace_handle_v1_set_coordinates( - struct wlr_workspace_handle_v1 *workspace, struct wl_array *coordinates); +void wlr_ext_workspace_handle_v1_set_coordinates( + struct wlr_ext_workspace_handle_v1 *workspace, struct wl_array *coordinates); -void wlr_workspace_handle_v1_set_active( - struct wlr_workspace_handle_v1 *workspace, bool active); +void wlr_ext_workspace_handle_v1_set_active( + struct wlr_ext_workspace_handle_v1 *workspace, bool active); #endif diff --git a/types/wlr_ext_workspace_v1.c b/types/wlr_ext_workspace_v1.c index 240b40bf2..90ecbb34d 100644 --- a/types/wlr_ext_workspace_v1.c +++ b/types/wlr_ext_workspace_v1.c @@ -3,27 +3,27 @@ #include #include #include -#include +#include #include #include #include "util/signal.h" -#include "wlr-workspace-unstable-v1-protocol.h" +#include "ext-workspace-unstable-v1-protocol.h" #define WORKSPACE_V1_VERSION 1 static void workspace_manager_idle_send_done(void *data) { - struct wlr_workspace_manager_v1 *manager = data; + struct wlr_ext_workspace_manager_v1 *manager = data; struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &manager->resources) { - zwlr_workspace_manager_v1_send_done(resource); + zext_workspace_manager_v1_send_done(resource); } manager->idle_source = NULL; } static void workspace_manager_update_idle_source( - struct wlr_workspace_manager_v1 *manager) { + struct wlr_ext_workspace_manager_v1 *manager) { if (manager->idle_source) { return; } @@ -32,11 +32,11 @@ static void workspace_manager_update_idle_source( workspace_manager_idle_send_done, manager); } -static const struct zwlr_workspace_handle_v1_interface workspace_handle_impl; -static struct wlr_workspace_handle_v1 *workspace_from_resource( +static const struct zext_workspace_handle_v1_interface workspace_handle_impl; +static struct wlr_ext_workspace_handle_v1 *workspace_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, - &zwlr_workspace_handle_v1_interface, + &zext_workspace_handle_v1_interface, &workspace_handle_impl)); return wl_resource_get_user_data(resource); } @@ -48,22 +48,22 @@ static void workspace_handle_destroy(struct wl_client *client, static void workspace_handle_activate(struct wl_client *client, struct wl_resource *resource) { - struct wlr_workspace_handle_v1 *workspace = workspace_from_resource(resource); + struct wlr_ext_workspace_handle_v1 *workspace = workspace_from_resource(resource); if (!workspace) { return; } - workspace->pending |= WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + workspace->pending |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } static void workspace_handle_deactivate(struct wl_client *client, struct wl_resource *resource) { - struct wlr_workspace_handle_v1 *workspace = workspace_from_resource(resource); + struct wlr_ext_workspace_handle_v1 *workspace = workspace_from_resource(resource); if (!workspace) { return; } - workspace->pending &= ~WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + workspace->pending &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } static void workspace_handle_resource_destroy(struct wl_resource *resource) { @@ -72,25 +72,25 @@ static void workspace_handle_resource_destroy(struct wl_resource *resource) { static bool fill_array_from_workspace_state(struct wl_array *array, uint32_t state) { - if (state & WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { + if (state & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { uint32_t *index = wl_array_add(array, sizeof(uint32_t)); if (index == NULL) { return false; } - *index = ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + *index = ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } return true; } static void workspace_handle_send_details_to_resource( - struct wlr_workspace_handle_v1 *workspace, struct wl_resource *resource) { + struct wlr_ext_workspace_handle_v1 *workspace, struct wl_resource *resource) { if (workspace->name) { - zwlr_workspace_handle_v1_send_name(resource, workspace->name); + zext_workspace_handle_v1_send_name(resource, workspace->name); } if (workspace->coordinates.size > 0) { - zwlr_workspace_handle_v1_send_coordinates(resource, + zext_workspace_handle_v1_send_coordinates(resource, &workspace->coordinates); } @@ -102,46 +102,46 @@ static void workspace_handle_send_details_to_resource( return; } - zwlr_workspace_handle_v1_send_state(resource, &state); + zext_workspace_handle_v1_send_state(resource, &state); } -static const struct zwlr_workspace_handle_v1_interface workspace_handle_impl = { +static const struct zext_workspace_handle_v1_interface workspace_handle_impl = { .destroy = workspace_handle_destroy, .activate = workspace_handle_activate, .deactivate = workspace_handle_deactivate, }; -void wlr_workspace_handle_v1_set_name(struct wlr_workspace_handle_v1 *workspace, +void wlr_ext_workspace_handle_v1_set_name(struct wlr_ext_workspace_handle_v1 *workspace, const char* name) { free(workspace->name); workspace->name = strdup(name); struct wl_resource *tmp, *resource; wl_resource_for_each_safe(resource, tmp, &workspace->resources) { - zwlr_workspace_handle_v1_send_name(resource, name); + zext_workspace_handle_v1_send_name(resource, name); } workspace_manager_update_idle_source(workspace->group->manager); } -void wlr_workspace_handle_v1_set_coordinates( - struct wlr_workspace_handle_v1 *workspace, struct wl_array *coordinates) { +void wlr_ext_workspace_handle_v1_set_coordinates( + struct wlr_ext_workspace_handle_v1 *workspace, struct wl_array *coordinates) { wl_array_copy(&workspace->coordinates, coordinates); struct wl_resource *tmp, *resource; wl_resource_for_each_safe(resource, tmp, &workspace->resources) { - zwlr_workspace_handle_v1_send_coordinates(resource, coordinates); + zext_workspace_handle_v1_send_coordinates(resource, coordinates); } workspace_manager_update_idle_source(workspace->group->manager); } -void wlr_workspace_handle_v1_set_active( - struct wlr_workspace_handle_v1 *workspace, bool activate) { +void wlr_ext_workspace_handle_v1_set_active( + struct wlr_ext_workspace_handle_v1 *workspace, bool activate) { if (activate) { - workspace->server_state |= WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + workspace->server_state |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } else { - workspace->server_state &= ~WLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + workspace->server_state &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } struct wl_array state; @@ -159,7 +159,7 @@ void wlr_workspace_handle_v1_set_active( struct wl_resource *tmp, *resource; wl_resource_for_each_safe(resource, tmp, &workspace->resources) { - zwlr_workspace_handle_v1_send_state(resource, &state); + zext_workspace_handle_v1_send_state(resource, &state); } wl_array_release(&state); @@ -167,12 +167,12 @@ void wlr_workspace_handle_v1_set_active( } static struct wl_resource *create_workspace_resource_for_group_resource( - struct wlr_workspace_handle_v1 *workspace, + struct wlr_ext_workspace_handle_v1 *workspace, struct wl_resource *group_resource) { struct wl_client *client = wl_resource_get_client(group_resource); struct wl_resource *resource = wl_resource_create(client, - &zwlr_workspace_handle_v1_interface, + &zext_workspace_handle_v1_interface, wl_resource_get_version(group_resource), 0); if (!resource) { wl_client_post_no_memory(client); @@ -183,15 +183,15 @@ static struct wl_resource *create_workspace_resource_for_group_resource( workspace_handle_resource_destroy); wl_list_insert(&workspace->resources, wl_resource_get_link(resource)); - zwlr_workspace_group_handle_v1_send_workspace(group_resource, resource); + zext_workspace_group_handle_v1_send_workspace(group_resource, resource); return resource; } -struct wlr_workspace_handle_v1 *wlr_workspace_handle_v1_create( - struct wlr_workspace_group_handle_v1 *group) { - struct wlr_workspace_handle_v1 *workspace = calloc(1, - sizeof(struct wlr_workspace_handle_v1)); +struct wlr_ext_workspace_handle_v1 *wlr_ext_workspace_handle_v1_create( + struct wlr_ext_workspace_group_handle_v1 *group) { + struct wlr_ext_workspace_handle_v1 *workspace = calloc(1, + sizeof(struct wlr_ext_workspace_handle_v1)); if (!workspace) { return NULL; } @@ -210,8 +210,8 @@ struct wlr_workspace_handle_v1 *wlr_workspace_handle_v1_create( return workspace; } -void wlr_workspace_handle_v1_destroy( - struct wlr_workspace_handle_v1 *workspace) { +void wlr_ext_workspace_handle_v1_destroy( + struct wlr_ext_workspace_handle_v1 *workspace) { if (!workspace) { return; } @@ -222,7 +222,7 @@ void wlr_workspace_handle_v1_destroy( struct wl_resource *tmp, *resource; wl_resource_for_each_safe(resource, tmp, &workspace->resources) { - zwlr_workspace_handle_v1_send_remove(resource); + zext_workspace_handle_v1_send_remove(resource); wl_resource_set_user_data(resource, NULL); wl_list_remove(&resource->link); @@ -239,7 +239,7 @@ static void workspace_group_handle_handle_destroy(struct wl_client *client, wl_resource_destroy(resource); } -const struct zwlr_workspace_group_handle_v1_interface workspace_group_impl = { +const struct zext_workspace_group_handle_v1_interface workspace_group_impl = { .destroy = workspace_group_handle_handle_destroy, }; @@ -251,11 +251,11 @@ static void workspace_group_resource_destroy(struct wl_resource *resource) { * Create the workspace group resource and child workspace resources as well. */ static struct wl_resource *create_workspace_group_resource_for_resource( - struct wlr_workspace_group_handle_v1 *group, + struct wlr_ext_workspace_group_handle_v1 *group, struct wl_resource *manager_resource) { struct wl_client *client = wl_resource_get_client(manager_resource); struct wl_resource *resource = wl_resource_create(client, - &zwlr_workspace_group_handle_v1_interface, + &zext_workspace_group_handle_v1_interface, wl_resource_get_version(manager_resource), 0); if (!resource) { wl_client_post_no_memory(client); @@ -266,9 +266,9 @@ static struct wl_resource *create_workspace_group_resource_for_resource( workspace_group_resource_destroy); wl_list_insert(&group->resources, wl_resource_get_link(resource)); - zwlr_workspace_manager_v1_send_workspace_group(manager_resource, resource); + zext_workspace_manager_v1_send_workspace_group(manager_resource, resource); - struct wlr_workspace_handle_v1 *tmp, *workspace; + struct wlr_ext_workspace_handle_v1 *tmp, *workspace; wl_list_for_each_safe(workspace, tmp, &group->workspaces, link) { struct wl_resource *workspace_resource = create_workspace_resource_for_group_resource(workspace, resource); @@ -286,17 +286,17 @@ static void send_output_to_group_resource(struct wl_resource *group_resource, wl_resource_for_each_safe(output_resource, tmp, &output->resources) { if (wl_resource_get_client(output_resource) == client) { if (enter) { - zwlr_workspace_group_handle_v1_send_output_enter(group_resource, + zext_workspace_group_handle_v1_send_output_enter(group_resource, output_resource); } else { - zwlr_workspace_group_handle_v1_send_output_leave(group_resource, + zext_workspace_group_handle_v1_send_output_leave(group_resource, output_resource); } } } } -static void group_send_output(struct wlr_workspace_group_handle_v1 *group, +static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output, bool enter) { struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &group->resources) { @@ -306,22 +306,22 @@ static void group_send_output(struct wlr_workspace_group_handle_v1 *group, static void workspace_handle_output_destroy(struct wl_listener *listener, void *data) { - struct wlr_workspace_group_handle_v1_output *output = + struct wlr_ext_workspace_group_handle_v1_output *output = wl_container_of(listener, output, output_destroy); - wlr_workspace_group_handle_v1_output_leave(output->group_handle, + wlr_ext_workspace_group_handle_v1_output_leave(output->group_handle, output->output); } -void wlr_workspace_group_handle_v1_output_enter( - struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output) { - struct wlr_workspace_group_handle_v1_output *group_output; +void wlr_ext_workspace_group_handle_v1_output_enter( + struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output) { + struct wlr_ext_workspace_group_handle_v1_output *group_output; wl_list_for_each(group_output, &group->outputs, link) { if (group_output->output == output) { return; // we have already sent output_enter event } } - group_output = calloc(1, sizeof(struct wlr_workspace_group_handle_v1_output)); + group_output = calloc(1, sizeof(struct wlr_ext_workspace_group_handle_v1_output)); if (!group_output) { wlr_log(WLR_ERROR, "failed to allocate memory for workspace output"); return; @@ -338,16 +338,16 @@ void wlr_workspace_group_handle_v1_output_enter( } static void group_output_destroy( - struct wlr_workspace_group_handle_v1_output *output) { + struct wlr_ext_workspace_group_handle_v1_output *output) { wl_list_remove(&output->link); wl_list_remove(&output->output_destroy.link); free(output); } -void wlr_workspace_group_handle_v1_output_leave( - struct wlr_workspace_group_handle_v1 *group, struct wlr_output *output) { - struct wlr_workspace_group_handle_v1_output *group_output_iterator; - struct wlr_workspace_group_handle_v1_output *group_output = NULL; +void wlr_ext_workspace_group_handle_v1_output_leave( + struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output) { + struct wlr_ext_workspace_group_handle_v1_output *group_output_iterator; + struct wlr_ext_workspace_group_handle_v1_output *group_output = NULL; wl_list_for_each(group_output_iterator, &group->outputs, link) { if (group_output_iterator->output == output) { @@ -365,19 +365,19 @@ void wlr_workspace_group_handle_v1_output_leave( } static void group_send_details_to_resource( - struct wlr_workspace_group_handle_v1 *group, + struct wlr_ext_workspace_group_handle_v1 *group, struct wl_resource *resource) { - struct wlr_workspace_group_handle_v1_output *output; + struct wlr_ext_workspace_group_handle_v1_output *output; wl_list_for_each(output, &group->outputs, link) { send_output_to_group_resource(resource, output->output, true); } } -struct wlr_workspace_group_handle_v1 *wlr_workspace_group_handle_v1_create( - struct wlr_workspace_manager_v1 *manager) { +struct wlr_ext_workspace_group_handle_v1 *wlr_ext_workspace_group_handle_v1_create( + struct wlr_ext_workspace_manager_v1 *manager) { - struct wlr_workspace_group_handle_v1 *group = calloc(1, - sizeof(struct wlr_workspace_group_handle_v1)); + struct wlr_ext_workspace_group_handle_v1 *group = calloc(1, + sizeof(struct wlr_ext_workspace_group_handle_v1)); if (!group) { return NULL; } @@ -398,28 +398,28 @@ struct wlr_workspace_group_handle_v1 *wlr_workspace_group_handle_v1_create( return group; } -void wlr_workspace_group_handle_v1_destroy( - struct wlr_workspace_group_handle_v1 *group) { +void wlr_ext_workspace_group_handle_v1_destroy( + struct wlr_ext_workspace_group_handle_v1 *group) { if (!group) { return; } - struct wlr_workspace_handle_v1 *workspace, *tmp; + struct wlr_ext_workspace_handle_v1 *workspace, *tmp; wl_list_for_each_safe(workspace, tmp, &group->workspaces, link) { - wlr_workspace_handle_v1_destroy(workspace); + wlr_ext_workspace_handle_v1_destroy(workspace); } wlr_signal_emit_safe(&group->events.destroy, group); workspace_manager_update_idle_source(group->manager); - struct wlr_workspace_group_handle_v1_output *output, *tmp2; + struct wlr_ext_workspace_group_handle_v1_output *output, *tmp2; wl_list_for_each_safe(output, tmp2, &group->outputs, link) { group_output_destroy(output); } struct wl_resource *tmp3, *resource; wl_resource_for_each_safe(resource, tmp3, &group->resources) { - zwlr_workspace_group_handle_v1_send_remove(resource); + zext_workspace_group_handle_v1_send_remove(resource); wl_resource_set_user_data(resource, NULL); wl_list_remove(&resource->link); @@ -429,25 +429,25 @@ void wlr_workspace_group_handle_v1_destroy( free(group); } -static const struct zwlr_workspace_manager_v1_interface workspace_manager_impl; +static const struct zext_workspace_manager_v1_interface workspace_manager_impl; -static struct wlr_workspace_manager_v1 *manager_from_resource( +static struct wlr_ext_workspace_manager_v1 *manager_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, - &zwlr_workspace_manager_v1_interface, + &zext_workspace_manager_v1_interface, &workspace_manager_impl)); return wl_resource_get_user_data(resource); } static void workspace_manager_commit(struct wl_client *client, struct wl_resource *resource) { - struct wlr_workspace_manager_v1 *manager = manager_from_resource(resource); + struct wlr_ext_workspace_manager_v1 *manager = manager_from_resource(resource); if (!manager) { return; } - struct wlr_workspace_group_handle_v1 *group; - struct wlr_workspace_handle_v1 *workspace; + struct wlr_ext_workspace_group_handle_v1 *group; + struct wlr_ext_workspace_handle_v1 *workspace; wl_list_for_each(group, &manager->groups, link) { wl_list_for_each(workspace, &group->workspaces, link) { workspace->current = workspace->pending; @@ -459,16 +459,16 @@ static void workspace_manager_commit(struct wl_client *client, static void workspace_manager_stop(struct wl_client *client, struct wl_resource *resource) { - struct wlr_workspace_manager_v1 *manager = manager_from_resource(resource); + struct wlr_ext_workspace_manager_v1 *manager = manager_from_resource(resource); if (!manager) { return; } - zwlr_workspace_manager_v1_send_finished(resource); + zext_workspace_manager_v1_send_finished(resource); wl_resource_destroy(resource); } -static const struct zwlr_workspace_manager_v1_interface +static const struct zext_workspace_manager_v1_interface workspace_manager_impl = { .commit = workspace_manager_commit, .stop = workspace_manager_stop, @@ -480,9 +480,9 @@ static void workspace_manager_resource_destroy( struct wl_resource *resource) { static void workspace_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { - struct wlr_workspace_manager_v1 *manager = data; + struct wlr_ext_workspace_manager_v1 *manager = data; struct wl_resource *resource = wl_resource_create(client, - &zwlr_workspace_manager_v1_interface, version, id); + &zext_workspace_manager_v1_interface, version, id); if (!resource) { wl_client_post_no_memory(client); return; @@ -492,18 +492,18 @@ static void workspace_manager_bind(struct wl_client *client, void *data, wl_list_insert(&manager->resources, wl_resource_get_link(resource)); - struct wlr_workspace_group_handle_v1 *group, *tmp; + struct wlr_ext_workspace_group_handle_v1 *group, *tmp; wl_list_for_each_safe(group, tmp, &manager->groups, link) { struct wl_resource *group_resource = create_workspace_group_resource_for_resource(group, resource); group_send_details_to_resource(group, group_resource); } - zwlr_workspace_manager_v1_send_done(resource); + zext_workspace_manager_v1_send_done(resource); } static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_workspace_manager_v1 *manager = + struct wlr_ext_workspace_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); wlr_signal_emit_safe(&manager->events.destroy, manager); @@ -513,18 +513,18 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { free(manager); } -struct wlr_workspace_manager_v1 *wlr_workspace_manager_v1_create( +struct wlr_ext_workspace_manager_v1 *wlr_ext_workspace_manager_v1_create( struct wl_display *display) { - struct wlr_workspace_manager_v1 *manager = calloc(1, - sizeof(struct wlr_workspace_manager_v1)); + struct wlr_ext_workspace_manager_v1 *manager = calloc(1, + sizeof(struct wlr_ext_workspace_manager_v1)); if (!manager) { return NULL; } manager->event_loop = wl_display_get_event_loop(display); manager->global = wl_global_create(display, - &zwlr_workspace_manager_v1_interface, + &zext_workspace_manager_v1_interface, WORKSPACE_V1_VERSION, manager, workspace_manager_bind); if (!manager->global) { From ebcad3604c3c484fe0edaf8f671a3616de45e49c Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 17 Feb 2021 08:15:14 +0100 Subject: [PATCH 5/6] implement additional states in ext-workspace --- include/wlr/types/wlr_ext_workspace_v1.h | 8 +++ types/wlr_ext_workspace_v1.c | 68 +++++++++++++++++++----- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/include/wlr/types/wlr_ext_workspace_v1.h b/include/wlr/types/wlr_ext_workspace_v1.h index 8a01b7e91..b412cae6a 100644 --- a/include/wlr/types/wlr_ext_workspace_v1.h +++ b/include/wlr/types/wlr_ext_workspace_v1.h @@ -57,6 +57,8 @@ struct wlr_ext_workspace_group_handle_v1_output { enum wlr_ext_workspace_handle_v1_state { WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE = 1 << 0, + WLR_EXT_WORKSPACE_HANDLE_V1_STATE_URGENT = 1 << 1, + WLR_EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN = 1 << 2, }; struct wlr_ext_workspace_handle_v1 { @@ -119,4 +121,10 @@ void wlr_ext_workspace_handle_v1_set_coordinates( void wlr_ext_workspace_handle_v1_set_active( struct wlr_ext_workspace_handle_v1 *workspace, bool active); +void wlr_ext_workspace_handle_v1_set_urgent( + struct wlr_ext_workspace_handle_v1 *workspace, bool urgent); + +void wlr_ext_workspace_handle_v1_set_hidden( + struct wlr_ext_workspace_handle_v1 *workspace, bool hidden); + #endif diff --git a/types/wlr_ext_workspace_v1.c b/types/wlr_ext_workspace_v1.c index 90ecbb34d..a5febefec 100644 --- a/types/wlr_ext_workspace_v1.c +++ b/types/wlr_ext_workspace_v1.c @@ -70,14 +70,28 @@ static void workspace_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } +static bool push_entry_in_array(struct wl_array *array, uint32_t entry) { + uint32_t *index = wl_array_add(array, sizeof(uint32_t)); + if (index == NULL) { + return false; + } + *index = entry; + return true; +} + static bool fill_array_from_workspace_state(struct wl_array *array, uint32_t state) { - if (state & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { - uint32_t *index = wl_array_add(array, sizeof(uint32_t)); - if (index == NULL) { - return false; - } - *index = ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + if ((state & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) && + !push_entry_in_array(array, ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE)) { + return false; + } + if ((state & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_URGENT) && + !push_entry_in_array(array, ZEXT_WORKSPACE_HANDLE_V1_STATE_URGENT)) { + return false; + } + if ((state & WLR_EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN) && + !push_entry_in_array(array, ZEXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN)) { + return false; } return true; @@ -136,14 +150,7 @@ void wlr_ext_workspace_handle_v1_set_coordinates( workspace_manager_update_idle_source(workspace->group->manager); } -void wlr_ext_workspace_handle_v1_set_active( - struct wlr_ext_workspace_handle_v1 *workspace, bool activate) { - if (activate) { - workspace->server_state |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; - } else { - workspace->server_state &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; - } - +static void workspace_send_state(struct wlr_ext_workspace_handle_v1 *workspace) { struct wl_array state; wl_array_init(&state); @@ -166,6 +173,39 @@ void wlr_ext_workspace_handle_v1_set_active( workspace_manager_update_idle_source(workspace->group->manager); } +void wlr_ext_workspace_handle_v1_set_active( + struct wlr_ext_workspace_handle_v1 *workspace, bool activate) { + if (activate) { + workspace->server_state |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + } else { + workspace->server_state &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; + } + + workspace_send_state(workspace); +} + +void wlr_ext_workspace_handle_v1_set_urgent( + struct wlr_ext_workspace_handle_v1 *workspace, bool urgent) { + if (urgent) { + workspace->server_state |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_URGENT; + } else { + workspace->server_state &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_URGENT; + } + + workspace_send_state(workspace); +} + +void wlr_ext_workspace_handle_v1_set_hidden( + struct wlr_ext_workspace_handle_v1 *workspace, bool hidden) { + if (hidden) { + workspace->server_state |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN; + } else { + workspace->server_state &= ~WLR_EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN; + } + + workspace_send_state(workspace); +} + static struct wl_resource *create_workspace_resource_for_group_resource( struct wlr_ext_workspace_handle_v1 *workspace, struct wl_resource *group_resource) { From 4aab5f8bb0a24ef15d8cb0622405d417ca01fe01 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 23 Feb 2021 21:24:19 +0100 Subject: [PATCH 6/6] update to newest zext-workspace --- examples/{wlr-workspace.c => ext-workspace.c} | 120 +++++++++++------- examples/meson.build | 4 +- include/wlr/types/wlr_ext_workspace_v1.h | 8 ++ types/wlr_ext_workspace_v1.c | 39 +++++- 4 files changed, 120 insertions(+), 51 deletions(-) rename examples/{wlr-workspace.c => ext-workspace.c} (69%) diff --git a/examples/wlr-workspace.c b/examples/ext-workspace.c similarity index 69% rename from examples/wlr-workspace.c rename to examples/ext-workspace.c index eab65a28c..1e1544dd1 100644 --- a/examples/wlr-workspace.c +++ b/examples/ext-workspace.c @@ -5,18 +5,22 @@ #include #include #include -#include "wlr-workspace-unstable-v1-client-protocol.h" +#include "ext-workspace-unstable-v1-client-protocol.h" -#define WLR_WORKSPACE_VERSION 1 +#define WLR_EXT_WORKSPACE_VERSION 1 /** * Usage: - * 1. wlr-workspace + * 1. ext-workspace * List all workspace groups and their workspaces - * 2. wlr-workspace -w X + * 2. ext-workspace -w X * Focus workspace with name X - * 3. wlr-workspace -m + * 3. ext-workspace -m * Continuously monitor for changes and print new state. + * 4. ext-workspace -c X + * Create a new workspace with name hint X in some workspace group + * 5. ext-workspace -r X + * Request removal of workspace X */ enum workspace_state_field { @@ -44,7 +48,7 @@ static void copy_state(struct workspace_state *current, struct workspace_v1 { struct wl_list link; - struct zwlr_workspace_handle_v1 *handle; + struct zext_workspace_handle_v1 *handle; struct workspace_state current, pending; }; @@ -70,45 +74,44 @@ static uint32_t array_to_state(struct wl_array *array) { uint32_t state = 0; uint32_t *entry; wl_array_for_each(entry, array) { - if (*entry == ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) + if (*entry == ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) state |= WORKSPACE_FOCUSED; } return state; } - static void workspace_handle_name(void *data, - struct zwlr_workspace_handle_v1 *workspace_handle_v1, + struct zext_workspace_handle_v1 *workspace_handle_v1, const char *name) { struct workspace_v1 *workspace = (struct workspace_v1*) - zwlr_workspace_handle_v1_get_user_data(workspace_handle_v1); + zext_workspace_handle_v1_get_user_data(workspace_handle_v1); free(workspace->pending.name); workspace->pending.name = strdup(name); } static void workspace_handle_coordinates(void *data, - struct zwlr_workspace_handle_v1 *workspace_handle, + struct zext_workspace_handle_v1 *workspace_handle, struct wl_array *coordinates) { struct workspace_v1 *workspace = (struct workspace_v1*) - zwlr_workspace_handle_v1_get_user_data(workspace_handle); + zext_workspace_handle_v1_get_user_data(workspace_handle); wl_array_copy(&workspace->pending.coordinates, coordinates); } static void workspace_handle_state(void *data, - struct zwlr_workspace_handle_v1 *workspace_handle, + struct zext_workspace_handle_v1 *workspace_handle, struct wl_array *state) { struct workspace_v1 *workspace = (struct workspace_v1*) - zwlr_workspace_handle_v1_get_user_data(workspace_handle); + zext_workspace_handle_v1_get_user_data(workspace_handle); workspace->pending.state = array_to_state(state); } static void workspace_handle_remove(void *data, - struct zwlr_workspace_handle_v1 *workspace_handle) { + struct zext_workspace_handle_v1 *workspace_handle) { struct workspace_v1 *workspace = (struct workspace_v1*) - zwlr_workspace_handle_v1_get_user_data(workspace_handle); - zwlr_workspace_handle_v1_destroy(workspace_handle); + zext_workspace_handle_v1_get_user_data(workspace_handle); + zext_workspace_handle_v1_destroy(workspace_handle); wl_list_remove(&workspace->link); free(workspace->current.name); @@ -118,7 +121,7 @@ static void workspace_handle_remove(void *data, free(workspace); } -static const struct zwlr_workspace_handle_v1_listener workspace_listener = { +static const struct zext_workspace_handle_v1_listener workspace_listener = { .name = workspace_handle_name, .coordinates = workspace_handle_coordinates, .state = workspace_handle_state, @@ -128,33 +131,34 @@ static const struct zwlr_workspace_handle_v1_listener workspace_listener = { struct group_v1 { struct wl_list link; + struct zext_workspace_group_handle_v1 *handle; int32_t id; struct wl_list workspaces; }; static void group_handle_output_enter(void *data, - struct zwlr_workspace_group_handle_v1 *group_handle, + struct zext_workspace_group_handle_v1 *group_handle, struct wl_output *output) { struct group_v1 *group = (struct group_v1*) - zwlr_workspace_group_handle_v1_get_user_data(group_handle); + zext_workspace_group_handle_v1_get_user_data(group_handle); printf("Group %d output_enter %u\n", group->id, (uint32_t)(size_t)wl_output_get_user_data(output)); } static void group_handle_output_leave(void *data, - struct zwlr_workspace_group_handle_v1 *group_handle, + struct zext_workspace_group_handle_v1 *group_handle, struct wl_output *output) { struct group_v1 *group = (struct group_v1*) - zwlr_workspace_group_handle_v1_get_user_data(group_handle); + zext_workspace_group_handle_v1_get_user_data(group_handle); printf("Group %d output_leave %u\n", group->id, (uint32_t)(size_t)wl_output_get_user_data(output)); } static void group_handle_workspace(void *data, - struct zwlr_workspace_group_handle_v1 *group_handle, - struct zwlr_workspace_handle_v1 *workspace_handle) { + struct zext_workspace_group_handle_v1 *group_handle, + struct zext_workspace_handle_v1 *workspace_handle) { struct group_v1 *group = (struct group_v1*) - zwlr_workspace_group_handle_v1_get_user_data(group_handle); + zext_workspace_group_handle_v1_get_user_data(group_handle); struct workspace_v1 *workspace = (struct workspace_v1*) calloc(1, sizeof(struct workspace_v1)); @@ -163,15 +167,15 @@ static void group_handle_workspace(void *data, wl_array_init(&workspace->current.coordinates); workspace->handle = workspace_handle; - zwlr_workspace_handle_v1_add_listener(workspace_handle, + zext_workspace_handle_v1_add_listener(workspace_handle, &workspace_listener, NULL); - zwlr_workspace_handle_v1_set_user_data(workspace_handle, workspace); + zext_workspace_handle_v1_set_user_data(workspace_handle, workspace); } static void group_handle_remove(void *data, - struct zwlr_workspace_group_handle_v1 *group_handle) { + struct zext_workspace_group_handle_v1 *group_handle) { struct group_v1 *group = (struct group_v1*) - zwlr_workspace_group_handle_v1_get_user_data(group_handle); + zext_workspace_group_handle_v1_get_user_data(group_handle); wl_list_remove(&group->link); if (!wl_list_empty(&group->workspaces)) { printf("Compositor bug! Group destroyed before its workspaces.\n"); @@ -180,33 +184,34 @@ static void group_handle_remove(void *data, free(group); } -static const struct zwlr_workspace_group_handle_v1_listener group_listener = { +static const struct zext_workspace_group_handle_v1_listener group_listener = { .output_enter = group_handle_output_enter, .output_leave = group_handle_output_leave, .workspace = group_handle_workspace, .remove = group_handle_remove, }; -static struct zwlr_workspace_manager_v1 *workspace_manager = NULL; +static struct zext_workspace_manager_v1 *workspace_manager = NULL; static struct wl_list group_list; static int32_t last_group_id = 0; static void workspace_manager_handle_workspace_group(void *data, - struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1, - struct zwlr_workspace_group_handle_v1 *workspace_group) { + struct zext_workspace_manager_v1 *zext_workspace_manager_v1, + struct zext_workspace_group_handle_v1 *workspace_group) { struct group_v1 *group = (struct group_v1*) calloc(1, sizeof(struct group_v1)); group->id = last_group_id++; + group->handle = workspace_group; wl_list_init(&group->workspaces); wl_list_insert(&group_list, &group->link); - zwlr_workspace_group_handle_v1_add_listener(workspace_group, + zext_workspace_group_handle_v1_add_listener(workspace_group, &group_listener, NULL); - zwlr_workspace_group_handle_v1_set_user_data(workspace_group, group); + zext_workspace_group_handle_v1_set_user_data(workspace_group, group); } static void workspace_manager_handle_done(void *data, - struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1) { + struct zext_workspace_manager_v1 *zext_workspace_manager_v1) { printf("*** Workspace configuration ***\n"); struct group_v1 *group; @@ -221,11 +226,11 @@ static void workspace_manager_handle_done(void *data, } static void workspace_manager_handle_finished(void *data, - struct zwlr_workspace_manager_v1 *zwlr_workspace_manager_v1) { - zwlr_workspace_manager_v1_destroy(zwlr_workspace_manager_v1); + struct zext_workspace_manager_v1 *zext_workspace_manager_v1) { + zext_workspace_manager_v1_destroy(zext_workspace_manager_v1); } -static const struct zwlr_workspace_manager_v1_listener workspace_manager_impl = { +static const struct zext_workspace_manager_v1_listener workspace_manager_impl = { .workspace_group = workspace_manager_handle_workspace_group, .done = workspace_manager_handle_done, .finished = workspace_manager_handle_finished, @@ -239,12 +244,12 @@ static void handle_global(void *data, struct wl_registry *registry, &wl_output_interface, version); wl_output_set_user_data(output, (void*)(size_t)name); // assign some ID to the output } else if (strcmp(interface, - zwlr_workspace_manager_v1_interface.name) == 0) { + zext_workspace_manager_v1_interface.name) == 0) { workspace_manager = wl_registry_bind(registry, name, - &zwlr_workspace_manager_v1_interface, WLR_WORKSPACE_VERSION); + &zext_workspace_manager_v1_interface, WLR_EXT_WORKSPACE_VERSION); wl_list_init(&group_list); - zwlr_workspace_manager_v1_add_listener(workspace_manager, + zext_workspace_manager_v1_add_listener(workspace_manager, &workspace_manager_impl, NULL); } } @@ -278,11 +283,19 @@ static struct workspace_v1 *workspace_by_name_or_bail(const char *name) { int main(int argc, char **argv) { int c; - char *focus_name = NULL; + char *focus_name = NULL; + char *create_name = NULL; + char *remove_name = NULL; bool monitor = false; - while ((c = getopt(argc, argv, "w:m")) != -1) { + while ((c = getopt(argc, argv, "c:r:w:m")) != -1) { switch (c) { + case 'c': + create_name = strdup(optarg); + break; + case 'r': + remove_name = strdup(optarg); + break; case 'w': focus_name = strdup(optarg); break; @@ -319,11 +332,24 @@ int main(int argc, char **argv) { wl_list_for_each(group, &group_list, link) { wl_list_for_each(workspace, &group->workspaces, link) { - zwlr_workspace_handle_v1_deactivate(workspace->handle); + zext_workspace_handle_v1_deactivate(workspace->handle); } } - zwlr_workspace_handle_v1_activate(focus->handle); - zwlr_workspace_manager_v1_commit(workspace_manager); + zext_workspace_handle_v1_activate(focus->handle); + zext_workspace_manager_v1_commit(workspace_manager); + } + + if (create_name != NULL) { + struct group_v1 *group; + wl_list_for_each(group, &group_list, link) { + zext_workspace_group_handle_v1_create_workspace(group->handle, create_name); + break; + } + } + + if (remove_name != NULL) { + struct workspace_v1 *remove = workspace_by_name_or_bail(remove_name); + zext_workspace_handle_v1_remove(remove->handle); } wl_display_flush(display); diff --git a/examples/meson.build b/examples/meson.build index e3d113fda..07ce91f5c 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -185,8 +185,8 @@ clients = { 'input-method-unstable-v2', ], }, - 'wlr-workspace': { - 'src': 'wlr-workspace.c', + 'ext-workspace': { + 'src': 'ext-workspace.c', 'dep': [wlroots], 'proto': ['ext-workspace-unstable-v1'], }, diff --git a/include/wlr/types/wlr_ext_workspace_v1.h b/include/wlr/types/wlr_ext_workspace_v1.h index b412cae6a..2ce74810b 100644 --- a/include/wlr/types/wlr_ext_workspace_v1.h +++ b/include/wlr/types/wlr_ext_workspace_v1.h @@ -40,12 +40,19 @@ struct wlr_ext_workspace_group_handle_v1 { struct wlr_ext_workspace_manager_v1 *manager; struct { + // wlr_ext_workspace_group_handle_v1_create_workspace_event + struct wl_signal create_workspace_request; struct wl_signal destroy; } events; void *data; }; +struct wlr_ext_workspace_group_handle_v1_create_workspace_event { + struct wlr_ext_workspace_group_handle_v1 *workspace_group; + const char *name; +}; + struct wlr_ext_workspace_group_handle_v1_output { struct wl_list link; // wlr_ext_workspace_group_handle_v1::outputs struct wl_listener output_destroy; @@ -77,6 +84,7 @@ struct wlr_ext_workspace_handle_v1 { struct wl_array coordinates; struct { + struct wl_signal remove_request; struct wl_signal destroy; } events; diff --git a/types/wlr_ext_workspace_v1.c b/types/wlr_ext_workspace_v1.c index a5febefec..352e7d8b4 100644 --- a/types/wlr_ext_workspace_v1.c +++ b/types/wlr_ext_workspace_v1.c @@ -33,6 +33,8 @@ static void workspace_manager_update_idle_source( } static const struct zext_workspace_handle_v1_interface workspace_handle_impl; +static const struct zext_workspace_group_handle_v1_interface workspace_group_impl; + static struct wlr_ext_workspace_handle_v1 *workspace_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, @@ -41,6 +43,14 @@ static struct wlr_ext_workspace_handle_v1 *workspace_from_resource( return wl_resource_get_user_data(resource); } +static struct wlr_ext_workspace_group_handle_v1 *workspace_group_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zext_workspace_group_handle_v1_interface, + &workspace_group_impl)); + return wl_resource_get_user_data(resource); +} + static void workspace_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -56,6 +66,16 @@ static void workspace_handle_activate(struct wl_client *client, workspace->pending |= WLR_EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE; } +static void workspace_handle_remove(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_ext_workspace_handle_v1 *workspace = workspace_from_resource(resource); + if (!workspace) { + return; + } + + wlr_signal_emit_safe(&workspace->events.remove_request, NULL); +} + static void workspace_handle_deactivate(struct wl_client *client, struct wl_resource *resource) { struct wlr_ext_workspace_handle_v1 *workspace = workspace_from_resource(resource); @@ -123,6 +143,7 @@ static const struct zext_workspace_handle_v1_interface workspace_handle_impl = { .destroy = workspace_handle_destroy, .activate = workspace_handle_activate, .deactivate = workspace_handle_deactivate, + .remove = workspace_handle_remove, }; void wlr_ext_workspace_handle_v1_set_name(struct wlr_ext_workspace_handle_v1 *workspace, @@ -240,6 +261,7 @@ struct wlr_ext_workspace_handle_v1 *wlr_ext_workspace_handle_v1_create( wl_list_insert(&group->workspaces, &workspace->link); wl_array_init(&workspace->coordinates); wl_list_init(&workspace->resources); + wl_signal_init(&workspace->events.remove_request); wl_signal_init(&workspace->events.destroy); struct wl_resource *tmp, *group_resource; @@ -274,13 +296,25 @@ void wlr_ext_workspace_handle_v1_destroy( free(workspace->name); } +static void workspace_group_handle_handle_create_workspace(struct wl_client *client, + struct wl_resource *resource, const char *arg) { + struct wlr_ext_workspace_group_handle_v1 *group = + workspace_group_from_resource(resource); + + struct wlr_ext_workspace_group_handle_v1_create_workspace_event event; + event.workspace_group = group; + event.name = arg; + wlr_signal_emit_safe(&group->events.create_workspace_request, &event); +} + static void workspace_group_handle_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } -const struct zext_workspace_group_handle_v1_interface workspace_group_impl = { - .destroy = workspace_group_handle_handle_destroy, +static const struct zext_workspace_group_handle_v1_interface workspace_group_impl = { + .create_workspace = workspace_group_handle_handle_create_workspace, + .destroy = workspace_group_handle_handle_destroy, }; static void workspace_group_resource_destroy(struct wl_resource *resource) { @@ -428,6 +462,7 @@ struct wlr_ext_workspace_group_handle_v1 *wlr_ext_workspace_group_handle_v1_crea wl_list_init(&group->outputs); wl_list_init(&group->resources); wl_list_init(&group->workspaces); + wl_signal_init(&group->events.create_workspace_request); wl_signal_init(&group->events.destroy); struct wl_resource *tmp, *manager_resource;