cosmic-workspaces: abstract transaction-addon

This allows to use it for a future ext-workspace implementation.
It is also more generalized so can be used for other protocol
implementation in the future in case the protocols require some
kind of transaction management.
This commit is contained in:
Consolatis 2024-11-18 18:38:42 +01:00 committed by Johan Malm
parent afe416f04e
commit 63dc609085
7 changed files with 258 additions and 176 deletions

View file

@ -8,6 +8,7 @@
#include "cosmic-workspace-unstable-v1-protocol.h"
#include "protocols/cosmic-workspaces.h"
#include "protocols/cosmic-workspaces-internal.h"
#include "protocols/transaction-addon.h"
/*
* .--------------------.
@ -49,6 +50,13 @@ enum workspace_state {
CW_WS_STATE_INVALID = 1 << 31,
};
struct ws_create_workspace_event {
char *name;
struct {
struct wl_listener transaction_op_destroy;
} on;
};
static void
add_caps(struct wl_array *caps_arr, uint32_t caps)
{
@ -79,37 +87,40 @@ workspace_handle_destroy(struct wl_client *client, struct wl_resource *resource)
static void
workspace_handle_activate(struct wl_client *client, struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
/* workspace was destroyed from the compositor side */
return;
}
struct lab_cosmic_workspace *workspace = addon->data;
transaction_add_workspace_ev(workspace, resource, CW_PENDING_WS_ACTIVATE);
lab_transaction_op_add(addon->ctx, CW_PENDING_WS_ACTIVATE,
workspace, /*data*/ NULL);
}
static void
workspace_handle_deactivate(struct wl_client *client, struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
/* Workspace was destroyed from the compositor side */
return;
}
struct lab_cosmic_workspace *workspace = addon->data;
transaction_add_workspace_ev(workspace, resource, CW_PENDING_WS_DEACTIVATE);
lab_transaction_op_add(addon->ctx, CW_PENDING_WS_DEACTIVATE,
workspace, /*data*/ NULL);
}
static void
workspace_handle_remove(struct wl_client *client, struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
/* workspace was destroyed from the compositor side */
return;
}
struct lab_cosmic_workspace *workspace = addon->data;
transaction_add_workspace_ev(workspace, resource, CW_PENDING_WS_REMOVE);
lab_transaction_op_add(addon->ctx, CW_PENDING_WS_REMOVE,
workspace, /*data*/ NULL);
}
static const struct zcosmic_workspace_handle_v1_interface workspace_impl = {
@ -122,9 +133,9 @@ static const struct zcosmic_workspace_handle_v1_interface workspace_impl = {
static void
workspace_instance_resource_destroy(struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (addon) {
resource_addon_destroy(addon);
lab_resource_addon_destroy(addon);
wl_resource_set_user_data(resource, NULL);
}
@ -133,7 +144,7 @@ workspace_instance_resource_destroy(struct wl_resource *resource)
static struct wl_resource *
workspace_resource_create(struct lab_cosmic_workspace *workspace,
struct wl_resource *group_resource, struct session_context *ctx)
struct wl_resource *group_resource, struct lab_transaction_session_context *ctx)
{
struct wl_client *client = wl_resource_get_client(group_resource);
struct wl_resource *resource = wl_resource_create(client,
@ -144,7 +155,7 @@ workspace_resource_create(struct lab_cosmic_workspace *workspace,
return NULL;
}
struct wl_resource_addon *addon = resource_addon_create(ctx);
struct lab_wl_resource_addon *addon = lab_resource_addon_create(ctx);
addon->data = workspace;
wl_resource_set_implementation(resource, &workspace_impl, addon,
@ -212,17 +223,35 @@ workspace_set_state(struct lab_cosmic_workspace *workspace,
}
/* Group */
static void
ws_create_workspace_handle_transaction_op_destroy(struct wl_listener *listener, void *data)
{
struct ws_create_workspace_event *ev =
wl_container_of(listener, ev, on.transaction_op_destroy);
wl_list_remove(&ev->on.transaction_op_destroy.link);
free(ev->name);
free(ev);
}
static void
group_handle_create_workspace(struct wl_client *client,
struct wl_resource *resource, const char *name)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
return;
}
struct lab_cosmic_workspace_group *group = addon->data;
transaction_add_workspace_group_ev(group, resource, CW_PENDING_WS_CREATE, name);
struct ws_create_workspace_event *ev = znew(*ev);
ev->name = xstrdup(name);
struct lab_transaction_op *transaction_op = lab_transaction_op_add(
addon->ctx, CW_PENDING_WS_CREATE, group, ev);
ev->on.transaction_op_destroy.notify =
ws_create_workspace_handle_transaction_op_destroy;
wl_signal_add(&transaction_op->events.destroy, &ev->on.transaction_op_destroy);
}
static void
@ -239,9 +268,9 @@ static const struct zcosmic_workspace_group_handle_v1_interface group_impl = {
static void
group_instance_resource_destroy(struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (addon) {
resource_addon_destroy(addon);
lab_resource_addon_destroy(addon);
wl_resource_set_user_data(resource, NULL);
}
wl_list_remove(wl_resource_get_link(resource));
@ -249,7 +278,7 @@ group_instance_resource_destroy(struct wl_resource *resource)
static struct wl_resource *
group_resource_create(struct lab_cosmic_workspace_group *group,
struct wl_resource *manager_resource, struct session_context *ctx)
struct wl_resource *manager_resource, struct lab_transaction_session_context *ctx)
{
struct wl_client *client = wl_resource_get_client(manager_resource);
struct wl_resource *resource = wl_resource_create(client,
@ -260,7 +289,7 @@ group_resource_create(struct lab_cosmic_workspace_group *group,
return NULL;
}
struct wl_resource_addon *addon = resource_addon_create(ctx);
struct lab_wl_resource_addon *addon = lab_resource_addon_create(ctx);
addon->data = group;
wl_resource_set_implementation(resource, &group_impl, addon,
@ -284,40 +313,38 @@ group_send_state(struct lab_cosmic_workspace_group *group, struct wl_resource *r
static void
manager_handle_commit(struct wl_client *client, struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
return;
}
struct transaction_group *trans_grp;
struct transaction_workspace *trans_ws;
struct transaction *trans, *trans_tmp;
wl_list_for_each_safe(trans, trans_tmp, &addon->ctx->transactions, link) {
switch (trans->change) {
struct lab_cosmic_workspace *workspace;
struct lab_cosmic_workspace_group *group;
struct lab_transaction_op *trans_op, *trans_op_tmp;
lab_transaction_for_each_safe(trans_op, trans_op_tmp, addon->ctx) {
switch (trans_op->change) {
case CW_PENDING_WS_CREATE:
trans_grp = wl_container_of(trans, trans_grp, base);
wl_signal_emit_mutable(
&trans_grp->group->events.create_workspace,
trans_grp->new_workspace_name);
free(trans_grp->new_workspace_name);
group = trans_op->src;
struct ws_create_workspace_event *ev = trans_op->data;
wl_signal_emit_mutable(&group->events.create_workspace, ev->name);
break;
case CW_PENDING_WS_ACTIVATE:
trans_ws = wl_container_of(trans, trans_ws, base);
wl_signal_emit_mutable(&trans_ws->workspace->events.activate, NULL);
workspace = trans_op->src;
wl_signal_emit_mutable(&workspace->events.activate, NULL);
break;
case CW_PENDING_WS_DEACTIVATE:
trans_ws = wl_container_of(trans, trans_ws, base);
wl_signal_emit_mutable(&trans_ws->workspace->events.deactivate, NULL);
workspace = trans_op->src;
wl_signal_emit_mutable(&workspace->events.deactivate, NULL);
break;
case CW_PENDING_WS_REMOVE:
trans_ws = wl_container_of(trans, trans_ws, base);
wl_signal_emit_mutable(&trans_ws->workspace->events.remove, NULL);
workspace = trans_op->src;
wl_signal_emit_mutable(&workspace->events.remove, NULL);
break;
default:
wlr_log(WLR_ERROR, "Invalid transaction state: %u", trans->change);
wlr_log(WLR_ERROR, "Invalid transaction state: %u", trans_op->change);
}
wl_list_remove(&trans->link);
free(trans);
lab_transaction_op_destroy(trans_op);
}
}
@ -336,9 +363,9 @@ static const struct zcosmic_workspace_manager_v1_interface manager_impl = {
static void
manager_instance_resource_destroy(struct wl_resource *resource)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (addon) {
resource_addon_destroy(addon);
lab_resource_addon_destroy(addon);
wl_resource_set_user_data(resource, NULL);
}
@ -358,7 +385,7 @@ manager_handle_bind(struct wl_client *client, void *data,
return;
}
struct wl_resource_addon *addon = resource_addon_create(/* session context*/ NULL);
struct lab_wl_resource_addon *addon = lab_resource_addon_create(/* session context*/ NULL);
addon->data = manager;
wl_resource_set_implementation(resource, &manager_impl,
@ -495,7 +522,7 @@ lab_cosmic_workspace_group_create(struct lab_cosmic_workspace_manager *manager)
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &manager->resources) {
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
assert(addon && addon->ctx);
struct wl_resource *group_resource =
group_resource_create(group, resource, addon->ctx);
@ -522,9 +549,9 @@ lab_cosmic_workspace_group_destroy(struct lab_cosmic_workspace_group *group)
struct wl_resource *resource, *res_tmp;
wl_resource_for_each_safe(resource, res_tmp, &group->resources) {
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (addon) {
resource_addon_destroy(addon);
lab_resource_addon_destroy(addon);
wl_resource_set_user_data(resource, NULL);
}
zcosmic_workspace_group_handle_v1_send_remove(resource);
@ -532,6 +559,20 @@ lab_cosmic_workspace_group_destroy(struct lab_cosmic_workspace_group *group)
wl_list_init(wl_resource_get_link(resource));
}
/* Cancel pending transaction operations involving this group */
struct lab_transaction_op *trans_op, *trans_op_tmp;
wl_resource_for_each(resource, &group->manager->resources) {
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
continue;
}
lab_transaction_for_each_safe(trans_op, trans_op_tmp, addon->ctx) {
if (trans_op->src == group) {
lab_transaction_op_destroy(trans_op);
}
}
}
wl_list_remove(&group->link);
wl_array_release(&group->capabilities);
free(group);
@ -569,7 +610,7 @@ lab_cosmic_workspace_create(struct lab_cosmic_workspace_group *group)
/* Notify clients */
struct wl_resource *group_resource;
wl_resource_for_each(group_resource, &group->resources) {
struct wl_resource_addon *addon = wl_resource_get_user_data(group_resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(group_resource);
assert(addon && addon->ctx);
struct wl_resource *workspace_resource =
workspace_resource_create(workspace, group_resource, addon->ctx);
@ -642,9 +683,9 @@ lab_cosmic_workspace_destroy(struct lab_cosmic_workspace *workspace)
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &workspace->resources) {
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (addon) {
resource_addon_destroy(addon);
lab_resource_addon_destroy(addon);
wl_resource_set_user_data(resource, NULL);
}
zcosmic_workspace_handle_v1_send_remove(resource);
@ -653,6 +694,20 @@ lab_cosmic_workspace_destroy(struct lab_cosmic_workspace *workspace)
}
manager_schedule_done_event(workspace->group->manager);
/* Cancel pending transaction operations involving this workspace */
struct lab_transaction_op *trans_op, *trans_op_tmp;
wl_resource_for_each(resource, &workspace->group->manager->resources) {
struct lab_wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
continue;
}
lab_transaction_for_each_safe(trans_op, trans_op_tmp, addon->ctx) {
if (trans_op->src == workspace) {
lab_transaction_op_destroy(trans_op);
}
}
}
wl_list_remove(&workspace->link);
wl_array_release(&workspace->coordinates);
wl_array_release(&workspace->capabilities);

View file

@ -1,5 +1,4 @@
labwc_sources += files(
'cosmic-workspaces.c',
'transactions.c',
'output.c',
)

View file

@ -1,93 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <assert.h>
#include <wayland-server-core.h>
#include <wlr/util/log.h>
#include "common/list.h"
#include "common/mem.h"
#include "protocols/cosmic-workspaces-internal.h"
static void
transactions_destroy(struct wl_list *list)
{
struct transaction_group *group;
struct transaction *trans, *trans_tmp;
wl_list_for_each_safe(trans, trans_tmp, list, link) {
if (trans->change == CW_PENDING_WS_CREATE) {
group = wl_container_of(trans, group, base);
free(group->new_workspace_name);
}
wl_list_remove(&trans->link);
free(trans);
}
}
void
resource_addon_destroy(struct wl_resource_addon *addon)
{
assert(addon);
assert(addon->ctx);
addon->ctx->ref_count--;
assert(addon->ctx->ref_count >= 0);
wlr_log(WLR_DEBUG, "New refcount for session %p: %d",
addon->ctx, addon->ctx->ref_count);
if (!addon->ctx->ref_count) {
wlr_log(WLR_DEBUG, "Destroying session context");
transactions_destroy(&addon->ctx->transactions);
free(addon->ctx);
}
free(addon);
}
struct wl_resource_addon *
resource_addon_create(struct session_context *ctx)
{
struct wl_resource_addon *addon = znew(*addon);
if (!ctx) {
ctx = znew(*ctx);
wl_list_init(&ctx->transactions);
}
addon->ctx = ctx;
addon->ctx->ref_count++;
return addon;
}
void
transaction_add_workspace_ev(struct lab_cosmic_workspace *ws,
struct wl_resource *resource, enum pending_change change)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
wlr_log(WLR_ERROR, "Failed to find manager addon for workspace transaction");
return;
}
assert(change != CW_PENDING_WS_CREATE);
struct transaction_workspace *trans_ws = znew(*trans_ws);
trans_ws->workspace = ws;
trans_ws->base.change = change;
wl_list_append(&addon->ctx->transactions, &trans_ws->base.link);
}
void
transaction_add_workspace_group_ev(struct lab_cosmic_workspace_group *group,
struct wl_resource *resource, enum pending_change change,
const char *new_workspace_name)
{
struct wl_resource_addon *addon = wl_resource_get_user_data(resource);
if (!addon) {
wlr_log(WLR_ERROR, "Failed to find manager addon for group transaction");
return;
}
assert(change == CW_PENDING_WS_CREATE);
struct transaction_group *trans_grp = znew(*trans_grp);
trans_grp->group = group;
trans_grp->base.change = change;
trans_grp->new_workspace_name = xstrdup(new_workspace_name);
wl_list_append(&addon->ctx->transactions, &trans_grp->base.link);
}

View file

@ -1 +1,5 @@
labwc_sources += files(
'transaction-addon.c',
)
subdir('cosmic_workspaces')

View file

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <assert.h>
#include <wayland-server-core.h>
#include "common/list.h"
#include "common/mem.h"
#include "protocols/transaction-addon.h"
void
lab_transaction_op_destroy(struct lab_transaction_op *trans_op)
{
wl_signal_emit_mutable(&trans_op->events.destroy, trans_op);
wl_list_remove(&trans_op->link);
free(trans_op);
}
static void
transaction_destroy(struct wl_list *list)
{
struct lab_transaction_op *trans_op, *trans_op_tmp;
wl_list_for_each_safe(trans_op, trans_op_tmp, list, link) {
lab_transaction_op_destroy(trans_op);
}
}
void
lab_resource_addon_destroy(struct lab_wl_resource_addon *addon)
{
assert(addon);
assert(addon->ctx);
addon->ctx->ref_count--;
assert(addon->ctx->ref_count >= 0);
if (!addon->ctx->ref_count) {
transaction_destroy(&addon->ctx->transaction_ops);
free(addon->ctx);
}
free(addon);
}
struct lab_wl_resource_addon *
lab_resource_addon_create(struct lab_transaction_session_context *ctx)
{
struct lab_wl_resource_addon *addon = znew(*addon);
if (!ctx) {
ctx = znew(*ctx);
wl_list_init(&ctx->transaction_ops);
}
addon->ctx = ctx;
addon->ctx->ref_count++;
return addon;
}
struct lab_transaction_op *
lab_transaction_op_add(struct lab_transaction_session_context *ctx,
uint32_t pending_change, void *src, void *data)
{
assert(ctx);
struct lab_transaction_op *trans_op = znew(*trans_op);
trans_op->change = pending_change;
trans_op->src = src;
trans_op->data = data;
wl_signal_init(&trans_op->events.destroy);
wl_list_append(&ctx->transaction_ops, &trans_op->link);
return trans_op;
}