vlc | branch: master | Rémi Denis-Courmont <[email protected]> | 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 *); + _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
