From 207847e8cff100856da62ca873f70574bb6266fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 10 Jun 2022 17:23:08 +0200 Subject: [PATCH] wayland: Add transaction skeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: * Use single hash table with struct which will contain all kinds of state handled by a transaction. v3: * Add meta_wayland_transaction_destroy. v4 (Georges Basile Stavracas Neto) * Fix struct _MetaWaylandTransaction(Entry) formatting. * Explicitly test against NULL. * Use gpointer insteadof void * for meta_wayland_transaction_entry_destroy. v5: (Robert Mader) * Use for loop in is_ancestor. * Include meta-wayland-transaction.h first in meta-wayland-transaction.c. v6: * Use g_autofree & g_clear_object. v7: (Jonas Ã…dahl) * Rename meta_wayland_transaction_entry_destroy to meta_wayland_transaction_entry_free. * Drop g_autofree use from meta_wayland_transaction_entry_free again. * Make meta_wayland_transaction_entry_free take a MetaWaylandTransactionEntry pointer. * Rename meta_wayland_transaction_destroy to meta_wayland_transaction_free. Part-of: --- src/meson.build | 2 + src/wayland/meta-wayland-surface.c | 2 +- src/wayland/meta-wayland-surface.h | 3 + src/wayland/meta-wayland-transaction.c | 186 +++++++++++++++++++++++++ src/wayland/meta-wayland-transaction.h | 35 +++++ src/wayland/meta-wayland-types.h | 2 + 6 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/wayland/meta-wayland-transaction.c create mode 100644 src/wayland/meta-wayland-transaction.h diff --git a/src/meson.build b/src/meson.build index 063c06b02..faacb3159 100644 --- a/src/meson.build +++ b/src/meson.build @@ -657,6 +657,8 @@ if have_wayland 'wayland/meta-wayland-text-input.h', 'wayland/meta-wayland-touch.c', 'wayland/meta-wayland-touch.h', + 'wayland/meta-wayland-transaction.c', + 'wayland/meta-wayland-transaction.h', 'wayland/meta-wayland-types.h', 'wayland/meta-wayland-versions.h', 'wayland/meta-wayland-viewporter.c', diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 3696a2786..adc8ba836 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -713,7 +713,7 @@ meta_wayland_surface_discard_presentation_feedback (MetaWaylandSurface *surface) } } -static void +void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, MetaWaylandSurfaceState *state) { diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 34d771324..e0f7544c5 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -263,6 +263,9 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit struct wl_resource *compositor_resource, guint32 id); +void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state); + MetaWaylandSurfaceState * meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface); diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c new file mode 100644 index 000000000..37af40fa9 --- /dev/null +++ b/src/wayland/meta-wayland-transaction.c @@ -0,0 +1,186 @@ +/* + * Wayland Transaction Support + * + * Copyright (C) 2021 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "wayland/meta-wayland-transaction.h" + +#include "wayland/meta-wayland-subsurface.h" + +struct _MetaWaylandTransaction +{ + GHashTable *entries; +}; + +typedef struct _MetaWaylandTransactionEntry +{ + MetaWaylandSurfaceState *state; +} MetaWaylandTransactionEntry; + +static MetaWaylandTransactionEntry * +meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + return g_hash_table_lookup (transaction->entries, surface); +} + +static void +meta_wayland_transaction_sync_child_states (MetaWaylandSurface *surface) +{ + MetaWaylandSurface *subsurface_surface; + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + { + MetaWaylandSubsurface *subsurface; + MetaWaylandActorSurface *actor_surface; + + subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role); + actor_surface = META_WAYLAND_ACTOR_SURFACE (subsurface); + meta_wayland_actor_surface_sync_actor_state (actor_surface); + } +} + +static gboolean +is_ancestor (MetaWaylandSurface *candidate, + MetaWaylandSurface *reference) +{ + MetaWaylandSurface *ancestor; + + for (ancestor = reference->sub.parent; ancestor; ancestor = ancestor->sub.parent) + { + if (ancestor == candidate) + return TRUE; + } + + return FALSE; +} + +static int +meta_wayland_transaction_compare (const void *key1, + const void *key2) +{ + MetaWaylandSurface *surface1 = *(MetaWaylandSurface **) key1; + MetaWaylandSurface *surface2 = *(MetaWaylandSurface **) key2; + + /* Order of siblings doesn't matter */ + if (surface1->sub.parent == surface2->sub.parent) + return 0; + + /* Ancestor surfaces come before descendant surfaces */ + if (is_ancestor (surface1, surface2)) + return 1; + + if (is_ancestor (surface2, surface1)) + return -1; + + /* + * Order unrelated surfaces by their toplevel surface pointer values, to + * prevent unrelated surfaces from getting mixed between siblings + */ + return (meta_wayland_surface_get_toplevel (surface1) < + meta_wayland_surface_get_toplevel (surface2)) ? -1 : 1; +} + +void +meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) +{ + g_autofree MetaWaylandSurface **surfaces = NULL; + unsigned int num_surfaces; + int i; + + surfaces = (MetaWaylandSurface **) + g_hash_table_get_keys_as_array (transaction->entries, &num_surfaces); + + /* Sort surfaces from ancestors to descendants */ + qsort (surfaces, num_surfaces, sizeof (MetaWaylandSurface *), + meta_wayland_transaction_compare); + + /* Apply states from ancestors to descendants */ + for (i = 0; i < num_surfaces; i++) + { + MetaWaylandSurface *surface = surfaces[i]; + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_get_entry (transaction, surface); + meta_wayland_surface_apply_state (surface, entry->state); + } + + /* Synchronize child states from descendants to ancestors */ + for (i = num_surfaces - 1; i >= 0; i--) + meta_wayland_transaction_sync_child_states (surfaces[i]); + + meta_wayland_transaction_free (transaction); +} + +static MetaWaylandTransactionEntry * +meta_wayland_transaction_ensure_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_get_entry (transaction, surface); + if (entry) + return entry; + + entry = g_new0 (MetaWaylandTransactionEntry, 1); + g_hash_table_insert (transaction->entries, surface, entry); + + return entry; +} + +void +meta_wayland_transaction_add_state (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state) +{ + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + g_assert (!entry->state); + entry->state = state; +} + +static void +meta_wayland_transaction_entry_free (MetaWaylandTransactionEntry *entry) +{ + g_clear_object (&entry->state); + g_free (entry); +} + +MetaWaylandTransaction * +meta_wayland_transaction_new (void) +{ + MetaWaylandTransaction *transaction; + + transaction = g_new0 (MetaWaylandTransaction, 1); + + transaction->entries = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) meta_wayland_transaction_entry_free); + + return transaction; +} + +void +meta_wayland_transaction_free (MetaWaylandTransaction *transaction) +{ + g_hash_table_destroy (transaction->entries); + g_free (transaction); +} diff --git a/src/wayland/meta-wayland-transaction.h b/src/wayland/meta-wayland-transaction.h new file mode 100644 index 000000000..62c0f388d --- /dev/null +++ b/src/wayland/meta-wayland-transaction.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_TRANSACTION_H +#define META_WAYLAND_TRANSACTION_H + +#include "wayland/meta-wayland-types.h" + +void meta_wayland_transaction_commit (MetaWaylandTransaction *transaction); + +void meta_wayland_transaction_add_state (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state); + +MetaWaylandTransaction *meta_wayland_transaction_new (void); + +void meta_wayland_transaction_free (MetaWaylandTransaction *transaction); + +#endif diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h index 2df2b5e2f..c4db05b61 100644 --- a/src/wayland/meta-wayland-types.h +++ b/src/wayland/meta-wayland-types.h @@ -54,6 +54,8 @@ typedef struct _MetaWaylandRegion MetaWaylandRegion; typedef struct _MetaWaylandSurface MetaWaylandSurface; typedef struct _MetaWaylandSurfaceState MetaWaylandSurfaceState; +typedef struct _MetaWaylandTransaction MetaWaylandTransaction; + typedef struct _MetaWaylandOutput MetaWaylandOutput; typedef struct _MetaWaylandWindowConfiguration MetaWaylandWindowConfiguration;