[vlc-commits] Wayland: add common helpers for registry handling
Rémi Denis-Courmont
git at videolan.org
Sun Oct 27 19:23:54 CET 2019
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Oct 27 19:07:45 2019 +0200| [ff063b51543754e94f4e94bda26b165804a95971] | committer: Rémi Denis-Courmont
Wayland: add common helpers for registry handling
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ff063b51543754e94f4e94bda26b165804a95971
---
modules/video_output/wayland/registry.c | 282 ++++++++++++++++++++++++++++++++
modules/video_output/wayland/registry.h | 44 +++++
2 files changed, 326 insertions(+)
diff --git a/modules/video_output/wayland/registry.c b/modules/video_output/wayland/registry.c
new file mode 100644
index 0000000000..02be60d717
--- /dev/null
+++ b/modules/video_output/wayland/registry.c
@@ -0,0 +1,282 @@
+/**
+ * @file registry.c
+ * @brief Wayland client register common helpers for VLC media player
+ */
+/*****************************************************************************
+ * Copyright © 2019 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <wayland-client.h>
+#include <vlc_common.h>
+#include "registry.h"
+
+struct vlc_wl_interface;
+
+struct vlc_wl_global
+{
+ uint32_t name;
+ uint32_t version;
+ struct vlc_wl_interface *interface;
+ struct wl_list node;
+};
+
+struct vlc_wl_interface
+{
+ struct wl_list globals;
+ char interface[];
+};
+
+static struct vlc_wl_global *vlc_wl_global_add(struct vlc_wl_interface *vi,
+ uint32_t name, uint32_t version)
+{
+ struct vlc_wl_global *vg = malloc(sizeof (*vg));
+ if (likely(vg != NULL))
+ {
+ vg->name = name;
+ vg->version = version;
+ vg->interface = vi;
+ wl_list_insert(&vi->globals, &vg->node);
+ }
+ return vg;
+}
+
+static void vlc_wl_global_remove(struct vlc_wl_global *vg)
+{
+ wl_list_remove(&vg->node);
+ free(vg);
+}
+
+static struct vlc_wl_interface *vlc_wl_interface_create(const char *iface)
+{
+ const size_t len = strlen(iface) + 1;
+ struct vlc_wl_interface *vi = malloc(sizeof (*vi) + len);
+
+ if (likely(vi != NULL))
+ {
+ memcpy(vi->interface, iface, len);
+ wl_list_init(&vi->globals);
+ }
+ return vi;
+}
+
+static void vlc_wl_interface_destroy(struct vlc_wl_interface *vi)
+{
+ assert(wl_list_empty(&vi->globals));
+ free(vi);
+}
+
+struct vlc_wl_registry
+{
+ struct wl_registry *registry;
+ void *interfaces;
+ void *names;
+};
+
+static int vwimatch(const void *a, const void *b)
+{
+ const char *name = a;
+ const struct vlc_wl_interface *iface = b;
+
+ return strcmp(name, iface->interface);
+}
+
+static struct vlc_wl_interface *
+vlc_wl_interface_find(const struct vlc_wl_registry *vr, const char *interface)
+{
+ void **pvi = tfind(interface, &vr->interfaces, vwimatch);
+
+ return (pvi != NULL) ? *pvi : NULL;
+}
+
+static struct vlc_wl_global *
+vlc_wl_global_find(const struct vlc_wl_registry *vr, const char *interface)
+{
+ struct vlc_wl_interface *vi = vlc_wl_interface_find(vr, interface);
+
+ if (vi == NULL || wl_list_empty(&vi->globals))
+ return 0;
+
+ return container_of(vi->globals.next, struct vlc_wl_global, node);
+}
+
+uint_fast32_t vlc_wl_interface_get_version(struct vlc_wl_registry *vr,
+ const char *interface)
+{
+ const struct vlc_wl_global *vg = vlc_wl_global_find(vr, interface);
+
+ return (vg != NULL) ? vg->version : 0;
+}
+
+struct wl_proxy *vlc_wl_interface_bind(struct vlc_wl_registry *vr,
+ const char *interface,
+ const struct wl_interface *wi,
+ uint32_t *restrict version)
+{
+ const struct vlc_wl_global *vg = vlc_wl_global_find(vr, interface);
+
+ if (vg == NULL)
+ return 0;
+
+ uint32_t vers = (version != NULL) ? *version : 1;
+
+ if (vers > vg->version)
+ *version = vers = vg->version;
+
+ return wl_registry_bind(vr->registry, vg->name, wi, vers);
+}
+
+static int vwicmp(const void *a, const void *b)
+{
+ const struct vlc_wl_interface *ia = a;
+ const struct vlc_wl_interface *ib = b;
+
+ return strcmp(ia->interface, ib->interface);
+}
+
+static int vwncmp(const void *a, const void *b)
+{
+ const struct vlc_wl_global *ga = a;
+ const struct vlc_wl_global *gb = b;
+
+ return (ga->name < gb->name) ? -1 : (ga->name > gb->name);
+}
+
+static void registry_global_cb(void *data, struct wl_registry *registry,
+ uint32_t name, const char *iface, uint32_t vers)
+{
+ struct vlc_wl_registry *vr = data;
+ struct vlc_wl_interface *vi = vlc_wl_interface_create(iface);
+
+ void **pvi = tsearch(vi, &vr->interfaces, vwicmp);
+ if (unlikely(pvi == NULL))
+ {
+ vlc_wl_interface_destroy(vi);
+ return;
+ }
+
+ if (*pvi != vi)
+ {
+ vlc_wl_interface_destroy(vi);
+ vi = *pvi;
+ }
+
+ struct vlc_wl_global *vg = vlc_wl_global_add(vi, name, vers);
+ if (unlikely(vg == NULL))
+ return;
+
+ void **pvg = tsearch(vg, &vr->names, vwncmp);
+ if (unlikely(pvg == NULL) /* OOM */
+ || unlikely(*pvg != vg) /* display server bug */)
+ vlc_wl_global_remove(vg);
+
+ (void) registry;
+}
+
+static void registry_global_remove_cb(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ struct vlc_wl_registry *vr = data;
+ struct vlc_wl_global key = { .name = name };
+ void **pvg = tfind(&key, &vr->names, vwncmp);
+
+ if (likely(pvg != NULL))
+ {
+ struct vlc_wl_global *vg = *pvg;
+
+ tdelete(vg, &vr->names, vwncmp);
+ vlc_wl_global_remove(vg);
+ }
+
+ (void) registry;
+}
+
+static const struct wl_registry_listener registry_cbs =
+{
+ registry_global_cb,
+ registry_global_remove_cb,
+};
+
+struct vlc_wl_registry *vlc_wl_registry_get(struct wl_display *display,
+ struct wl_event_queue *queue)
+{
+ struct vlc_wl_registry *vr = malloc(sizeof (*vr));
+ if (unlikely(vr == NULL))
+ return NULL;
+
+ vr->registry = wl_display_get_registry(display);
+ if (unlikely(vr->registry == NULL))
+ {
+ free(vr);
+ return NULL;
+ }
+
+ vr->interfaces = NULL;
+ vr->names = NULL;
+
+ /* FIXME: setting queue is not thread safe */
+ wl_proxy_set_queue((struct wl_proxy *)vr->registry, queue);
+ wl_registry_add_listener(vr->registry, ®istry_cbs, vr);
+
+ /* complete registry enumeration */
+ if (wl_display_roundtrip_queue(display, queue) < 0)
+ {
+ vlc_wl_registry_destroy(vr);
+ vr = NULL;
+ }
+
+ return vr;
+}
+
+static void name_destroy(void *d)
+{
+ vlc_wl_global_remove(d);
+}
+
+static void interface_destroy(void *d)
+{
+ vlc_wl_interface_destroy(d);
+}
+
+void vlc_wl_registry_destroy(struct vlc_wl_registry *vr)
+{
+ wl_registry_destroy(vr->registry);
+ tdestroy(vr->names, name_destroy);
+ tdestroy(vr->interfaces, interface_destroy);
+ free(vr);
+}
+
+struct wl_compositor *vlc_wl_compositor_get(struct vlc_wl_registry *vr)
+{
+ return (struct wl_compositor *)vlc_wl_interface_bind(vr, "wl_compositor",
+ &wl_compositor_interface, NULL);
+}
+
+struct wl_shm *vlc_wl_shm_get(struct vlc_wl_registry *vr)
+{
+ return (struct wl_shm *)vlc_wl_interface_bind(vr, "wl_shm",
+ &wl_shm_interface, NULL);
+}
diff --git a/modules/video_output/wayland/registry.h b/modules/video_output/wayland/registry.h
new file mode 100644
index 0000000000..26a1f4b424
--- /dev/null
+++ b/modules/video_output/wayland/registry.h
@@ -0,0 +1,44 @@
+/**
+ * @file registry.h
+ * @brief Wayland client register common helpers for VLC media player
+ */
+/*****************************************************************************
+ * Copyright © 2019 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <stdint.h>
+
+struct wl_display;
+struct wl_event_queue;
+struct wl_interface;
+struct wl_shm;
+struct vlc_wl_registry;
+
+struct vlc_wl_registry *vlc_wl_registry_get(struct wl_display *display,
+ struct wl_event_queue *queue);
+void vlc_wl_registry_destroy(struct vlc_wl_registry *vr);
+
+uint_fast32_t vlc_wl_interface_get_version(struct vlc_wl_registry *,
+ const char *interface);
+struct wl_proxy *vlc_wl_interface_bind(struct vlc_wl_registry *,
+ const char *interface,
+ const struct wl_interface *,
+ uint32_t *version);
+
+struct wl_compositor *vlc_wl_compositor_get(struct vlc_wl_registry *);
+struct wl_shm *vlc_wl_shm_get(struct vlc_wl_registry *);
+
More information about the vlc-commits
mailing list