summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/wayland/Registry.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/windowing/wayland/Registry.h')
-rw-r--r--xbmc/windowing/wayland/Registry.h162
1 files changed, 162 insertions, 0 deletions
diff --git a/xbmc/windowing/wayland/Registry.h b/xbmc/windowing/wayland/Registry.h
new file mode 100644
index 0000000..f440782
--- /dev/null
+++ b/xbmc/windowing/wayland/Registry.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "Connection.h"
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <utility>
+
+#include <wayland-client-protocol.hpp>
+
+namespace KODI
+{
+namespace WINDOWING
+{
+namespace WAYLAND
+{
+
+/**
+ * Handle Wayland globals
+ *
+ * Request singletons (bound once) with \ref RequestSingleton, non-singletons
+ * such as wl_output with \ref Request, then call \ref Bind once.
+ *
+ * Make sure to destroy all registries before destroying the \ref CConnection.
+ */
+class CRegistry
+{
+public:
+ explicit CRegistry(CConnection& connection);
+
+ /**
+ * Request a static singleton global to be bound to a proxy
+ *
+ * You should only use this if the singleton is announced at registry bind time
+ * (not dynamically) and you do not need to catch events that are sent immediately
+ * in response to the bind. Use \ref Request in that case, even if there is
+ * ever only one instance of the object at maximum.
+ *
+ * Cannot be called after \ref Bind has been called.
+ *
+ * \param target target of waylandpp proxy type
+ * \param minVersion minimum version to bind
+ * \param maxVersion maximum version to bind
+ * \param required whether to throw an exception when the bind cannot be satisfied
+ * by the compositor - exception is thrown in \ref Bind
+ */
+ template<typename T>
+ void RequestSingleton(T& target, std::uint32_t minVersion, std::uint32_t maxVersion, bool required = true)
+ {
+ RequestSingletonInternal(target, T::interface_name, minVersion, maxVersion, required);
+ }
+ using AddHandler = std::function<void(std::uint32_t /* name */, wayland::proxy_t&& /* object */)>;
+ using RemoveHandler = std::function<void(std::uint32_t) /* name */>;
+ /**
+ * Request a callback when a dynamic global appears or disappears
+ *
+ * The callbacks may be called from the thread that calls \ref Bind or the
+ * global Wayland message pump thread during \ref Bind (but never at the same
+ * time) and only from the global thread after \ref Bind returns.
+ *
+ * Events that occur immediately upon binding are only delivered reliably
+ * if \ref Bind is called from the Wayland message pump thread.
+ *
+ * Cannot be called after \ref Bind has been called.
+ *
+ * \param minVersion minimum version to bind
+ * \param maxVersion maximum version to bind
+ * \param addHandler function that is called when a global of the requested
+ * type is added
+ * \param removeHandler function that is called when a global of the requested
+ * type is removed
+ */
+ template<typename T>
+ void Request(std::uint32_t minVersion,
+ std::uint32_t maxVersion,
+ const AddHandler& addHandler,
+ const RemoveHandler& removeHandler)
+ {
+ RequestInternal([]{ return T(); }, T::interface_name, minVersion, maxVersion, addHandler, removeHandler);
+ }
+
+ /**
+ * Create a registry object at the compositor and do an roundtrip to bind
+ * objects
+ *
+ * This function blocks until the initial roundtrip is complete. All statically
+ * requested singletons that were available will be bound then.
+ *
+ * Neither statically nor dynamically requested proxies will be bound before this
+ * function is called.
+ *
+ * May throw std::runtime_error if a required global was not found.
+ *
+ * Can only be called once for the same \ref CRegistry object.
+ */
+ void Bind();
+ /**
+ * Unbind all singletons requested with \ref RequestSingleton
+ */
+ void UnbindSingletons();
+
+private:
+ CRegistry(CRegistry const& other) = delete;
+ CRegistry& operator=(CRegistry const& other) = delete;
+
+ void RequestSingletonInternal(wayland::proxy_t& target, std::string const& interfaceName, std::uint32_t minVersion, std::uint32_t maxVersion, bool required);
+ void RequestInternal(std::function<wayland::proxy_t()> constructor, std::string const& interfaceName, std::uint32_t minVersion, std::uint32_t maxVersion, AddHandler addHandler, RemoveHandler removeHandler);
+ void CheckRequired();
+
+ CConnection& m_connection;
+ wayland::registry_t m_registry;
+
+ struct SingletonBindInfo
+ {
+ wayland::proxy_t& target;
+ // Throw exception if trying to bind below this version and required
+ std::uint32_t minVersion;
+ // Limit bind version to the minimum of this and compositor version
+ std::uint32_t maxVersion;
+ bool required;
+ SingletonBindInfo(wayland::proxy_t& target, std::uint32_t minVersion, std::uint32_t maxVersion, bool required)
+ : target{target}, minVersion{minVersion}, maxVersion{maxVersion}, required{required}
+ {}
+ };
+ std::map<std::string, SingletonBindInfo> m_singletonBinds;
+
+ struct BindInfo
+ {
+ std::function<wayland::proxy_t()> constructor;
+ std::uint32_t minVersion;
+ std::uint32_t maxVersion;
+ AddHandler addHandler;
+ RemoveHandler removeHandler;
+ BindInfo(std::function<wayland::proxy_t()> constructor,
+ std::uint32_t minVersion,
+ std::uint32_t maxVersion,
+ AddHandler addHandler,
+ RemoveHandler removeHandler)
+ : constructor{std::move(constructor)},
+ minVersion{minVersion},
+ maxVersion{maxVersion},
+ addHandler{std::move(addHandler)},
+ removeHandler{std::move(removeHandler)}
+ {}
+ };
+ std::map<std::string, BindInfo> m_binds;
+
+ std::map<std::uint32_t, std::reference_wrapper<BindInfo>> m_boundNames;
+};
+
+}
+}
+}