From bbde4bb1abfbed61c13d8ceb21de12e3cde7cd35 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 23 May 2024 16:00:10 +0100 Subject: [PATCH] api: introduce the concept of backend specific plugins Allow loaded plugins to hook into specific backends. Signed-off-by: Yuxuan Shui --- include/picom/api.h | 21 ++++++++++++++- src/api.c | 65 ++++++++++++++++++++++++++++++++++++++++++--- src/api_internal.h | 7 +++++ src/picom.c | 2 ++ 4 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/api_internal.h diff --git a/include/picom/api.h b/include/picom/api.h index 70e4a006..719fd09a 100644 --- a/include/picom/api.h +++ b/include/picom/api.h @@ -3,12 +3,31 @@ #pragma once +#include #include #define PICOM_API_MAJOR (0UL) #define PICOM_API_MINOR (1UL) -struct picom_api {}; +struct backend_base; + +/// The entry point of a backend plugin. Called after the backend is initialized. +typedef void (*picom_backend_plugin_entrypoint)(struct backend_base *backend, void *user_data); +struct picom_api { + /// Add a plugin for a specific backend. The plugin's entry point will be called + /// when the specified backend is initialized. + /// + /// @param backend_name The name of the backend to add the plugin to. + /// @param major The major version of the backend API interface this plugin + /// is compatible with. + /// @param minor The minor version of the backend API interface this plugin + /// is compatible with. + /// @param entrypoint The entry point of the plugin. + /// @param user_data The user data to pass to the plugin's entry point. + bool (*add_backend_plugin)(const char *backend_name, uint64_t major, uint64_t minor, + picom_backend_plugin_entrypoint entrypoint, + void *user_data); +}; const struct picom_api * picom_api_get_interfaces(uint64_t major, uint64_t minor, const char *context); diff --git a/src/api.c b/src/api.c index 7005efef..713fece8 100644 --- a/src/api.c +++ b/src/api.c @@ -6,10 +6,69 @@ #include #include -#include "compiler.h" -#include "log.h" +#include -static struct picom_api picom_api; +#include "compiler.h" +#include "list.h" +#include "log.h" +#include "utils.h" + +struct backend_plugins { + UT_hash_handle hh; + const char *backend_name; + struct list_node plugins; +} *backend_plugins; + +struct backend_plugin { + const char *backend_name; + picom_backend_plugin_entrypoint entrypoint; + void *user_data; + struct list_node siblings; +}; + +static bool add_backend_plugin(const char *backend_name, uint64_t major, uint64_t minor, + picom_backend_plugin_entrypoint entrypoint, void *user_data) { + if (major != PICOM_BACKEND_MAJOR || minor > PICOM_BACKEND_MINOR) { + log_error("Cannot add plugin for backend %s, because the requested " + "version %" PRIu64 ".%" PRIu64 " is incompatible with the our " + "%lu.%lu", + backend_name, major, minor, PICOM_BACKEND_MAJOR, + PICOM_BACKEND_MINOR); + return false; + } + + auto plugin = ccalloc(1, struct backend_plugin); + plugin->backend_name = backend_name; + plugin->entrypoint = entrypoint; + plugin->user_data = user_data; + + struct backend_plugins *plugins = NULL; + HASH_FIND_STR(backend_plugins, backend_name, plugins); + if (!plugins) { + plugins = ccalloc(1, struct backend_plugins); + plugins->backend_name = strdup(backend_name); + list_init_head(&plugins->plugins); + HASH_ADD_STR(backend_plugins, backend_name, plugins); + } + list_insert_after(&plugins->plugins, &plugin->siblings); + return true; +} + +void api_backend_plugins_invoke(const char *backend_name, struct backend_base *backend) { + struct backend_plugins *plugins = NULL; + HASH_FIND_STR(backend_plugins, backend_name, plugins); + if (!plugins) { + return; + } + + list_foreach(struct backend_plugin, plugin, &plugins->plugins, siblings) { + plugin->entrypoint(backend, plugin->user_data); + } +} + +static struct picom_api picom_api = { + .add_backend_plugin = add_backend_plugin, +}; PICOM_PUBLIC_API const struct picom_api * picom_api_get_interfaces(uint64_t major, uint64_t minor, const char *context) { diff --git a/src/api_internal.h b/src/api_internal.h new file mode 100644 index 00000000..de5fa777 --- /dev/null +++ b/src/api_internal.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) Yuxuan Shui + +struct backend_base; + +/// Invoke all backend plugins for the specified backend. +void api_backend_plugins_invoke(const char *backend_name, struct backend_base *backend); diff --git a/src/picom.c b/src/picom.c index 595ea3dd..10fda603 100644 --- a/src/picom.c +++ b/src/picom.c @@ -41,6 +41,7 @@ #include #include +#include "api_internal.h" #include "common.h" #include "compiler.h" #include "config.h" @@ -660,6 +661,7 @@ static bool initialize_backend(session_t *ps) { // Reinitialize win_data ps->backend_data = backend_init(ps->o.backend, ps, session_get_target_window(ps)); + api_backend_plugins_invoke(backend_name(ps->o.backend), ps->backend_data); if (!ps->backend_data) { log_fatal("Failed to initialize backend, aborting..."); quit(ps);