--- /dev/null
+#include <wayland-server.h>
+#include <linux-explicit-synchronization-unstable-v1-server-protocol.h>
+
+#include "libds/types/ds_surface.h"
+#include "libds/log.h"
+#include "libds/util/defs.h"
+#include "libds/util/addon.h"
+#include "util.h"
+
+#define ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_VERSION 2
+
+struct ds_linux_explicit_sync_v1 {
+ struct wl_global *global;
+
+ struct wl_listener display_destroy;
+};
+
+struct ds_linux_explicit_sync_v1_state {
+ int acquire_fence_fd;
+};
+
+struct ds_linux_explicit_sync_v1_surface {
+ struct wl_resource *resource;
+ struct ds_linux_explicit_sync_v1 *explicit_sync;
+ struct ds_surface *surface;
+
+ struct ds_linux_explicit_sync_v1_state pending, cache, current;
+ struct ds_addon addon;
+
+ struct wl_listener surface_destroy;
+};
+
+static void linux_explicit_sync_v1_handle_display_destroy(struct wl_listener *listener, void *data);
+static void linux_explicit_sync_v1_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
+
+WL_EXPORT struct ds_linux_explicit_sync_v1 *
+ds_linux_explicit_sync_v1_create(struct wl_display *display);
+{
+ struct ds_linux_explicit_sync_v1 *explicit_sync;
+
+ explicit_sync = calloc(1, sizeof *explicit_sync);
+ if (!explicit_sync)
+ return NULL;
+
+ explicit_sync->global = wl_global_create(display,
+ &zwp_linux_explicit_synchronization_v1_interface,
+ ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_VERSION,
+ explicit_sync,
+ linux_explicit_sync_v1_bind);
+ if (!explicit_sync->global) {
+ ds_err("Could not create global");
+ free(explicit_sync);
+ return NULL;
+ }
+
+ explicit_sync->display_destroy.notify =
+ linux_explicit_sync_v1_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &explicit_sync->display_destroy);
+
+ ds_inf("Create ds_linux_explicit_sync_v1");
+
+ return explicit_sync;
+}
+
+static void
+linux_explicit_sync_v1_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_linux_explicit_sync_v1 *explicit_sync;
+
+ explicit_sync = wl_container_of(listener, explicit_sync, display_destroy);
+
+ wl_global_destroy(explicit_sync->global);
+ free(explicit_sync);
+}
+
+static void
+surface_destroy(struct ds_linux_explicit_sync_v1_surface *surface)
+{
+ fd_clear(&surface->pending.acquire_fence_fd);
+ ds_addon_finish(&surface->addon);
+ free(surface);
+}
+
+static void
+surface_addon_destroy(struct ds_addon *addon)
+{
+ struct ds_linux_explicit_sync_v1_surface *surface;
+
+ surface = wl_container_of(addon, surface, addon);
+ surface_destroy(surface);
+}
+
+static const struct ds_addon_interface surface_addon_impl = {
+ .name = "ds_linux_explicit_sync_v1_surface",
+ .destroy = surface_addon_destroy,
+};
+
+static ds_linux_explicit_sync_v1_surface *
+create_surface(struct ds_linux_explicit_sync_v1 *explicit_sync,
+ struct ds_surface *ds_surface)
+{
+ struct ds_linux_explicit_sync_v1_surface *surface;
+
+ surface = calloc(1, sizeof(*surface));
+ if (!surface)
+ return NULL;
+
+ surface->surface = ds_surface;
+ surface->explicit_sync = explicit_sync;
+
+ ds_addon_init(&surface->addon, &ds_surface->addons, explicit_sync,
+ &surface_addon_impl);
+}
+
+static void
+linux_explicit_sync_v1_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+surface_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_linux_explicit_sync_v1_surface *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ if (!surface)
+ return;
+
+ surface_destroy(surface);
+ surface->synchronization_resource = NULL;
+}
+
+static void
+surface_sync_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+surface_sync_handle_set_acquire_fence(struct wl_client *client,
+ struct wl_resource *resource, int32_t fd)
+{
+ struct ds_surface *surface;
+
+ surface = wl_resource_get_user_data(resource);
+}
+
+static void
+surface_sync_handle_get_release(struct wl_client *client,
+ struct wl_resource *resource, int32_t id)
+{
+
+}
+
+const struct zwp_linux_surface_synchronization_v1_interface
+surface_impl = {
+ .destroy = surface_sync_handle_destroy,
+ .set_acquire_fence = surface_sync_handle_set_acquire_fence,
+ .get_release = surface_sync_handle_get_release,
+}
+
+static void
+linux_explicit_sync_handle_get_synchronization(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct ds_linux_explicit_sync_v1 *explicit_sync;
+ struct ds_linux_explicit_sync_v1_surface *surface;
+ struct ds_surface *ds_surface;
+ struct ds_addon *addon;
+
+ explicit_sync = wl_resource_get_user_data(resource);
+
+ ds_surface = ds_surface_from_resource(surface_resource);
+ DS_ASSERT(ds_surface);
+
+ addon = ds_addon_find(&ds_surface->addons, explicit_sync, &surface_addon_impl);
+ if (addon) {
+ wl_resource_post_error(resource,
+ ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_V1_ERROR_SYNCHRONIZATION_EXISTS,
+ "wl_surface@d already has a synchronization object",
+ wl_resource_get_id(surface_resource));
+ return;
+ }
+
+ surface = create_surface(explicit_sync, ds_surface);
+ if (!surface) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ surface->resource = wl_resource_create(client,
+ &zwp_linux_surface_synchronization_v1_interface,
+ wl_resource_get_version(resource), id);
+ if (!surface->resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(surface->resource,
+ &surface_impl,
+ surface,
+ surface_handle_resource_destroy);
+}
+
+static const struct zwp_linux_explicit_synchronization_v1_interface
+linux_explicit_sync_v1_impl = {
+ .destroy = linux_explicit_sync_v1_destroy,
+ .get_synchronization = linux_explicit_sync_handle_get_synchronization,
+}
+
+static void
+linux_explicit_sync_v1_bind(struct wl_client *client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct ds_linux_explicit_sync_v1 *explicit_sync = data;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client,
+ &zwp_linux_explicit_synchronization_v1_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &linux_explicit_sync_v1_impl,
+ explicit_sync, NULL);
+}
+