--- /dev/null
+#ifndef LIBDS_XDG_SHELL_V6_H
+#define LIBDS_XDG_SHELL_V6_H
+
+#include <stdint.h>
+#include <wayland-server.h>
+
+#include "surface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_xdg_shell_v6;
+
+struct ds_xdg_surface_v6;
+
+struct ds_xdg_shell_v6 *
+ds_xdg_shell_v6_create(struct wl_display *display);
+
+void
+ds_xdg_shell_v6_add_destroy_listener(struct ds_xdg_shell_v6 *shell,
+ struct wl_listener *listener);
+
+void
+ds_xdg_shell_v6_add_new_surface_listener(struct ds_xdg_shell_v6 *shell,
+ struct wl_listener *listener);
+
+void
+ds_xdg_surface_v6_add_destroy_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener);
+
+void
+ds_xdg_surface_v6_add_map_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener);
+
+void
+ds_xdg_surface_v6_add_unmap_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener);
+
+void
+ds_xdg_surface_v6_ping(struct ds_xdg_surface_v6 *surface);
+
+struct ds_surface *
+ds_xdg_surface_v6_get_surface(struct ds_xdg_surface_v6 *surface);
+
+uint32_t
+ds_xdg_toplevel_set_size(struct ds_xdg_surface_v6 *surface,
+ uint32_t width, uint32_t height);
+
+uint32_t
+ds_xdg_toplevel_set_activated(struct ds_xdg_surface_v6 *surface,
+ bool activated);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
BuildRequires: pkgconfig(wayland-server)
BuildRequires: pkgconfig(wayland-client)
BuildRequires: pkgconfig(wayland-protocols)
+BuildRequires: pkgconfig(xdg-shell-unstable-v6-server)
BuildRequires: pkgconfig(pixman-1)
BuildRequires: pkgconfig(libdrm)
BuildRequires: pkgconfig(xkbcommon)
%description devel
Development package of Wayland Compositor Library
+## libds-xdg-shell-v6
+%package xdg-shell-v6
+Summary: Wayland Compositor Library for xdg-shell-v6
+Group: Development/Libraries
+
+%description xdg-shell-v6
+Wayland Compositor Library for xdg-shell-v6
+
+%package xdg-shell-v6-devel
+Summary: Wayland Compositor Development package for xdg-shell-v6
+Group: Development/Libraries
+
+%description xdg-shell-v6-devel
+Wayland Compositor Development package for xdg-shell-v6
+
%prep
%setup -q
cp %{SOURCE1001} .
%{_bindir}/input-device-test
%{_bindir}/libinput-backend
%{_bindir}/ds-simple-shm-shell
+
+%files xdg-shell-v6
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_libdir}/libds-xdg-shell-v6.so.*
+
+%files xdg-shell-v6-devel
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_includedir}/libds/xdg_shell_v6.h
+%{_libdir}/pkgconfig/libds-xdg-shell-v6.pc
+%{_libdir}/libds-xdg-shell-v6.so
name: meson.project_name(),
description: 'Wayland compositor library',
)
+
+subdir('xdg_shell_v6')
--- /dev/null
+libds_xdg_shell_v6_files = [
+ 'xdg_shell_v6.c',
+ 'xdg_surface_v6.c',
+ 'xdg_toplevel_v6.c',
+]
+
+libds_xdg_shell_v6_deps = [
+ dep_libds,
+ dependency('xdg-shell-unstable-v6-server', required: true),
+]
+
+lib_libds_xdg_shell_v6 = shared_library('ds-xdg-shell-v6', libds_xdg_shell_v6_files,
+ dependencies: libds_xdg_shell_v6_deps,
+ include_directories: [ common_inc, include_directories('.'), include_directories('..') ],
+ version: meson.project_version(),
+ install: true
+)
+
+deps_libds_xdg_shell_v6 = declare_dependency(
+ link_with: lib_libds_xdg_shell_v6,
+ dependencies: libds_xdg_shell_v6_deps,
+ include_directories: [ common_inc, include_directories('.') ],
+)
+
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(lib_libds_xdg_shell_v6,
+ version: meson.project_version(),
+ filebase: 'libds-xdg-shell-v6',
+ name: 'libds-xdg-shell-v6',
+ description: 'wayland server implementation of xdg-shel-v6 unstable protocol',
+)
--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "libds/log.h"
+#include "libds/xdg_shell_v6.h"
+
+#include "xdg_shell_v6.h"
+
+#define XDG_SHELL_V6_BASE_VERSION 1
+#define XDG_SHELL_V6_PING_TIMEOUT 10000
+
+static void xdg_shell_v6_handle_display_destroy(struct wl_listener *listener,
+ void *data);
+static void xdg_shell_v6_bind(struct wl_client *wl_client, void *data,
+ uint32_t verison, uint32_t id);
+
+WL_EXPORT struct ds_xdg_shell_v6 *
+ds_xdg_shell_v6_create(struct wl_display *display)
+{
+ struct ds_xdg_shell_v6 *shell;
+
+ shell = calloc(1, sizeof *shell);
+ if (!shell) {
+ return NULL;
+ }
+
+ shell->ping_timeout = XDG_SHELL_V6_PING_TIMEOUT;
+
+ wl_list_init(&shell->clients);
+
+ shell->global = wl_global_create(display, &zxdg_shell_v6_interface,
+ XDG_SHELL_V6_BASE_VERSION, shell, xdg_shell_v6_bind);
+ if (!shell->global) {
+ free(shell);
+ return NULL;
+ }
+
+ wl_signal_init(&shell->events.destroy);
+ wl_signal_init(&shell->events.new_surface);
+
+ shell->display_destroy.notify = xdg_shell_v6_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &shell->display_destroy);
+
+ ds_inf("Global created: xdg_shell_v6(%p)", shell);
+
+ return shell;
+}
+
+WL_EXPORT void
+ds_xdg_shell_v6_add_destroy_listener(struct ds_xdg_shell_v6 *shell,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&shell->events.destroy, listener);
+}
+
+void
+ds_xdg_shell_v6_add_new_surface_listener(struct ds_xdg_shell_v6 *shell,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&shell->events.new_surface, listener);
+}
+
+static void
+xdg_shell_v6_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_xdg_shell_v6 *shell;
+
+ shell = wl_container_of(listener, shell, display_destroy);
+
+ ds_inf("Global destroy: xdg_shell_v6(%p)", shell);
+
+ wl_signal_emit(&shell->events.destroy, shell);
+ wl_list_remove(&shell->display_destroy.link);
+ wl_global_destroy(shell->global);
+ free(shell);
+}
+
+static void
+xdg_shell_v6_handle_destroy(struct wl_client *wl_client,
+ struct wl_resource *resource)
+{
+ struct ds_xdg_client_v6 *client;
+
+ client = wl_resource_get_user_data(resource);
+
+ if (!wl_list_empty(&client->surfaces)) {
+ wl_resource_post_error(client->resource,
+ ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES,
+ "xdg_shell_v6 was destroyed before children");
+ return;
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_shell_v6_handle_create_positioner(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t id)
+{
+ // TODO
+}
+
+static void
+xdg_shell_v6_handle_get_xdg_surface_v6(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct ds_xdg_client_v6 *client;
+ struct ds_surface *surface;
+
+ client = wl_resource_get_user_data(resource);
+ surface = ds_surface_from_resource(surface_resource);
+ create_xdg_surface_v6(client, surface, id);
+}
+
+static void
+xdg_shell_v6_handle_pong(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t serial)
+{
+ struct ds_xdg_client_v6 *client;
+
+ client = wl_resource_get_user_data(resource);
+ if (client->ping_serial != serial)
+ return;
+
+ wl_event_source_timer_update(client->ping_timer, 0);
+ client->ping_serial = 0;
+}
+
+static const struct zxdg_shell_v6_interface xdg_shell_v6_impl =
+{
+ .destroy = xdg_shell_v6_handle_destroy,
+ .create_positioner = xdg_shell_v6_handle_create_positioner,
+ .get_xdg_surface = xdg_shell_v6_handle_get_xdg_surface_v6,
+ .pong = xdg_shell_v6_handle_pong,
+};
+
+static void
+xdg_client_v6_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_xdg_client_v6 *client;
+ struct ds_xdg_surface_v6 *surface, *tmp;
+
+ client = wl_resource_get_user_data(resource);
+
+ wl_list_for_each_safe(surface, tmp, &client->surfaces, link)
+ destroy_xdg_surface_v6(surface);
+
+ if (client->ping_timer != NULL)
+ wl_event_source_remove(client->ping_timer);
+
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static int
+xdg_client_v6_handle_ping_timeout(void *user_data)
+{
+ struct ds_xdg_client_v6 *client = user_data;
+ struct ds_xdg_surface_v6 *surface;
+
+ wl_list_for_each(surface, &client->surfaces, link)
+ wl_signal_emit(&surface->events.ping_timeout, surface);
+
+ client->ping_serial = 0;
+
+ return 1;
+}
+
+static void
+xdg_client_v6_init_ping_timer(struct ds_xdg_client_v6 *client)
+{
+ struct wl_display *display;
+ struct wl_event_loop *loop;
+
+ display = wl_client_get_display(client->wl_client);
+ loop = wl_display_get_event_loop(display);
+ client->ping_timer = wl_event_loop_add_timer(loop,
+ xdg_client_v6_handle_ping_timeout, client);
+ if (client->ping_timer == NULL)
+ wl_client_post_no_memory(client->wl_client);
+}
+
+static void
+xdg_shell_v6_bind(struct wl_client *wl_client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct ds_xdg_shell_v6 *shell = data;
+ struct ds_xdg_client_v6 *client;
+
+ client = calloc(1, sizeof *client);
+ if (client == NULL) {
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ client->wl_client = wl_client;
+ client->shell = shell;
+
+ wl_list_init(&client->surfaces);
+
+ client->resource =
+ wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id);
+ if (client->resource == NULL) {
+ free(client);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(client->resource, &xdg_shell_v6_impl, client,
+ xdg_client_v6_handle_resource_destroy);
+
+ wl_list_insert(&shell->clients, &client->link);
+
+ xdg_client_v6_init_ping_timer(client);
+}
--- /dev/null
+#ifndef DS_XDG_SHELL_V6_H
+#define DS_XDG_SHELL_V6_H
+
+#include <wayland-server.h>
+#include <xdg-shell-unstable-v6-server-protocol.h>
+
+#include "libds/output.h"
+
+#include "surface.h"
+
+enum ds_xdg_surface_v6_role
+{
+ DS_XDG_SURFACE_V6_ROLE_NONE,
+ DS_XDG_SURFACE_V6_ROLE_TOPLEVEL,
+ DS_XDG_SURFACE_V6_ROLE_POPUP,
+};
+
+struct ds_xdg_shell_v6
+{
+ struct wl_global *global;
+
+ struct wl_list clients;
+
+ struct wl_listener display_destroy;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal new_surface;
+ } events;
+
+ uint32_t ping_timeout;
+};
+
+struct ds_xdg_client_v6
+{
+ struct ds_xdg_shell_v6 *shell;
+
+ struct wl_resource *resource;
+ struct wl_client *wl_client;
+ struct wl_event_source *ping_timer;
+
+ struct wl_list surfaces;
+
+ struct wl_list link; // ds_xdg_shell_v6::clients
+
+ uint32_t ping_serial;
+};
+
+struct ds_xdg_toplevle_v6_state
+{
+ bool maximized, fullscreen, resizing, activated;
+ uint32_t tiled;
+ uint32_t width, height;
+ uint32_t max_width, max_height;
+ uint32_t min_width, min_height;
+};
+
+struct ds_xdg_toplevle_v6_configure
+{
+ bool maximized, fullscreen, resizing, activated;
+ uint32_t tiled;
+ uint32_t width, height;
+};
+
+struct ds_xdg_toplevel_v6_requested
+{
+ bool maximized, minimized, fullscreen;
+ struct ds_output *fullscreen_output;
+ struct wl_listener fullscreen_output_destroy;
+};
+
+struct ds_xdg_toplevle_v6
+{
+ struct wl_resource *resource;
+ struct ds_xdg_surface_v6 *base;
+ bool added;
+
+ struct ds_xdg_surface_v6 *parent;
+ struct wl_listener parent_unmap;
+
+ struct ds_xdg_toplevle_v6_state current, pending;
+ struct ds_xdg_toplevle_v6_configure scheduled;
+ struct ds_xdg_toplevel_v6_requested requested;
+
+ char *title;
+ char *app_id;
+
+ struct {
+ struct wl_signal request_maximize;
+ struct wl_signal request_fullscreen;
+ struct wl_signal request_minimize;
+ struct wl_signal request_move;
+ struct wl_signal request_resize;
+ struct wl_signal request_show_window_menu;
+ struct wl_signal set_parent;
+ struct wl_signal set_title;
+ struct wl_signal set_app_id;
+ } events;
+};
+
+struct ds_xdg_popup
+{
+
+};
+
+struct ds_xdg_surface_v6_state
+{
+ uint32_t configure_serial;
+ struct {
+ int x, y;
+ int width, height;
+ } geometry;
+};
+
+struct ds_xdg_surface_v6
+{
+ struct ds_xdg_client_v6 *client;
+ struct ds_surface *ds_surface;
+
+ enum ds_xdg_surface_v6_role role;
+
+ union {
+ struct ds_xdg_toplevle_v6 *toplevel;
+ struct ds_xdg_popup *popup;
+ };
+
+ struct wl_resource *resource;
+
+ struct wl_event_source *configure_idle;
+ uint32_t scheduled_serial;
+ struct wl_list configure_list;
+
+ struct ds_xdg_surface_v6_state current, pending;
+
+ struct wl_list link; // ds_xdg_client_v6::surfaces
+
+ struct {
+ struct wl_listener surface_destroy;
+ struct wl_listener surface_commit;
+ } listener;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal ping_timeout;
+ struct wl_signal new_popup;
+ struct wl_signal map;
+ struct wl_signal unmap;
+ struct wl_signal configure;
+ struct wl_signal ack_configure;
+ } events;
+
+ bool added, configured, mapped;
+};
+
+struct ds_xdg_surface_v6_configure
+{
+ struct ds_xdg_surface_v6 *surface;
+ struct wl_list link;
+ uint32_t serial;
+
+ struct ds_xdg_toplevle_v6_configure *toplevel_configure;
+};
+
+uint32_t
+ds_xdg_surface_v6_schedule_configure(struct ds_xdg_surface_v6 *surface);
+
+struct ds_xdg_surface_v6 *
+create_xdg_surface_v6(struct ds_xdg_client_v6 *client, struct ds_surface *surface,
+ uint32_t id);
+
+void destroy_xdg_surface_v6(struct ds_xdg_surface_v6 *surface);
+
+void
+reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface);
+
+void
+create_xdg_toplevel_v6(struct ds_xdg_surface_v6 *surface, uint32_t id);
+
+void
+handle_xdg_surface_v6_commit(struct ds_surface *ds_surface);
+
+void
+handle_xdg_surface_v6_toplevel_committed(struct ds_xdg_surface_v6 *surface);
+
+void
+send_xdg_toplevel_v6_configure(struct ds_xdg_surface_v6 *surface,
+ struct ds_xdg_surface_v6_configure *configure);
+
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+
+#include "libds/log.h"
+
+#include "xdg_shell_v6.h"
+
+static const struct zxdg_surface_v6_interface xdg_surface_v6_impl;
+
+static void xdg_surface_v6_handle_surface_destroy(struct wl_listener *listener,
+ void *data);
+static void xdg_surface_v6_handle_surface_commit(struct wl_listener *listener,
+ void *data);
+static void xdg_surface_v6_handle_resource_destroy(struct wl_resource *resource);
+static void xdg_surface_v6_configure_destroy(struct ds_xdg_surface_v6_configure *configure);
+static void surface_send_configure(void *user_data);
+
+void
+ds_xdg_surface_v6_add_destroy_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&surface->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_xdg_surface_v6_add_map_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&surface->events.map, listener);
+}
+
+WL_EXPORT void
+ds_xdg_surface_v6_add_unmap_listener(struct ds_xdg_surface_v6 *surface,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&surface->events.unmap, listener);
+}
+
+struct ds_surface *
+ds_xdg_surface_v6_get_surface(struct ds_xdg_surface_v6 *surface)
+{
+ return surface->ds_surface;
+}
+
+struct ds_xdg_surface_v6 *
+create_xdg_surface_v6(struct ds_xdg_client_v6 *client, struct ds_surface *ds_surface,
+ uint32_t id)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = calloc(1, sizeof *surface);
+ if (!surface) {
+ wl_client_post_no_memory(client->wl_client);
+ return NULL;
+ }
+
+ surface->client = client;
+ surface->role = DS_XDG_SURFACE_V6_ROLE_NONE;
+ surface->ds_surface = ds_surface;
+ surface->resource = wl_resource_create(client->wl_client,
+ &zxdg_surface_v6_interface, wl_resource_get_version(client->resource),
+ id);
+ if (!surface->resource) {
+ free(surface);
+ wl_client_post_no_memory(client->wl_client);
+ return NULL;
+ }
+
+ if (ds_surface_has_buffer(surface->ds_surface)) {
+ wl_resource_destroy(surface->resource);
+ free(surface);
+ wl_resource_post_error(client->resource,
+ ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
+ "xdg_surface_v6 must not have a buffer at creation");
+ return NULL;
+ }
+
+ wl_list_init(&surface->configure_list);
+
+ wl_signal_init(&surface->events.destroy);
+ wl_signal_init(&surface->events.ping_timeout);
+ wl_signal_init(&surface->events.new_popup);
+ wl_signal_init(&surface->events.map);
+ wl_signal_init(&surface->events.unmap);
+ wl_signal_init(&surface->events.configure);
+ wl_signal_init(&surface->events.ack_configure);
+
+ surface->listener.surface_destroy.notify =
+ xdg_surface_v6_handle_surface_destroy;
+ ds_surface_add_destroy_listener(ds_surface,
+ &surface->listener.surface_destroy);
+
+ surface->listener.surface_commit.notify =
+ xdg_surface_v6_handle_surface_commit;
+ ds_surface_add_commit_listener(ds_surface,
+ &surface->listener.surface_commit);
+
+ wl_resource_set_implementation(surface->resource, &xdg_surface_v6_impl,
+ surface, xdg_surface_v6_handle_resource_destroy);
+
+ wl_list_insert(&client->surfaces, &surface->link);
+
+ ds_inf("New xdg_surface_v6 %p (res %p)", surface, surface->resource);
+
+ return surface;
+}
+
+void
+unmap_xdg_surface_v6(struct ds_xdg_surface_v6 *surface)
+{
+ struct ds_xdg_surface_v6_configure *configure, *tmp;
+
+ // TODO handle popup
+
+ if (surface->mapped)
+ wl_signal_emit(&surface->events.unmap, surface);
+
+ switch (surface->role) {
+ case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
+ if (surface->toplevel->parent) {
+ wl_list_remove(&surface->toplevel->parent_unmap.link);
+ surface->toplevel->parent = NULL;
+ }
+ free(surface->toplevel->title);
+ surface->toplevel->title = NULL;
+ free(surface->toplevel->app_id);
+ surface->toplevel->app_id = NULL;
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ // TODO
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_NONE:
+ assert(false && "not reached");
+ }
+
+ wl_list_for_each_safe(configure, tmp, &surface->configure_list, link)
+ xdg_surface_v6_configure_destroy(configure);
+
+ if (surface->configure_idle) {
+ wl_event_source_remove(surface->configure_idle);
+ surface->configure_idle = NULL;
+ }
+
+ surface->configured = false;
+ surface->mapped = false;
+}
+
+void
+reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface)
+{
+ struct ds_xdg_toplevel_v6_requested *req;
+
+ if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE)
+ unmap_xdg_surface_v6(surface);
+
+ if (surface->added) {
+ wl_signal_emit(&surface->events.destroy, surface);
+ surface->added = false;
+ }
+
+ switch (surface->role) {
+ case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
+ wl_resource_set_user_data(surface->toplevel->resource, NULL);
+ surface->toplevel->resource = NULL;
+ req = &surface->toplevel->requested;
+ if (req->fullscreen_output)
+ wl_list_remove(&req->fullscreen_output_destroy.link);
+ free(surface->toplevel);
+ surface->toplevel = NULL;
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ // TODO
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_NONE:
+ // This space is intentionally left blank
+ break;
+ }
+
+ surface->role = DS_XDG_SURFACE_V6_ROLE_NONE;
+}
+
+void
+destroy_xdg_surface_v6(struct ds_xdg_surface_v6 *surface)
+{
+ reset_xdg_surface_v6(surface);
+
+ wl_resource_set_user_data(surface->resource, NULL);
+
+ ds_surface_reset_role_data(surface->ds_surface);
+
+ wl_list_remove(&surface->link);
+ wl_list_remove(&surface->listener.surface_destroy.link);
+ wl_list_remove(&surface->listener.surface_commit.link);
+
+ free(surface);
+}
+
+void
+handle_xdg_surface_v6_commit(struct ds_surface *ds_surface)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = ds_surface_get_role_data(ds_surface);
+ surface->current = surface->pending;
+
+ switch (surface->role) {
+ case DS_XDG_SURFACE_V6_ROLE_NONE:
+ // inert toplevel or popup
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
+ handle_xdg_surface_v6_toplevel_committed(surface);
+ // TODO
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ // TODO
+ break;
+ }
+
+ if (!surface->added) {
+ surface->added = true;
+ wl_signal_emit(&surface->client->shell->events.new_surface, surface);
+ }
+
+ if (surface->configured &&
+ ds_surface_has_buffer(surface->ds_surface) &&
+ !surface->mapped) {
+ surface->mapped = true;
+ wl_signal_emit(&surface->events.map, surface);
+ }
+}
+
+void handle_xdg_surface_v6_precommit(struct ds_surface *ds_surface)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = ds_surface_get_role_data(ds_surface);
+
+ // TODO
+ (void)surface;
+}
+
+uint32_t
+ds_xdg_surface_v6_schedule_configure(struct ds_xdg_surface_v6 *surface)
+{
+ struct wl_display *display;
+ struct wl_event_loop *loop;
+
+ display = wl_client_get_display(surface->client->wl_client);
+ loop = wl_display_get_event_loop(display);
+
+ if (!surface->configure_idle) {
+ surface->scheduled_serial = wl_display_next_serial(display);
+ surface->configure_idle = wl_event_loop_add_idle(loop,
+ surface_send_configure, surface);
+ if (!surface->configure_idle)
+ wl_client_post_no_memory(surface->client->wl_client);
+ }
+
+ return surface->scheduled_serial;
+}
+
+void
+ds_xdg_surface_v6_ping(struct ds_xdg_surface_v6 *surface)
+{
+ struct wl_display *display;
+
+ display = wl_client_get_display(surface->client->wl_client);
+
+ surface->client->ping_serial = wl_display_next_serial(display);
+ zxdg_shell_v6_send_ping(surface->resource, surface->client->ping_serial);
+}
+
+static void
+xdg_surface_v6_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_container_of(listener, surface, listener.surface_destroy);
+ destroy_xdg_surface_v6(surface);
+}
+
+static void
+xdg_surface_v6_handle_surface_commit(struct wl_listener *listener, void *data)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_container_of(listener, surface, listener.surface_commit);
+
+ if (ds_surface_has_buffer(surface->ds_surface) &&
+ !surface->configured) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
+ "xdg_surface_v6 has never been configured");
+ return;
+ }
+
+ if (!ds_surface_get_role(surface->ds_surface)) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface_v6 must have a role");
+ return;
+ }
+}
+
+static void
+xdg_surface_v6_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ if (!surface)
+ return;
+
+ destroy_xdg_surface_v6(surface);
+}
+
+static void
+xdg_surface_v6_configure_destroy(struct ds_xdg_surface_v6_configure *configure)
+{
+ wl_list_remove(&configure->link);
+ free(configure->toplevel_configure);
+ free(configure);
+}
+
+static void
+xdg_surface_v6_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+
+ if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE) {
+ ds_err("Tried to destroy an xdg_surface_v6 before its role object");
+ return;
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_surface_v6_handle_get_toplevel(struct wl_client *client,
+ struct wl_resource *resource, uint32_t id)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ create_xdg_toplevel_v6(surface, id);
+}
+
+static void
+xdg_surface_v6_handle_get_popup(struct wl_client *client,
+ struct wl_resource *resource, uint32_t id,
+ struct wl_resource *parent_resource,
+ struct wl_resource *positioner_resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+
+ // TODO
+ (void)surface;
+}
+
+static void
+xdg_surface_v6_handle_ack_configure(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+
+ if (surface->role == DS_XDG_SURFACE_V6_ROLE_NONE) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface_v6 must have a role");
+ return;
+ }
+
+ bool found = false;
+ struct ds_xdg_surface_v6_configure *configure, *tmp;
+ wl_list_for_each(configure, &surface->configure_list, link) {
+ if (configure->serial == serial) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ wl_resource_post_error(surface->client->resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+ "wrong configure serial: %u", serial);
+ return;
+ }
+
+ wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
+ if (configure->serial == serial)
+ break;
+
+ wl_signal_emit(&surface->events.ack_configure, configure);
+ xdg_surface_v6_configure_destroy(configure);
+ }
+
+ switch (surface->role) {
+ case DS_XDG_SURFACE_V6_ROLE_NONE:
+ assert(0 && "not reached");
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
+ // TODO
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ break;
+ }
+
+ surface->configured = true;
+ surface->pending.configure_serial = serial;
+
+ wl_signal_emit(&surface->events.ack_configure, configure);
+ xdg_surface_v6_configure_destroy(configure);
+}
+
+static void
+xdg_surface_v6_handle_set_window_geometry(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+
+ if (surface->role == DS_XDG_SURFACE_V6_ROLE_NONE) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface_v6 must have a role");
+ return;
+ }
+
+ if (width <= 0 || height <= 0) {
+ ds_err("Client tried to set invalid geometry");
+ wl_resource_post_error(resource, -1,
+ "Tried to set invalid xdg_surface_v6 geometry");
+ return;
+ }
+
+ surface->pending.geometry.x = x;
+ surface->pending.geometry.y = y;
+ surface->pending.geometry.width = width;
+ surface->pending.geometry.height = height;
+}
+
+static const struct zxdg_surface_v6_interface xdg_surface_v6_impl =
+{
+ .destroy = xdg_surface_v6_handle_destroy,
+ .get_toplevel = xdg_surface_v6_handle_get_toplevel,
+ .get_popup = xdg_surface_v6_handle_get_popup,
+ .ack_configure = xdg_surface_v6_handle_ack_configure,
+ .set_window_geometry = xdg_surface_v6_handle_set_window_geometry,
+};
+
+static void
+surface_send_configure(void *user_data)
+{
+ struct ds_xdg_surface_v6 *surface;
+ struct ds_xdg_surface_v6_configure *configure;
+
+ surface = user_data;
+ surface->configure_idle = NULL;
+
+ configure = calloc(1, sizeof *configure);
+ if (!configure) {
+ wl_client_post_no_memory(surface->client->wl_client);
+ return;
+ }
+
+ wl_list_insert(surface->configure_list.prev, &configure->link);
+ configure->serial = surface->scheduled_serial;
+ configure->surface = surface;
+
+ switch (surface->role) {
+ case DS_XDG_SURFACE_V6_ROLE_NONE:
+ assert(0 && "not reached");
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
+ send_xdg_toplevel_v6_configure(surface, configure);
+ break;
+ case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ break;
+ }
+
+ wl_signal_emit(&surface->events.configure, configure);
+
+ zxdg_surface_v6_send_configure(surface->resource, configure->serial);
+}
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xdg_shell_v6.h"
+
+static const struct ds_surface_role xdg_toplevel_v6_surface_role =
+{
+ .name = "xdg_toplevel_v6",
+ .commit = handle_xdg_surface_v6_commit,
+};
+
+static const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_impl;
+
+static void xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource);
+
+void
+create_xdg_toplevel_v6(struct ds_xdg_surface_v6 *surface, uint32_t id)
+{
+ if (!ds_surface_set_role(surface->ds_surface, &xdg_toplevel_v6_surface_role,
+ surface, surface->resource, ZXDG_SHELL_V6_ERROR_ROLE))
+ return;
+
+ if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
+ "xdg_surface_v6 has already been constructed");
+ return;
+ }
+
+ assert(surface->toplevel == NULL);
+
+ surface->toplevel = calloc(1, sizeof *surface->toplevel);
+ if (!surface->toplevel) {
+ wl_resource_post_no_memory(surface->resource);
+ return;
+ }
+
+ surface->toplevel->base = surface;
+
+ wl_signal_init(&surface->toplevel->events.request_maximize);
+ wl_signal_init(&surface->toplevel->events.request_fullscreen);
+ wl_signal_init(&surface->toplevel->events.request_minimize);
+ wl_signal_init(&surface->toplevel->events.request_move);
+ wl_signal_init(&surface->toplevel->events.request_resize);
+ wl_signal_init(&surface->toplevel->events.request_show_window_menu);
+ wl_signal_init(&surface->toplevel->events.set_parent);
+ wl_signal_init(&surface->toplevel->events.set_title);
+ wl_signal_init(&surface->toplevel->events.set_app_id);
+
+ surface->toplevel->resource = wl_resource_create(
+ surface->client->wl_client, &zxdg_toplevel_v6_interface,
+ wl_resource_get_version(surface->resource), id);
+ if (!surface->toplevel->resource) {
+ free(surface->toplevel);
+ wl_resource_post_no_memory(surface->resource);
+ return;
+ }
+
+ wl_resource_set_implementation(surface->toplevel->resource,
+ &xdg_toplevel_v6_impl, surface,
+ xdg_toplevel_v6_handle_resource_destroy);
+
+ surface->role = DS_XDG_SURFACE_V6_ROLE_TOPLEVEL;
+}
+
+void
+handle_xdg_surface_v6_toplevel_committed(struct ds_xdg_surface_v6 *surface)
+{
+ if (!surface->toplevel->added) {
+ ds_xdg_surface_v6_schedule_configure(surface);
+ surface->toplevel->added = true;
+ return;
+ }
+
+ surface->toplevel->current = surface->toplevel->pending;
+}
+
+void
+send_xdg_toplevel_v6_configure(struct ds_xdg_surface_v6 *surface,
+ struct ds_xdg_surface_v6_configure *configure)
+{
+ struct wl_array states;
+ uint32_t width, height;
+
+ configure->toplevel_configure =
+ malloc(sizeof *configure->toplevel_configure);
+ if (!configure->toplevel_configure) {
+ wl_resource_post_no_memory(surface->toplevel->resource);
+ return;
+ }
+
+ *configure->toplevel_configure = surface->toplevel->scheduled;
+
+ wl_array_init(&states);
+ if (surface->toplevel->scheduled.maximized) {
+ uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s)
+ goto error_out;
+ *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
+ }
+
+ if (surface->toplevel->scheduled.fullscreen) {
+ uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s)
+ goto error_out;
+ *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
+ }
+
+ if (surface->toplevel->scheduled.resizing) {
+ uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s)
+ goto error_out;
+ *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
+ }
+
+ if (surface->toplevel->scheduled.activated) {
+ uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s)
+ goto error_out;
+ *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
+ }
+
+ if (surface->toplevel->scheduled.tiled) {
+ ;;;
+ // TODO
+ }
+
+ width = surface->toplevel->scheduled.width;
+ height = surface->toplevel->scheduled.height;
+
+ zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, height,
+ &states);
+ wl_array_release(&states);
+
+ return;
+
+error_out:
+ wl_array_release(&states);
+ wl_resource_post_no_memory(surface->toplevel->resource);
+}
+
+void
+destroy_xdg_toplevel_v6(struct ds_xdg_surface_v6 *xdg_surface_v6)
+{
+ reset_xdg_surface_v6(xdg_surface_v6);
+}
+
+static void
+xdg_toplevel_v6_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_toplevel_v6_handle_set_parent(struct wl_client *client,
+ struct wl_resource *resource, struct wl_resource *parent_resource)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_set_title(struct wl_client *client,
+ struct wl_resource *resource, const char *title)
+{
+ struct ds_xdg_surface_v6 *surface;
+ char *tmp;
+
+ surface = wl_resource_get_user_data(resource);
+ tmp = strdup(title);
+ if (!tmp) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ if (surface->toplevel->title)
+ free(surface->toplevel->title);
+
+ surface->toplevel->title = tmp;
+ wl_signal_emit(&surface->toplevel->events.set_title, surface);
+}
+
+static void
+xdg_toplevel_v6_handle_set_app_id(struct wl_client *client,
+ struct wl_resource *resource, const char *app_id)
+{
+ struct ds_xdg_surface_v6 *surface;
+ char *tmp;
+
+ surface = wl_resource_get_user_data(resource);
+ tmp = strdup(app_id);
+ if (!tmp) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ if (surface->toplevel->app_id)
+ free(surface->toplevel->app_id);
+
+ surface->toplevel->app_id= tmp;
+ wl_signal_emit(&surface->toplevel->events.set_app_id, surface);
+
+}
+
+static void
+xdg_toplevel_v6_handle_show_window_menu(struct wl_client *client,
+ struct wl_resource *resource, struct wl_resource *seat_resource,
+ uint32_t serial, int32_t x, int32_t y)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_move(struct wl_client *client,
+ struct wl_resource *resource, struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_resize(struct wl_client *client,
+ struct wl_resource *resource, struct wl_resource *seat_resource,
+ uint32_t serial, uint32_t edges)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_set_max_size(struct wl_client *client,
+ struct wl_resource *resource, int32_t width, int32_t height)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ surface->toplevel->pending.max_width = width;
+ surface->toplevel->pending.max_height = height;
+}
+
+static void
+xdg_toplevel_v6_handle_set_min_size(struct wl_client *client,
+ struct wl_resource *resource, int32_t width, int32_t height)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ surface->toplevel->pending.min_width = width;
+ surface->toplevel->pending.min_height = height;
+}
+
+static void
+xdg_toplevel_v6_handle_set_maximized(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ surface->toplevel->requested.maximized = true;
+ wl_signal_emit(&surface->toplevel->events.request_maximize, surface);
+ ds_xdg_surface_v6_schedule_configure(surface);
+}
+
+static void
+xdg_toplevel_v6_handle_unset_maximized(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ surface->toplevel->requested.maximized = false;
+ wl_signal_emit(&surface->toplevel->events.request_maximize, surface);
+ ds_xdg_surface_v6_schedule_configure(surface);
+}
+
+static void
+xdg_toplevel_v6_handle_set_fullscreen(struct wl_client *client,
+ struct wl_resource *resource, struct wl_resource *output_resource)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_unset_fullscreen(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ // TODO
+}
+
+static void
+xdg_toplevel_v6_handle_set_minimized(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ surface->toplevel->requested.minimized = true;
+ wl_signal_emit(&surface->toplevel->events.request_maximize, surface);
+}
+
+static const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_impl =
+{
+ xdg_toplevel_v6_handle_destroy,
+ xdg_toplevel_v6_handle_set_parent,
+ xdg_toplevel_v6_handle_set_title,
+ xdg_toplevel_v6_handle_set_app_id,
+ xdg_toplevel_v6_handle_show_window_menu,
+ xdg_toplevel_v6_handle_move,
+ xdg_toplevel_v6_handle_resize,
+ xdg_toplevel_v6_handle_set_max_size,
+ xdg_toplevel_v6_handle_set_min_size,
+ xdg_toplevel_v6_handle_set_maximized,
+ xdg_toplevel_v6_handle_unset_maximized,
+ xdg_toplevel_v6_handle_set_fullscreen,
+ xdg_toplevel_v6_handle_unset_fullscreen,
+ xdg_toplevel_v6_handle_set_minimized,
+};
+
+static void
+xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_xdg_surface_v6 *surface;
+
+ surface = wl_resource_get_user_data(resource);
+ if (!surface)
+ return;
+
+ destroy_xdg_toplevel_v6(surface);
+}