[RFC weston 1/6] Introduce libweston-desktop

Quentin Glidic sardemff7+wayland at sardemff7.net
Sun Jul 17 08:59:18 UTC 2016


From: Quentin Glidic <sardemff7+git at sardemff7.net>

Signed-off-by: Quentin Glidic <sardemff7+git at sardemff7.net>
---
 Makefile.am                               |  26 ++
 configure.ac                              |   1 +
 libweston-desktop/client.c                | 139 +++++++
 libweston-desktop/internal.h              | 109 +++++
 libweston-desktop/libweston-desktop.c     | 191 +++++++++
 libweston-desktop/libweston-desktop.h     | 111 ++++++
 libweston-desktop/libweston-desktop.pc.in |  12 +
 libweston-desktop/seat.c                  | 328 +++++++++++++++
 libweston-desktop/surface.c               | 525 ++++++++++++++++++++++++
 libweston-desktop/wl-shell.c              | 318 +++++++++++++++
 libweston-desktop/xdg-shell-v5.c          | 641 ++++++++++++++++++++++++++++++
 libweston-desktop/xwayland.c              | 287 +++++++++++++
 12 files changed, 2688 insertions(+)
 create mode 100644 libweston-desktop/client.c
 create mode 100644 libweston-desktop/internal.h
 create mode 100644 libweston-desktop/libweston-desktop.c
 create mode 100644 libweston-desktop/libweston-desktop.h
 create mode 100644 libweston-desktop/libweston-desktop.pc.in
 create mode 100644 libweston-desktop/seat.c
 create mode 100644 libweston-desktop/surface.c
 create mode 100644 libweston-desktop/wl-shell.c
 create mode 100644 libweston-desktop/xdg-shell-v5.c
 create mode 100644 libweston-desktop/xwayland.c

diff --git a/Makefile.am b/Makefile.am
index 436bb1b..6c44f2b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -105,6 +105,29 @@ libweston_la_SOURCES =					\
 	shared/platform.h				\
 	libweston/weston-egl-ext.h
 
+lib_LTLIBRARIES += libweston-desktop.la
+libweston_desktop_la_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON
+libweston_desktop_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS)
+libweston_desktop_la_LIBADD = libweston.la $(COMPOSITOR_LIBS)
+libweston_desktop_la_LDFLAGS = -release ${LIBWESTON_ABI_VERSION}
+
+libweston_desktop_la_SOURCES =				\
+	libweston-desktop/client.c			\
+	libweston-desktop/internal.h			\
+	libweston-desktop/libweston-desktop.c		\
+	libweston-desktop/libweston-desktop.h		\
+	libweston-desktop/seat.c			\
+	libweston-desktop/surface.c			\
+	libweston-desktop/wl-shell.c			\
+	libweston-desktop/xdg-shell-v5.c		\
+	libweston-desktop/xwayland.c
+
+nodist_libweston_desktop_la_SOURCES =				\
+	protocol/xdg-shell-unstable-v5-protocol.c		\
+	protocol/xdg-shell-unstable-v5-server-protocol.h
+
+libweston-desktop.la libweston-desktop/xdg-shell-v5.lo: protocol/xdg-shell-unstable-v5-server-protocol.h
+
 if SYSTEMD_NOTIFY_SUPPORT
 module_LTLIBRARIES += systemd-notify.la
 systemd_notify_la_LDFLAGS = -module -avoid-version
@@ -246,6 +269,9 @@ libwestoninclude_HEADERS =			\
 	shared/zalloc.h				\
 	shared/platform.h
 
+libwestoninclude_HEADERS +=			\
+	libweston-desktop/libweston-desktop.h
+
 westonincludedir = $(includedir)/weston
 westoninclude_HEADERS = compositor/weston.h
 
diff --git a/configure.ac b/configure.ac
index 85a475a..f52e8f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -638,6 +638,7 @@ AC_CONFIG_FILES([Makefile libweston/version.h compositor/weston.pc])
 # AC_CONFIG_FILES needs the full name when running autoconf, so we need to use
 # libweston_abi_version here, and outside [] because of m4 quoting rules
 AC_CONFIG_FILES([libweston/libweston-]libweston_abi_version[.pc:libweston/libweston.pc.in])
+AC_CONFIG_FILES([libweston-desktop/libweston-desktop-]libweston_abi_version[.pc:libweston-desktop/libweston-desktop.pc.in])
 
 AM_CONDITIONAL([HAVE_GIT_REPO], [test -f $srcdir/.git/logs/HEAD])
 
diff --git a/libweston-desktop/client.c b/libweston-desktop/client.c
new file mode 100644
index 0000000..8b73f71
--- /dev/null
+++ b/libweston-desktop/client.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+struct weston_desktop_client {
+    struct weston_desktop *desktop;
+    struct wl_client *client;
+    struct wl_resource *resource;
+    uint32_t ping_serial;
+    struct wl_event_source *ping_timer;
+    struct weston_desktop_surface *ping_surface;
+};
+
+static void
+_weston_desktop_client_destroy(struct wl_resource *resource)
+{
+    struct weston_desktop_client *self = wl_resource_get_user_data(resource);
+
+    free(self);
+}
+
+static int
+_weston_desktop_client_ping_timeout(void *user_data)
+{
+    struct weston_desktop_client *self = user_data;
+
+    weston_desktop_api_timeout(self->desktop, self->ping_surface);
+    return 1;
+}
+
+void
+weston_desktop_client_create(struct weston_desktop *desktop, struct wl_client *client, wl_dispatcher_func_t dispatcher, const struct wl_interface *interface, const void *implementation, uint32_t version, uint32_t id)
+{
+    struct weston_desktop_client *self;
+    struct wl_display *display;
+    struct wl_event_loop *loop;
+
+    self = zalloc(sizeof(struct weston_desktop_client));
+    if ( self == NULL )
+    {
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    self->desktop = desktop;
+    self->client = client;
+
+    self->resource = wl_resource_create(client, interface, version, id);
+    if ( self->resource == NULL )
+    {
+        wl_client_post_no_memory(client);
+        free(self);
+        return ;
+    }
+
+    if ( dispatcher != NULL )
+        wl_resource_set_dispatcher(self->resource, dispatcher, _weston_desktop_client_destroy, self, _weston_desktop_client_destroy);
+    else
+        wl_resource_set_implementation(self->resource, implementation, self, _weston_desktop_client_destroy);
+
+    display = wl_client_get_display(self->client);
+    loop = wl_display_get_event_loop(display);
+    self->ping_timer = wl_event_loop_add_timer(loop, _weston_desktop_client_ping_timeout, self);
+    if ( self->ping_timer == NULL )
+        wl_client_post_no_memory(client);
+}
+
+struct weston_desktop *
+weston_desktop_client_get_desktop(struct weston_desktop_client *self)
+{
+    return self->desktop;
+}
+
+struct wl_client *
+weston_desktop_client_get_client(struct weston_desktop_client *self)
+{
+    return self->client;
+}
+
+struct wl_resource *
+weston_desktop_client_get_resource(struct weston_desktop_client *self)
+{
+    return self->resource;
+}
+
+uint32_t
+weston_desktop_client_ping(struct weston_desktop_client *self, struct weston_desktop_surface *surface)
+{
+    if ( self->ping_serial != 0 )
+        return 0;
+    self->ping_serial = wl_display_next_serial(wl_client_get_display(self->client));
+    wl_event_source_timer_update(self->ping_timer, 10000);
+    self->ping_surface = surface;
+    return self->ping_serial;
+}
+
+void
+weston_desktop_client_pong(struct weston_desktop_client *self, uint32_t serial)
+{
+    if ( self->ping_serial != serial )
+        return;
+
+    wl_event_source_timer_update(self->ping_timer, 0);
+    self->ping_serial = 0;
+    self->ping_surface = NULL;
+}
diff --git a/libweston-desktop/internal.h b/libweston-desktop/internal.h
new file mode 100644
index 0000000..169b23f
--- /dev/null
+++ b/libweston-desktop/internal.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef WESTON_DESKTOP_INTERNAL_H
+#define WESTON_DESKTOP_INTERNAL_H
+
+#include "compositor.h"
+
+struct weston_desktop_seat;
+struct weston_desktop_client;
+
+struct weston_compositor *weston_desktop_get_compositor(struct weston_desktop *desktop);
+struct wl_display *weston_desktop_get_display(struct weston_desktop *desktop);
+
+void weston_desktop_api_timeout(struct weston_desktop *desktop, struct weston_desktop_surface *surface);
+void weston_desktop_api_surface_new(struct weston_desktop *desktop, struct weston_desktop_surface *surface);
+void weston_desktop_api_surface_free(struct weston_desktop *desktop, struct weston_desktop_surface *surface);
+void weston_desktop_api_commit(struct weston_desktop *desktop, struct weston_desktop_surface *surface, int32_t sx, int32_t sy);
+void weston_desktop_api_show_window_menu(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, int32_t x, int32_t y);
+void weston_desktop_api_set_parent(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_desktop_surface *parent);
+void weston_desktop_api_move(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial);
+void weston_desktop_api_resize(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, enum weston_desktop_surface_edge edges);
+void weston_desktop_api_ask_fullscreen(struct weston_desktop *desktop, struct weston_desktop_surface *surface, bool fullscreen);
+void weston_desktop_api_ask_maximized(struct weston_desktop *desktop, struct weston_desktop_surface *surface, bool maximized);
+void weston_desktop_api_ask_minimized(struct weston_desktop *desktop, struct weston_desktop_surface *surface);
+
+struct weston_desktop_surface_geometry weston_surface_get_bounding_box(struct weston_surface *surface);
+
+struct weston_desktop_seat *weston_seat_get_desktop_seat(struct weston_seat *seat);
+
+struct weston_desktop_surface_implementation {
+    void (*set_activated)(struct weston_desktop_surface *surface, void *user_data, bool activated);
+    void (*set_fullscreen)(struct weston_desktop_surface *surface, void *user_data, bool fullscreen);
+    void (*set_maximized)(struct weston_desktop_surface *surface, void *user_data, bool maximized);
+    void (*set_resizing)(struct weston_desktop_surface *surface, void *user_data, bool resizing);
+    void (*set_size)(struct weston_desktop_surface *surface, void *user_data, int32_t width, int32_t height);
+    void (*commit)(struct weston_desktop_surface *surface, void *user_data, int32_t sx, int32_t sy);
+    void (*ping)(struct weston_desktop_surface *surface, void *user_data);
+    void (*close)(struct weston_desktop_surface *surface, void *user_data);
+
+    bool (*get_activated)(struct weston_desktop_surface *surface, void *user_data);
+    bool (*get_fullscreen)(struct weston_desktop_surface *surface, void *user_data);
+    bool (*get_maximized)(struct weston_desktop_surface *surface, void *user_data);
+    bool (*get_resizing)(struct weston_desktop_surface *surface, void *user_data);
+    struct weston_desktop_surface_geometry (*get_geometry)(struct weston_desktop_surface *surface, void *user_data);
+    struct weston_desktop_surface_size (*get_max_size)(struct weston_desktop_surface *surface, void *user_data);
+    struct weston_desktop_surface_size (*get_min_size)(struct weston_desktop_surface *surface, void *user_data);
+
+    void (*free)(struct weston_desktop_surface *surface, void *user_data);
+};
+
+void weston_desktop_client_create(struct weston_desktop *desktop, struct wl_client *client, wl_dispatcher_func_t dispatcher, const struct wl_interface *interface, const void *implementation, uint32_t version, uint32_t id);
+
+struct weston_desktop *weston_desktop_client_get_desktop(struct weston_desktop_client *client);
+struct wl_client *weston_desktop_client_get_client(struct weston_desktop_client *client);
+struct wl_resource *weston_desktop_client_get_resource(struct weston_desktop_client *client);
+
+uint32_t weston_desktop_client_ping(struct weston_desktop_client *client, struct weston_desktop_surface *surface);
+void weston_desktop_client_pong(struct weston_desktop_client *client, uint32_t serial);
+
+struct weston_desktop_surface *weston_desktop_surface_create(struct weston_desktop *desktop, struct weston_desktop_client *client, struct weston_surface *surface, const struct weston_desktop_surface_implementation *implementation, void *implementation_data);
+void weston_desktop_surface_resource_destroy(struct wl_resource *resource);
+struct wl_resource *weston_desktop_surface_add_resource(struct weston_desktop_surface *self, const struct wl_interface *interface, const void *implementation, uint32_t id, wl_resource_destroy_func_t destroy);
+struct weston_desktop_surface *weston_desktop_surface_from_grab_link(struct wl_list *grab_link);
+
+struct weston_desktop_client *weston_desktop_surface_get_client(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_has_implementation(struct weston_desktop_surface *surface, const struct weston_desktop_surface_implementation *implementation);
+void *weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *surface);
+struct weston_desktop_surface *weston_desktop_surface_get_parent(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_get_grab(struct weston_desktop_surface *surface);
+
+void weston_desktop_surface_set_title(struct weston_desktop_surface *surface, const char *title);
+void weston_desktop_surface_set_app_id(struct weston_desktop_surface *surface, const char *app_id);
+void weston_desktop_surface_set_parent(struct weston_desktop_surface *self, struct weston_desktop_surface *surface, int32_t x, int32_t y);
+void weston_desktop_surface_grab(struct weston_desktop_surface *popup, struct weston_desktop_seat *seat, uint32_t serial);
+void weston_desktop_surface_ungrab(struct weston_desktop_surface *popup, struct weston_desktop_seat *seat);
+
+struct weston_desktop_surface *weston_desktop_seat_grab_get_topmost_surface(struct weston_desktop_seat *seat);
+bool weston_desktop_seat_grab_start(struct weston_desktop_seat *seat, struct wl_client *client, uint32_t serial);
+void weston_desktop_seat_grab_add_surface(struct weston_desktop_seat *seat, struct wl_list *link);
+void weston_desktop_seat_grab_remove_surface(struct weston_desktop_seat *seat, struct wl_list *link);
+
+void weston_desktop_destroy_request(struct wl_client *client, struct wl_resource *resource);
+struct wl_global *weston_desktop_xdg_shell_v6_create(struct weston_desktop *desktop, struct wl_display *display);
+struct wl_global *weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop, struct wl_display *display);
+struct wl_global *weston_desktop_wl_shell_create(struct weston_desktop *desktop, struct wl_display *display);
+void weston_desktop_xwayland_init(struct weston_desktop *desktop);
+
+#endif /* WESTON_DESKTOP_INTERNAL_H */
diff --git a/libweston-desktop/libweston-desktop.c b/libweston-desktop/libweston-desktop.c
new file mode 100644
index 0000000..5c6fcbb
--- /dev/null
+++ b/libweston-desktop/libweston-desktop.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+
+struct weston_desktop {
+    struct weston_compositor *compositor;
+    struct weston_desktop_api api;
+    void *user_data;
+    struct wl_global *xdg_shell_v5;
+    struct wl_global *wl_shell;
+};
+
+void
+weston_desktop_destroy_request(struct wl_client *client, struct wl_resource *resource)
+{
+    wl_resource_destroy(resource);
+}
+
+WL_EXPORT
+struct weston_desktop *
+weston_desktop_create(struct weston_compositor *compositor, const struct weston_desktop_api *api, void *user_data)
+{
+    struct weston_desktop *self;
+
+    self = zalloc(sizeof(struct weston_desktop));
+    self->compositor = compositor;
+    self->user_data = user_data;
+
+    if ( sizeof(struct weston_desktop_api) < api->struct_size )
+        self->api.struct_size = sizeof(struct weston_desktop_api);
+    else
+        self->api.struct_size = api->struct_size;
+    memcpy(&self->api, api, self->api.struct_size);
+
+    self->xdg_shell_v5 = weston_desktop_xdg_shell_v5_create(self, self->compositor->wl_display);
+    if ( self->xdg_shell_v5 == NULL )
+    {
+        weston_desktop_destroy(self);
+        return NULL;
+    }
+
+    self->wl_shell = weston_desktop_wl_shell_create(self, self->compositor->wl_display);
+    if ( self->wl_shell == NULL )
+    {
+        weston_desktop_destroy(self);
+        return NULL;
+    }
+
+    weston_desktop_xwayland_init(self);
+
+    return self;
+}
+
+WL_EXPORT
+void
+weston_desktop_destroy(struct weston_desktop *self)
+{
+    if ( self == NULL )
+        return;
+
+    if ( self->wl_shell != NULL )
+        wl_global_destroy(self->wl_shell);
+    if ( self->xdg_shell_v5 != NULL )
+        wl_global_destroy(self->xdg_shell_v5);
+
+    free(self);
+}
+
+
+struct weston_compositor *
+weston_desktop_get_compositor(struct weston_desktop *self)
+{
+    return self->compositor;
+}
+
+struct wl_display *
+weston_desktop_get_display(struct weston_desktop *self)
+{
+    return self->compositor->wl_display;
+}
+
+void
+weston_desktop_api_timeout(struct weston_desktop *self, struct weston_desktop_surface *surface)
+{
+    if ( self->api.timeout != NULL )
+        self->api.timeout(surface, self->user_data);
+}
+
+void
+weston_desktop_api_surface_new(struct weston_desktop *self, struct weston_desktop_surface *surface)
+{
+    if ( self->api.surface_new != NULL )
+        self->api.surface_new(surface, self->user_data);
+}
+
+void
+weston_desktop_api_surface_free(struct weston_desktop *self, struct weston_desktop_surface *surface)
+{
+    if ( self->api.surface_free != NULL )
+        self->api.surface_free(surface, self->user_data);
+}
+
+void
+weston_desktop_api_commit(struct weston_desktop *self, struct weston_desktop_surface *surface, int32_t sx, int32_t sy)
+{
+    if ( self->api.commit != NULL )
+        self->api.commit(surface, sx, sy, self->user_data);
+}
+
+void
+weston_desktop_api_show_window_menu(struct weston_desktop *self, struct weston_desktop_surface *surface, struct weston_seat *seat, int32_t x, int32_t y)
+{
+    if ( self->api.show_window_menu != NULL )
+        self->api.show_window_menu(surface, seat, x, y, self->user_data);
+}
+
+void
+weston_desktop_api_set_parent(struct weston_desktop *self, struct weston_desktop_surface *surface, struct weston_desktop_surface *parent)
+{
+    if ( self->api.set_parent != NULL )
+        self->api.set_parent(surface, parent, self->user_data);
+}
+
+void
+weston_desktop_api_move(struct weston_desktop *self, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial)
+{
+    if ( self->api.move != NULL )
+        self->api.move(surface, seat, serial, self->user_data);
+}
+
+void
+weston_desktop_api_resize(struct weston_desktop *self, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, enum weston_desktop_surface_edge edges)
+{
+    if ( self->api.resize != NULL )
+        self->api.resize(surface, seat, serial, edges, self->user_data);
+}
+
+void
+weston_desktop_api_ask_fullscreen(struct weston_desktop *self, struct weston_desktop_surface *surface, bool fullscreen)
+{
+    if ( self->api.ask_fullscreen != NULL )
+        self->api.ask_fullscreen(surface, fullscreen, self->user_data);
+}
+
+void
+weston_desktop_api_ask_maximized(struct weston_desktop *self, struct weston_desktop_surface *surface, bool maximized)
+{
+    if ( self->api.ask_maximized != NULL )
+        self->api.ask_maximized(surface, maximized, self->user_data);
+}
+
+void
+weston_desktop_api_ask_minimized(struct weston_desktop *self, struct weston_desktop_surface *surface)
+{
+    if ( self->api.ask_minimized != NULL )
+        self->api.ask_minimized(surface, self->user_data);
+}
diff --git a/libweston-desktop/libweston-desktop.h b/libweston-desktop/libweston-desktop.h
new file mode 100644
index 0000000..c0e4a56
--- /dev/null
+++ b/libweston-desktop/libweston-desktop.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef WESTON_DESKTOP_H
+#define WESTON_DESKTOP_H
+
+#include "compositor.h"
+#include <pixman.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct weston_desktop_surface_geometry {
+    int32_t x, y;
+    int32_t width, height;
+};
+
+struct weston_desktop_surface_position {
+    int32_t x, y;
+};
+
+struct weston_desktop_surface_size {
+    int32_t width, height;
+};
+
+enum weston_desktop_surface_edge {
+    WESTON_DESKTOP_SURFACE_EDGE_NONE = 0,
+    WESTON_DESKTOP_SURFACE_EDGE_TOP = 1,
+    WESTON_DESKTOP_SURFACE_EDGE_BOTTOM = 2,
+    WESTON_DESKTOP_SURFACE_EDGE_LEFT = 4,
+    WESTON_DESKTOP_SURFACE_EDGE_TOP_LEFT = 5,
+    WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_LEFT = 6,
+    WESTON_DESKTOP_SURFACE_EDGE_RIGHT = 8,
+    WESTON_DESKTOP_SURFACE_EDGE_TOP_RIGHT = 9,
+    WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_RIGHT = 10,
+};
+
+struct weston_desktop;
+struct weston_desktop_surface;
+
+struct weston_desktop_api {
+    size_t struct_size;
+    void (*timeout)(struct weston_desktop_surface *surface, void *user_data);
+    void (*surface_new)(struct weston_desktop_surface *surface, void *user_data);
+    void (*surface_free)(struct weston_desktop_surface *surface, void *user_data);
+    void (*commit)(struct weston_desktop_surface *surface, int32_t sx, int32_t sy, void *user_data);
+    void (*show_window_menu)(struct weston_desktop_surface *surface, struct weston_seat *seat, int32_t x, int32_t y, void *user_data);
+    void (*set_parent)(struct weston_desktop_surface *surface, struct weston_desktop_surface *parent, void *user_data);
+    void (*move)(struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, void *user_data);
+    void (*resize)(struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, enum weston_desktop_surface_edge edges, void *user_data);
+    void (*ask_fullscreen)(struct weston_desktop_surface *surface, bool fullscreen, void *user_data);
+    void (*ask_maximized)(struct weston_desktop_surface *surface, bool maximized, void *user_data);
+    void (*ask_minimized)(struct weston_desktop_surface *surface, void *user_data);
+};
+
+struct weston_desktop *weston_desktop_create(struct weston_compositor *compositor, const struct weston_desktop_api *api, void *user_data);
+void weston_desktop_destroy(struct weston_desktop *desktop);
+
+bool weston_surface_is_desktop_surface(struct weston_surface *surface);
+struct weston_desktop_surface *weston_surface_get_desktop_surface(struct weston_surface *surface);
+
+void weston_desktop_surface_set_user_data(struct weston_desktop_surface *self, void *user_data);
+void weston_desktop_surface_update_layer(struct weston_desktop_surface *surface);
+void weston_desktop_surface_set_activated(struct weston_desktop_surface *surface, bool activated);
+void weston_desktop_surface_set_fullscreen(struct weston_desktop_surface *surface, bool fullscreen);
+void weston_desktop_surface_set_maximized(struct weston_desktop_surface *surface, bool maximized);
+void weston_desktop_surface_set_resizing(struct weston_desktop_surface *surface, bool resized);
+void weston_desktop_surface_set_size(struct weston_desktop_surface *surface, int32_t width, int32_t height);
+void weston_desktop_surface_ping(struct weston_desktop_surface *surface);
+void weston_desktop_surface_close(struct weston_desktop_surface *surface);
+
+void *weston_desktop_surface_get_user_data(struct weston_desktop_surface *surface);
+struct weston_surface *weston_desktop_surface_get_surface(struct weston_desktop_surface *surface);
+struct weston_view *weston_desktop_surface_get_view(struct weston_desktop_surface *surface);
+const char *weston_desktop_surface_get_title(struct weston_desktop_surface *surface);
+const char *weston_desktop_surface_get_app_id(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_get_activated(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_get_maximized(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_get_fullscreen(struct weston_desktop_surface *surface);
+bool weston_desktop_surface_get_resizing(struct weston_desktop_surface *surface);
+struct weston_desktop_surface_geometry weston_desktop_surface_get_geometry(struct weston_desktop_surface *surface);
+struct weston_desktop_surface_size weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface);
+struct weston_desktop_surface_size weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WESTON_DESKTOP_H */
diff --git a/libweston-desktop/libweston-desktop.pc.in b/libweston-desktop/libweston-desktop.pc.in
new file mode 100644
index 0000000..dd14ee0
--- /dev/null
+++ b/libweston-desktop/libweston-desktop.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+pkgincludedir=${includedir}/libweston- at LIBWESTON_ABI_VERSION@
+
+Name: libweston-desktop
+Description: Desktop shells abstraction library for libweston compositors
+Version: @WESTON_VERSION@
+Requires.private: libweston wayland-server
+Cflags: -I${pkgincludedir}
+Libs: -L${libdir} -lweston- at LIBWESTON_ABI_VERSION@
diff --git a/libweston-desktop/seat.c b/libweston-desktop/seat.c
new file mode 100644
index 0000000..2889508
--- /dev/null
+++ b/libweston-desktop/seat.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#include <assert.h>
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+struct weston_desktop_seat {
+    struct wl_listener seat_destroy_listener;
+    struct weston_seat *seat;
+    struct weston_keyboard_grab keyboard_grab;
+    struct weston_pointer_grab pointer_grab;
+    struct weston_touch_grab touch_grab;
+    bool initial_up;
+    struct wl_client *client;
+    struct wl_list surfaces;
+};
+
+static void _weston_desktop_seat_grab_end(struct weston_desktop_seat *self);
+
+static void
+_weston_desktop_seat_keyboard_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key, enum wl_keyboard_key_state state)
+{
+    grab->keyboard->default_grab.interface->key(grab, time, key, state);
+}
+
+static void
+_weston_desktop_seat_keyboard_modifiers(struct weston_keyboard_grab *grab, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+    grab->keyboard->default_grab.interface->modifiers(grab, serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+static void
+_weston_desktop_seat_keyboard_cancel(struct weston_keyboard_grab *grab)
+{
+    struct weston_desktop_seat *self = wl_container_of(grab, self, keyboard_grab);
+
+    _weston_desktop_seat_grab_end(self);
+}
+
+static const struct weston_keyboard_grab_interface _weston_desktop_seat_keyboard_grab_interface = {
+   .key = _weston_desktop_seat_keyboard_key,
+   .modifiers = _weston_desktop_seat_keyboard_modifiers,
+   .cancel = _weston_desktop_seat_keyboard_cancel,
+};
+
+static void
+_weston_desktop_seat_pointer_focus(struct weston_pointer_grab *grab)
+{
+    struct weston_desktop_seat *self = wl_container_of(grab, self, pointer_grab);
+    struct weston_pointer *pointer = grab->pointer;
+    struct weston_view *view;
+    wl_fixed_t sx, sy;
+
+    view = weston_compositor_pick_view(pointer->seat->compositor, pointer->x, pointer->y, &sx, &sy);
+
+    if ( ( view != NULL ) && ( view->surface->resource != NULL ) && ( wl_resource_get_client(view->surface->resource) == self->client ) )
+        weston_pointer_set_focus(pointer, view, sx, sy);
+    else
+        weston_pointer_clear_focus(pointer);
+}
+
+static void
+_weston_desktop_seat_pointer_motion(struct weston_pointer_grab *grab, uint32_t time, struct weston_pointer_motion_event *event)
+{
+    grab->pointer->default_grab.interface->motion(grab, time, event);
+}
+
+static void
+_weston_desktop_seat_pointer_button(struct weston_pointer_grab *grab, uint32_t time, uint32_t button, enum wl_pointer_button_state state)
+{
+    struct weston_desktop_seat *self = wl_container_of(grab, self, pointer_grab);
+    struct weston_pointer *pointer = grab->pointer;
+    struct weston_compositor *compositor = pointer->seat->compositor;
+    struct wl_resource *resource;
+    uint32_t serial;
+    struct wl_display *display = compositor->wl_display;
+    struct wl_list *resource_list = NULL;
+
+    if ( pointer->focus_client != NULL )
+        resource_list = &pointer->focus_client->pointer_resources;
+    if ( ( resource_list != NULL ) && ! wl_list_empty(resource_list) )
+    {
+        serial = wl_display_next_serial(display);
+        wl_resource_for_each(resource, resource_list)
+            wl_pointer_send_button(resource, serial, time, button, state);
+    }
+    else if ( ( state == WL_POINTER_BUTTON_STATE_RELEASED ) && ( self->initial_up || ( ( time - grab->pointer->grab_time ) > 500 ) ) )
+        _weston_desktop_seat_grab_end(self);
+
+    if ( state == WL_POINTER_BUTTON_STATE_RELEASED )
+        self->initial_up = true;
+}
+
+static void
+_weston_desktop_seat_pointer_axis(struct weston_pointer_grab *grab, uint32_t time, struct weston_pointer_axis_event *event)
+{
+    grab->pointer->default_grab.interface->axis(grab, time, event);
+}
+
+static void
+_weston_desktop_seat_pointer_axis_source(struct weston_pointer_grab *grab, uint32_t source)
+{
+    grab->pointer->default_grab.interface->axis_source(grab, source);
+}
+
+static void
+_weston_desktop_seat_pointer_frame(struct weston_pointer_grab *grab)
+{
+    grab->pointer->default_grab.interface->frame(grab);
+}
+
+static void
+_weston_desktop_seat_pointer_cancel(struct weston_pointer_grab *grab)
+{
+    struct weston_desktop_seat *self = wl_container_of(grab, self, pointer_grab);
+
+    _weston_desktop_seat_grab_end(self);
+}
+
+static const struct weston_pointer_grab_interface _weston_desktop_seat_pointer_grab_interface = {
+   .focus = _weston_desktop_seat_pointer_focus,
+   .motion = _weston_desktop_seat_pointer_motion,
+   .button = _weston_desktop_seat_pointer_button,
+   .axis = _weston_desktop_seat_pointer_axis,
+   .axis_source = _weston_desktop_seat_pointer_axis_source,
+   .frame = _weston_desktop_seat_pointer_frame,
+   .cancel = _weston_desktop_seat_pointer_cancel,
+};
+
+static void
+_weston_desktop_seat_touch_down(struct weston_touch_grab *grab, uint32_t time, int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+    grab->touch->default_grab.interface->down(grab, time, touch_id, sx, sy);
+}
+
+static void
+_weston_desktop_seat_touch_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
+{
+    grab->touch->default_grab.interface->up(grab, time, touch_id);
+}
+
+static void
+_weston_desktop_seat_touch_motion(struct weston_touch_grab *grab, uint32_t time, int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+    grab->touch->default_grab.interface->motion(grab, time, touch_id, sx, sy);
+}
+
+static void
+_weston_desktop_seat_touch_frame(struct weston_touch_grab *grab)
+{
+    grab->touch->default_grab.interface->frame(grab);
+}
+
+static void
+_weston_desktop_seat_touch_cancel(struct weston_touch_grab *grab)
+{
+    struct weston_desktop_seat *self = wl_container_of(grab, self, touch_grab);
+
+    _weston_desktop_seat_grab_end(self);
+}
+
+static const struct weston_touch_grab_interface _weston_desktop_seat_touch_grab_interface = {
+   .down = _weston_desktop_seat_touch_down,
+   .up = _weston_desktop_seat_touch_up,
+   .motion = _weston_desktop_seat_touch_motion,
+   .frame = _weston_desktop_seat_touch_frame,
+   .cancel = _weston_desktop_seat_touch_cancel,
+};
+
+static void
+_weston_desktop_seat_destroy(struct wl_listener *listener, void *data)
+{
+    struct weston_desktop_seat *self = wl_container_of(listener, self, seat_destroy_listener);
+
+    free(self);
+}
+
+struct weston_desktop_seat *
+weston_seat_get_desktop_seat(struct weston_seat *seat)
+{
+    struct wl_listener *listener;
+    struct weston_desktop_seat *self;
+
+    listener = wl_signal_get(&seat->destroy_signal, _weston_desktop_seat_destroy);
+    if ( listener != NULL )
+        return wl_container_of(listener, self, seat_destroy_listener);
+
+    self = zalloc(sizeof(struct weston_desktop_seat));
+    if ( self == NULL )
+        return NULL;
+
+    self->seat = seat;
+
+    self->seat_destroy_listener.notify = _weston_desktop_seat_destroy;
+    wl_signal_add(&seat->destroy_signal, &self->seat_destroy_listener);
+
+    self->keyboard_grab.interface = &_weston_desktop_seat_keyboard_grab_interface;
+    self->pointer_grab.interface = &_weston_desktop_seat_pointer_grab_interface;
+    self->touch_grab.interface = &_weston_desktop_seat_touch_grab_interface;
+
+    wl_list_init(&self->surfaces);
+
+    return self;
+}
+
+struct weston_desktop_surface *
+weston_desktop_seat_grab_get_topmost_surface(struct weston_desktop_seat *self)
+{
+    if ( wl_list_empty(&self->surfaces) )
+        return NULL;
+
+    struct wl_list *grab_link = self->surfaces.next;
+
+    return weston_desktop_surface_from_grab_link(grab_link);
+}
+
+bool
+weston_desktop_seat_grab_start(struct weston_desktop_seat *self, struct wl_client *client, uint32_t serial)
+{
+    assert(self->client == NULL || self->client == client);
+
+    struct weston_keyboard *keyboard = weston_seat_get_keyboard(self->seat);
+    struct weston_pointer *pointer = weston_seat_get_pointer(self->seat);
+    struct weston_touch *touch = weston_seat_get_touch(self->seat);
+
+    if ( ( keyboard != NULL ) && ( keyboard->grab_serial == serial ) )
+    {
+        if ( keyboard->grab->interface != &_weston_desktop_seat_keyboard_grab_interface )
+            weston_keyboard_start_grab(keyboard, &self->keyboard_grab);
+    }
+    else if ( ( pointer != NULL ) && ( pointer->grab_serial == serial ) )
+    {
+        if ( pointer->grab->interface != &_weston_desktop_seat_pointer_grab_interface )
+            weston_pointer_start_grab(pointer, &self->pointer_grab);
+    }
+    else if ( ( touch != NULL ) && ( touch->grab_serial == serial ) )
+    {
+        if ( touch->grab->interface != &_weston_desktop_seat_touch_grab_interface )
+            weston_touch_start_grab(touch, &self->touch_grab);
+    }
+    else
+        return false;
+
+    self->initial_up = false;
+    self->client = client;
+
+    return true;
+}
+
+static void
+_weston_desktop_seat_grab_end(struct weston_desktop_seat *self)
+{
+    struct weston_keyboard *keyboard = weston_seat_get_keyboard(self->seat);
+    struct weston_pointer *pointer = weston_seat_get_pointer(self->seat);
+    struct weston_touch *touch = weston_seat_get_touch(self->seat);
+
+    struct wl_list *link, *tmp_link;
+    for ( link = self->surfaces.prev, tmp_link = link->next ; link != &self->surfaces ; link = tmp_link, tmp_link = link->next )
+    {
+        struct weston_desktop_surface *surface = weston_desktop_surface_from_grab_link(link);
+        wl_list_remove(link);
+        wl_list_init(link);
+        weston_desktop_surface_close(surface);
+    }
+
+    if ( keyboard->grab->interface == &_weston_desktop_seat_keyboard_grab_interface )
+        weston_keyboard_end_grab(keyboard);
+    else if ( pointer->grab->interface == &_weston_desktop_seat_pointer_grab_interface )
+        weston_pointer_end_grab(pointer);
+    else if ( touch->grab->interface == &_weston_desktop_seat_touch_grab_interface )
+        weston_touch_end_grab(touch);
+
+    self->client = NULL;
+}
+
+void
+weston_desktop_seat_grab_add_surface(struct weston_desktop_seat *self, struct wl_list *link)
+{
+    assert(self->client != NULL);
+
+    wl_list_insert(&self->surfaces, link);
+}
+
+void
+weston_desktop_seat_grab_remove_surface(struct weston_desktop_seat *self, struct wl_list *link)
+{
+    assert(self->client != NULL);
+
+    wl_list_remove(link);
+    wl_list_init(link);
+    if ( wl_list_empty(&self->surfaces) )
+        _weston_desktop_seat_grab_end(self);
+}
diff --git a/libweston-desktop/surface.c b/libweston-desktop/surface.c
new file mode 100644
index 0000000..239c805
--- /dev/null
+++ b/libweston-desktop/surface.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#include <assert.h>
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+struct weston_desktop_surface {
+    struct weston_desktop *desktop;
+    struct weston_desktop_client *client;
+    const struct weston_desktop_surface_implementation *implementation;
+    void *implementation_data;
+    void *user_data;
+    struct weston_surface *surface;
+    struct weston_view *view;
+    struct wl_listener surface_destroy_listener;
+    struct wl_listener view_destroy_listener;
+    struct wl_list children_list;
+
+    struct wl_list resources;
+    struct {
+        char *title;
+        char *app_id;
+    };
+    struct {
+        struct weston_desktop_surface *parent;
+        struct wl_list children_link;
+        int32_t x;
+        int32_t y;
+    };
+    struct {
+        struct wl_list grab_link;
+    };
+};
+
+struct weston_desktop_surface_geometry
+weston_surface_get_bounding_box(struct weston_surface *surface)
+{
+    pixman_region32_t region;
+    pixman_box32_t *box;
+    struct weston_subsurface *subsurface;
+
+    pixman_region32_init_rect(&region, 0, 0, surface->width, surface->height);
+
+    wl_list_for_each(subsurface, &surface->subsurface_list, parent_link)
+        pixman_region32_union_rect(&region, &region, subsurface->position.x, subsurface->position.y, subsurface->surface->width, subsurface->surface->height);
+
+    box = pixman_region32_extents(&region);
+    struct weston_desktop_surface_geometry geometry = {
+        .x = box->x1,
+        .y = box->y1,
+        .width = box->x2 - box->x1,
+        .height = box->y2 - box->y1,
+    };
+
+    pixman_region32_fini(&region);
+
+    return geometry;
+}
+
+static void
+_weston_desktop_surface_destroy(struct weston_desktop_surface *self)
+{
+    wl_list_remove(&self->view_destroy_listener.link);
+    wl_list_remove(&self->surface_destroy_listener.link);
+
+    if ( ! wl_list_empty(&self->resources) )
+    {
+        struct wl_resource *resource, *tmp;
+        wl_resource_for_each_safe(resource, tmp, &self->resources)
+        {
+            wl_resource_set_user_data(resource, NULL);
+            wl_list_remove(wl_resource_get_link(resource));
+        }
+    }
+
+    self->implementation->free(self, self->implementation_data);
+
+    wl_list_remove(&self->children_link);
+
+    free(self);
+}
+
+void
+weston_desktop_surface_resource_destroy(struct wl_resource *resource)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+    if ( self != NULL )
+        _weston_desktop_surface_destroy(self);
+}
+
+static void
+_weston_desktop_surface_surface_destroyed(struct wl_listener *listener, void *data)
+{
+    struct weston_desktop_surface *self = wl_container_of(listener, self, surface_destroy_listener);
+
+    _weston_desktop_surface_destroy(self);
+}
+
+static void
+_weston_desktop_surface_view_destroyed(struct wl_listener *listener, void *data)
+{
+    struct weston_desktop_surface *self = wl_container_of(listener, self, view_destroy_listener);
+    struct weston_view *view = data;
+
+    weston_view_damage_below(view);
+    _weston_desktop_surface_destroy(self);
+}
+
+static void
+_weston_desktop_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
+{
+    struct weston_desktop_surface *self = surface->configure_private;
+
+    if ( self->parent != NULL )
+    {
+        weston_view_set_transform_parent(self->view, self->parent->view);
+        weston_view_set_position(self->view, self->x, self->y);
+        weston_desktop_surface_update_layer(self->parent);
+    }
+    else
+    {
+        if ( self->implementation->commit != NULL )
+            self->implementation->commit(self, self->implementation_data, sx, sy);
+    }
+}
+
+struct weston_desktop_surface *
+weston_desktop_surface_create(struct weston_desktop *desktop, struct weston_desktop_client *client, struct weston_surface *surface, const struct weston_desktop_surface_implementation *implementation, void *implementation_data)
+{
+    assert(implementation->free != NULL);
+
+    struct weston_desktop_surface *self;
+
+    self = zalloc(sizeof(struct weston_desktop_surface));
+    if ( self == NULL )
+    {
+        if ( client != NULL )
+            wl_client_post_no_memory(weston_desktop_client_get_client(client));
+        return NULL;
+    }
+
+    self->desktop = desktop;
+    self->implementation = implementation;
+    self->implementation_data = implementation_data;
+    self->client = client;
+    self->surface = surface;
+
+    self->view = weston_view_create(self->surface);
+    if ( self->view == NULL )
+    {
+        if ( client != NULL )
+            wl_client_post_no_memory(weston_desktop_client_get_client(client));
+        free(self);
+        return NULL;
+    }
+
+    surface->configure = _weston_desktop_surface_configure;
+    surface->configure_private = self;
+
+    self->surface_destroy_listener.notify = _weston_desktop_surface_surface_destroyed;
+    wl_signal_add(&self->surface->destroy_signal, &self->surface_destroy_listener);
+    self->view_destroy_listener.notify = _weston_desktop_surface_view_destroyed;
+    wl_signal_add(&self->view->destroy_signal, &self->view_destroy_listener);
+
+    wl_list_init(&self->resources);
+    wl_list_init(&self->children_list);
+    wl_list_init(&self->children_link);
+
+    return self;
+}
+
+struct wl_resource *
+weston_desktop_surface_add_resource(struct weston_desktop_surface *self, const struct wl_interface *interface, const void *implementation, uint32_t id, wl_resource_destroy_func_t destroy)
+{
+    assert(self->client != NULL);
+
+    struct wl_resource *client_resource = weston_desktop_client_get_resource(self->client);
+    struct wl_client *wl_client  = weston_desktop_client_get_client(self->client);
+    struct wl_resource *resource;
+
+    resource = wl_resource_create(wl_client, interface, wl_resource_get_version(client_resource), id);
+    if ( resource == NULL )
+    {
+        wl_client_post_no_memory(wl_client);
+        goto error;
+    }
+    wl_resource_set_implementation(resource, implementation, self, ( destroy != NULL ) ? destroy : weston_desktop_surface_resource_destroy);
+    wl_list_insert(&self->resources, wl_resource_get_link(resource));
+
+    return resource;
+
+error:
+    weston_view_destroy(self->view);
+    free(self);
+    return NULL;
+}
+
+struct weston_desktop_surface *
+weston_desktop_surface_from_grab_link(struct wl_list *grab_link)
+{
+    struct weston_desktop_surface *self = wl_container_of(grab_link, self, grab_link);
+
+    return self;
+}
+
+WL_EXPORT
+bool
+weston_surface_is_desktop_surface(struct weston_surface *surface)
+{
+    return ( surface->configure == _weston_desktop_surface_configure );
+}
+
+WL_EXPORT
+struct weston_desktop_surface *
+weston_surface_get_desktop_surface(struct weston_surface *surface)
+{
+    if ( ! weston_surface_is_desktop_surface(surface) )
+        return NULL;
+    return surface->configure_private;
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_user_data(struct weston_desktop_surface *self, void *user_data)
+{
+    self->user_data = user_data;
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_update_layer(struct weston_desktop_surface *self)
+{
+    struct weston_desktop_surface *child;
+    struct wl_list *link = &self->view->layer_link.link;
+    wl_list_for_each_reverse(child, &self->children_list, children_link)
+    {
+        struct weston_layer_entry *prev = wl_container_of(link->prev, prev, link);
+        if ( prev == &child->view->layer_link )
+            continue;
+
+        weston_view_damage_below(child->view);
+        weston_view_geometry_dirty(child->view);
+        weston_layer_entry_remove(&child->view->layer_link);
+        weston_layer_entry_insert(prev, &child->view->layer_link);
+        weston_view_geometry_dirty(child->view);
+        weston_surface_damage(child->surface);
+        weston_view_update_transform(child->view);
+
+        weston_desktop_surface_update_layer(child);
+    }
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_activated(struct weston_desktop_surface *self, bool activated)
+{
+    if ( self->implementation->set_activated != NULL )
+        self->implementation->set_activated(self, self->implementation_data, activated);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_fullscreen(struct weston_desktop_surface *self, bool fullscreen)
+{
+    if ( self->implementation->set_fullscreen != NULL )
+        self->implementation->set_fullscreen(self, self->implementation_data, fullscreen);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_maximized(struct weston_desktop_surface *self, bool maximized)
+{
+    if ( self->implementation->set_maximized != NULL )
+        self->implementation->set_maximized(self, self->implementation_data, maximized);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_resizing(struct weston_desktop_surface *self, bool resizing)
+{
+    if ( self->implementation->set_resizing != NULL )
+        self->implementation->set_resizing(self, self->implementation_data, resizing);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_set_size(struct weston_desktop_surface *self, int32_t width, int32_t height)
+{
+    if ( self->implementation->set_size != NULL )
+        self->implementation->set_size(self, self->implementation_data, width, height);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_ping(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->ping != NULL )
+        self->implementation->ping(self, self->implementation_data);
+}
+
+WL_EXPORT
+void
+weston_desktop_surface_close(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->close != NULL )
+        self->implementation->close(self, self->implementation_data);
+}
+
+struct weston_desktop_client *
+weston_desktop_surface_get_client(struct weston_desktop_surface *self)
+{
+    return self->client;
+}
+
+bool
+weston_desktop_surface_has_implementation(struct weston_desktop_surface *self, const struct weston_desktop_surface_implementation *implementation)
+{
+    return ( self->implementation == implementation );
+}
+
+void *
+weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *self)
+{
+    return self->implementation_data;
+}
+
+struct weston_desktop_surface *
+weston_desktop_surface_get_parent(struct weston_desktop_surface *self)
+{
+    return self->parent;
+}
+
+bool
+weston_desktop_surface_get_grab(struct weston_desktop_surface *self)
+{
+    return ( ! wl_list_empty(&self->grab_link) );
+}
+
+WL_EXPORT
+void *
+weston_desktop_surface_get_user_data(struct weston_desktop_surface *self)
+{
+    return self->user_data;
+}
+
+WL_EXPORT
+struct weston_surface *
+weston_desktop_surface_get_surface(struct weston_desktop_surface *self)
+{
+    return self->surface;
+}
+
+WL_EXPORT
+struct weston_view *
+weston_desktop_surface_get_view(struct weston_desktop_surface *self)
+{
+    return self->view;
+}
+
+WL_EXPORT
+const char *
+weston_desktop_surface_get_title(struct weston_desktop_surface *self)
+{
+    return self->title;
+}
+
+WL_EXPORT
+const char *
+weston_desktop_surface_get_app_id(struct weston_desktop_surface *self)
+{
+    return self->app_id;
+}
+WL_EXPORT
+bool
+weston_desktop_surface_get_activated(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->get_activated != NULL )
+        return self->implementation->get_activated(self, self->implementation_data);
+    return false;
+}
+
+WL_EXPORT
+bool
+weston_desktop_surface_get_resizing(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->get_resizing != NULL )
+        return self->implementation->get_resizing(self, self->implementation_data);
+    return false;
+}
+
+WL_EXPORT
+bool
+weston_desktop_surface_get_maximized(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->get_maximized != NULL )
+        return self->implementation->get_maximized(self, self->implementation_data);
+    return false;
+}
+
+WL_EXPORT
+bool
+weston_desktop_surface_get_fullscreen(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->get_fullscreen != NULL )
+        return self->implementation->get_fullscreen(self, self->implementation_data);
+    return false;
+}
+
+WL_EXPORT
+struct weston_desktop_surface_geometry
+weston_desktop_surface_get_geometry(struct weston_desktop_surface *self)
+{
+    if ( self->implementation->get_geometry != NULL )
+        return self->implementation->get_geometry(self, self->implementation_data);
+    return weston_surface_get_bounding_box(self->surface);
+}
+
+WL_EXPORT
+struct weston_desktop_surface_size
+weston_desktop_surface_get_max_size(struct weston_desktop_surface *self)
+{
+    struct weston_desktop_surface_size size = { 0, 0 };
+    if ( self->implementation->get_max_size != NULL )
+        size = self->implementation->get_max_size(self, self->implementation_data);
+    return size;
+}
+
+WL_EXPORT
+struct weston_desktop_surface_size
+weston_desktop_surface_get_min_size(struct weston_desktop_surface *self)
+{
+    struct weston_desktop_surface_size size = { 0, 0 };
+    if ( self->implementation->get_min_size != NULL )
+        size = self->implementation->get_min_size(self, self->implementation_data);
+    return size;
+}
+
+void
+weston_desktop_surface_set_title(struct weston_desktop_surface *self, const char *title)
+{
+    char *tmp;
+
+    tmp = strdup(title);
+    if ( tmp == NULL )
+        return;
+
+    free(self->title);
+    self->title = tmp;
+}
+
+void
+weston_desktop_surface_set_app_id(struct weston_desktop_surface *self, const char *app_id)
+{
+    char *tmp;
+
+    tmp = strdup(app_id);
+    if ( tmp == NULL )
+        return;
+
+    free(self->app_id);
+    self->app_id = tmp;
+}
+
+void
+weston_desktop_surface_set_parent(struct weston_desktop_surface *self, struct weston_desktop_surface *parent, int32_t x, int32_t y)
+{
+    self->parent = NULL;
+    wl_list_remove(&self->children_link);
+    wl_list_init(&self->children_link);
+
+    if ( parent != NULL )
+    {
+        self->parent = parent;
+        self->x = x;
+        self->y = y;
+        wl_list_insert(&self->parent->children_list, &self->children_link);
+    }
+}
+
+void
+weston_desktop_surface_grab(struct weston_desktop_surface *self, struct weston_desktop_seat *seat, uint32_t serial)
+{
+    if ( weston_desktop_seat_grab_start(seat, weston_desktop_client_get_client(self->client), serial) )
+        weston_desktop_seat_grab_add_surface(seat, &self->grab_link);
+    else
+        weston_desktop_surface_close(self);
+}
+
+void
+weston_desktop_surface_ungrab(struct weston_desktop_surface *self, struct weston_desktop_seat *seat)
+{
+    weston_desktop_seat_grab_remove_surface(seat, &self->grab_link);
+}
diff --git a/libweston-desktop/wl-shell.c b/libweston-desktop/wl-shell.c
new file mode 100644
index 0000000..28e3ab4
--- /dev/null
+++ b/libweston-desktop/wl-shell.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+#define WD_WL_SHELL_PROTOCOL_VERSION 1
+
+enum weston_desktop_wl_shell_surface_state {
+    NONE,
+    TOPLEVEL,
+    MAXIMIZED,
+    FULLSCREEN,
+    TRANSIENT,
+    POPUP,
+};
+
+struct weston_desktop_wl_shell_surface {
+    struct wl_resource *resource;
+    struct weston_desktop *desktop;
+    struct wl_display *display;
+    struct weston_desktop_surface *surface;
+    bool pushed;
+    enum weston_desktop_wl_shell_surface_state state;
+};
+
+static void
+_weston_desktop_wl_shell_surface_set_size(struct weston_desktop_surface *surface, void *user_data, int32_t width, int32_t height)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+    struct weston_surface *wsurface = weston_desktop_surface_get_surface(self->surface);
+
+    if ( ( wsurface->width == width ) && ( wsurface->height == height ) )
+        return;
+
+    wl_shell_surface_send_configure(self->resource, WL_SHELL_SURFACE_RESIZE_NONE, width, height);
+}
+
+static void
+_weston_desktop_wl_shell_surface_commit(struct weston_desktop_surface *surface, void *user_data, int32_t sx, int32_t sy)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+
+    weston_desktop_api_commit(self->desktop, self->surface, sx, sy);
+}
+
+static void
+_weston_desktop_wl_shell_surface_ping(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+    uint32_t serial;
+
+    serial = weston_desktop_client_ping(weston_desktop_surface_get_client(self->surface), self->surface);
+    if ( serial != 0 )
+        wl_shell_surface_send_ping(self->resource, serial);
+}
+
+static void
+_weston_desktop_wl_shell_surface_close(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+
+    if ( self->state == POPUP )
+        wl_shell_surface_send_popup_done(self->resource);
+}
+
+static bool
+_weston_desktop_wl_shell_surface_get_maximized(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+
+    return ( self->state == MAXIMIZED );
+}
+
+static bool
+_weston_desktop_wl_shell_surface_get_fullscreen(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+
+    return ( self->state == FULLSCREEN );
+}
+
+static void
+_weston_desktop_wl_shell_change_state(struct weston_desktop_wl_shell_surface *self, enum weston_desktop_wl_shell_surface_state state, struct weston_desktop_surface *parent, int32_t x, int32_t y)
+{
+    bool to_push = ( state == TOPLEVEL ) || ( state == FULLSCREEN ) || ( state == MAXIMIZED );
+
+    self->state = state;
+    if ( self->pushed == to_push )
+        return;
+
+    self->pushed = to_push;
+    weston_desktop_surface_set_parent(self->surface, parent, x, y);
+    if ( self->pushed )
+        weston_desktop_api_surface_new(self->desktop, self->surface);
+    else
+        weston_desktop_api_surface_free(self->desktop, self->surface);
+}
+
+static void
+_weston_desktop_wl_shell_surface_free(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_wl_shell_surface *self = user_data;
+
+    _weston_desktop_wl_shell_change_state(self, NONE, NULL, 0, 0);
+
+    free(self);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+
+    weston_desktop_client_pong(weston_desktop_surface_get_client(self), serial);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_move(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_move(self->desktop, surface, seat, serial);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, enum wl_shell_surface_resize edges)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_resize(self->desktop, surface, seat, serial, edges);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    _weston_desktop_wl_shell_change_state(self, TOPLEVEL, NULL, 0, 0);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_surface *parent = wl_resource_get_user_data(parent_resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    if ( weston_surface_is_desktop_surface(parent) )
+        _weston_desktop_wl_shell_change_state(self, TRANSIENT, weston_surface_get_desktop_surface(parent), x, y);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client, struct wl_resource *resource, enum wl_shell_surface_fullscreen_method method, uint32_t framerate, struct wl_resource *output_resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    _weston_desktop_wl_shell_change_state(self, FULLSCREEN, NULL, 0, 0);
+    weston_desktop_api_ask_fullscreen(self->desktop, surface, true);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, struct wl_resource *parent_resource, int32_t x, int32_t y, enum wl_shell_surface_transient flags)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_seat *seat = weston_seat_get_desktop_seat(wseat);
+    struct weston_surface *parent = wl_resource_get_user_data(parent_resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    if ( weston_surface_is_desktop_surface(parent) && ( seat != NULL ) )
+    {
+        _weston_desktop_wl_shell_change_state(self, POPUP, weston_surface_get_desktop_surface(parent), x, y);
+        weston_desktop_surface_grab(self->surface, seat, serial);
+    }
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *output_resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_wl_shell_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    _weston_desktop_wl_shell_change_state(self, MAXIMIZED, NULL, 0, 0);
+    weston_desktop_api_ask_maximized(self->desktop, surface, true);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client, struct wl_resource *resource, const char *title)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+
+    weston_desktop_surface_set_title(self, title);
+}
+
+static void
+_weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client, struct wl_resource *resource, const char *class_)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+
+    weston_desktop_surface_set_app_id(self, class_);
+}
+
+
+static const struct wl_shell_surface_interface _weston_desktop_wl_shell_surface_implementation = {
+    .pong           = _weston_desktop_wl_shell_surface_protocol_pong,
+    .move           = _weston_desktop_wl_shell_surface_protocol_move,
+    .resize         = _weston_desktop_wl_shell_surface_protocol_resize,
+    .set_toplevel   = _weston_desktop_wl_shell_surface_protocol_set_toplevel,
+    .set_transient  = _weston_desktop_wl_shell_surface_protocol_set_transient,
+    .set_fullscreen = _weston_desktop_wl_shell_surface_protocol_set_fullscreen,
+    .set_popup      = _weston_desktop_wl_shell_surface_protocol_set_popup,
+    .set_maximized  = _weston_desktop_wl_shell_surface_protocol_set_maximized,
+    .set_title      = _weston_desktop_wl_shell_surface_protocol_set_title,
+    .set_class      = _weston_desktop_wl_shell_surface_protocol_set_class,
+};
+
+static const struct weston_desktop_surface_implementation _weston_desktop_wl_shell_surface_internal_implementation = {
+    .set_size = _weston_desktop_wl_shell_surface_set_size,
+    .commit = _weston_desktop_wl_shell_surface_commit,
+    .ping = _weston_desktop_wl_shell_surface_ping,
+    .close = _weston_desktop_wl_shell_surface_close,
+
+    .get_maximized = _weston_desktop_wl_shell_surface_get_maximized,
+    .get_fullscreen = _weston_desktop_wl_shell_surface_get_fullscreen,
+
+    .free = _weston_desktop_wl_shell_surface_free,
+};
+
+static void
+_weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource)
+{
+    struct weston_desktop_client *client = wl_resource_get_user_data(resource);
+    struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
+    struct weston_desktop_wl_shell_surface *self;
+
+
+    if ( weston_surface_set_role(surface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0 )
+        return;
+
+    self = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
+    if ( self == NULL )
+    {
+        wl_client_post_no_memory(wl_client);
+        return;
+    }
+
+    self->desktop = weston_desktop_client_get_desktop(client);
+    self->display = weston_desktop_get_display(self->desktop);
+
+    self->surface = weston_desktop_surface_create(self->desktop, client, surface, &_weston_desktop_wl_shell_surface_internal_implementation, self);
+    if ( self->surface == NULL )
+    {
+        free(self);
+        return;
+    }
+
+    self->resource = weston_desktop_surface_add_resource(self->surface, &wl_shell_surface_interface, &_weston_desktop_wl_shell_surface_implementation, id, NULL);
+}
+
+
+static const struct wl_shell_interface _weston_desktop_wl_shell_implementation = {
+    .get_shell_surface = _weston_desktop_wl_shell_protocol_get_shell_surface,
+};
+
+static void
+_weston_desktop_wl_shell_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+    struct weston_desktop *desktop = data;
+
+    weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface, &_weston_desktop_wl_shell_implementation, version, id);
+}
+
+struct wl_global *
+weston_desktop_wl_shell_create(struct weston_desktop *desktop, struct wl_display *display)
+{
+    return wl_global_create(display, &wl_shell_interface, WD_WL_SHELL_PROTOCOL_VERSION, desktop, _weston_desktop_wl_shell_bind);
+}
diff --git a/libweston-desktop/xdg-shell-v5.c b/libweston-desktop/xdg-shell-v5.c
new file mode 100644
index 0000000..53e141c
--- /dev/null
+++ b/libweston-desktop/xdg-shell-v5.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#include <stdbool.h>
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+#include "protocol/xdg-shell-unstable-v5-server-protocol.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+#define WD_XDG_SHELL_PROTOCOL_VERSION 1
+
+struct weston_desktop_xdg_surface {
+    struct wl_resource *resource;
+    struct weston_desktop_surface *surface;
+    struct weston_desktop_client *client;
+    struct weston_desktop *desktop;
+    struct wl_event_source *configure_idle;
+    uint32_t configure_serial;
+    struct weston_desktop_surface_size requested_size;
+    struct {
+        bool maximized;
+        bool fullscreen;
+        bool resizing;
+        bool activated;
+    } requested_state, next_state, state;
+    bool has_next_geometry, has_geometry;
+    struct weston_desktop_surface_geometry next_geometry, geometry;
+};
+
+struct weston_desktop_xdg_popup {
+    struct wl_resource *resource;
+    struct weston_desktop_surface *popup;
+    struct weston_desktop *desktop;
+    struct weston_desktop_seat *seat;
+    struct wl_display *display;
+};
+
+static void
+_weston_desktop_xdg_surface_send_configure(void *data)
+{
+    struct weston_desktop_xdg_surface *self = data;
+    uint32_t *s;
+    struct wl_array states;
+
+    self->configure_idle = NULL;
+
+    self->configure_serial = wl_display_next_serial(weston_desktop_get_display(self->desktop));
+
+    wl_array_init(&states);
+    if ( self->requested_state.maximized )
+    {
+        s = wl_array_add(&states, sizeof(uint32_t));
+        *s = XDG_SURFACE_STATE_MAXIMIZED;
+    }
+    if ( self->requested_state.fullscreen )
+    {
+        s = wl_array_add(&states, sizeof(uint32_t));
+        *s = XDG_SURFACE_STATE_FULLSCREEN;
+    }
+    if ( self->requested_state.resizing )
+    {
+        s = wl_array_add(&states, sizeof(uint32_t));
+        *s = XDG_SURFACE_STATE_RESIZING;
+    }
+    if ( self->requested_state.activated )
+    {
+        s = wl_array_add(&states, sizeof(uint32_t));
+        *s = XDG_SURFACE_STATE_ACTIVATED;
+    }
+
+    xdg_surface_send_configure(self->resource, self->requested_size.width, self->requested_size.height, &states, self->configure_serial);
+
+    wl_array_release(&states);
+};
+
+static void
+_weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *self)
+{
+    if ( self->configure_idle != NULL )
+        return;
+    self->configure_idle = wl_event_loop_add_idle(wl_display_get_event_loop(weston_desktop_get_display(self->desktop)), _weston_desktop_xdg_surface_send_configure, self);
+}
+
+static void
+_weston_desktop_xdg_surface_set_maximized(struct weston_desktop_surface *surface, void *user_data, bool maximized)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    if ( self->state.maximized == maximized )
+        return;
+
+    self->requested_state.maximized = maximized;
+    _weston_desktop_xdg_surface_schedule_configure(self);
+}
+
+static void
+_weston_desktop_xdg_surface_set_fullscreen(struct weston_desktop_surface *surface, void *user_data, bool fullscreen)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    if ( self->state.fullscreen == fullscreen )
+        return;
+
+    self->requested_state.fullscreen = fullscreen;
+    _weston_desktop_xdg_surface_schedule_configure(self);
+}
+
+static void
+_weston_desktop_xdg_surface_set_resizing(struct weston_desktop_surface *surface, void *user_data, bool resizing)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    if ( self->state.resizing == resizing )
+        return;
+
+    self->requested_state.resizing = resizing;
+    _weston_desktop_xdg_surface_schedule_configure(self);
+}
+
+static void
+_weston_desktop_xdg_surface_set_activated(struct weston_desktop_surface *surface, void *user_data, bool activated)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    if ( self->state.activated == activated )
+        return;
+
+    self->requested_state.activated = activated;
+    _weston_desktop_xdg_surface_schedule_configure(self);
+}
+
+static void
+_weston_desktop_xdg_surface_set_size(struct weston_desktop_surface *surface, void *user_data, int32_t width, int32_t height)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+    struct weston_surface *wsurface = weston_desktop_surface_get_surface(self->surface);
+
+    if ( ( wsurface->width == width ) && ( wsurface->height == height ) )
+        return;
+
+    self->requested_size.width = width;
+    self->requested_size.height = height;
+    _weston_desktop_xdg_surface_schedule_configure(self);
+}
+
+static void
+_weston_desktop_xdg_surface_commit(struct weston_desktop_surface *surface, void *user_data, int32_t sx, int32_t sy)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+    struct weston_surface *wsurface = weston_desktop_surface_get_surface(self->surface);
+    bool reconfigure = false;
+
+    if ( self->next_state.maximized || self->next_state.fullscreen )
+        reconfigure = ( ( self->requested_size.width != wsurface->width ) || ( self->requested_size.height != wsurface->height ) );
+    if ( reconfigure )
+        _weston_desktop_xdg_surface_schedule_configure(self);
+    else
+    {
+        self->state = self->next_state;
+        if ( self->has_next_geometry )
+        {
+            self->has_geometry = true;
+            self->geometry = self->next_geometry;
+        }
+
+        weston_desktop_api_commit(self->desktop, self->surface, sx, sy);
+    }
+}
+
+static void
+_weston_desktop_xdg_surface_ping(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+    uint32_t serial;
+
+    serial = weston_desktop_client_ping(self->client, self->surface);
+    if ( serial != 0 )
+        xdg_shell_send_ping(weston_desktop_client_get_resource(self->client), serial);
+}
+
+static void
+_weston_desktop_xdg_surface_close(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    xdg_surface_send_close(self->resource);
+}
+
+static bool
+_weston_desktop_xdg_surface_get_maximized(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    return self->state.maximized;
+}
+
+static bool
+_weston_desktop_xdg_surface_get_fullscreen(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    return self->state.fullscreen;
+}
+
+static bool
+_weston_desktop_xdg_surface_get_resizing(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    return self->state.resizing;
+}
+
+static bool
+_weston_desktop_xdg_surface_get_activated(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    return self->state.activated;
+}
+
+static struct weston_desktop_surface_geometry
+_weston_desktop_xdg_surface_get_geometry(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    if ( self->has_geometry )
+        return self->geometry;
+    return weston_surface_get_bounding_box(weston_desktop_surface_get_surface(self->surface));
+}
+
+static void
+_weston_desktop_xdg_surface_free(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_surface *self = user_data;
+
+    weston_desktop_api_surface_free(self->desktop, self->surface);
+
+    if ( self->configure_idle != NULL )
+        wl_event_source_remove(self->configure_idle);
+
+    free(self);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_parent(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *parent_resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+    struct weston_desktop_surface *parent = wl_resource_get_user_data(parent_resource);
+
+    weston_desktop_api_set_parent(self->desktop, surface, parent);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_title(struct wl_client *wl_client, struct wl_resource *resource, const char *title)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+
+    weston_desktop_surface_set_title(self, title);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_app_id(struct wl_client *wl_client, struct wl_resource *resource, const char *app_id)
+{
+    struct weston_desktop_surface *self = wl_resource_get_user_data(resource);
+
+    weston_desktop_surface_set_app_id(self, app_id);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_show_window_menu(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_show_window_menu(self->desktop, surface, seat, x, y);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_move(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_move(self->desktop, surface, seat, serial);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, enum xdg_surface_resize_edge edges)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_resize(self->desktop, surface, seat, serial, edges);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    /* TODO: check if serial is newer or older */
+    if ( self->configure_serial != serial )
+    {
+        _weston_desktop_xdg_surface_schedule_configure(self);
+        return;
+    }
+
+    self->next_state = self->requested_state;
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    self->has_next_geometry = true;
+    self->next_geometry.x = x;
+    self->next_geometry.y = y;
+    self->next_geometry.width = width;
+    self->next_geometry.height = height;
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_maximized(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_ask_maximized(self->desktop, surface, true);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_unset_maximized(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_ask_maximized(self->desktop, surface, false);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_fullscreen(struct wl_client *wl_client, struct wl_resource *resource, struct wl_resource *output_resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_ask_fullscreen(self->desktop, surface, true);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_unset_fullscreen(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_ask_fullscreen(self->desktop, surface, false);
+}
+
+static void
+_weston_desktop_xdg_surface_protocol_set_minimized(struct wl_client *wl_client, struct wl_resource *resource)
+{
+    struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
+    struct weston_desktop_xdg_surface *self = weston_desktop_surface_get_implementation_data(surface);
+
+    weston_desktop_api_ask_minimized(self->desktop, surface);
+}
+
+static const struct xdg_surface_interface _weston_desktop_xdg_surface_implementation = {
+    .destroy             = weston_desktop_destroy_request,
+    .set_parent          = _weston_desktop_xdg_surface_protocol_set_parent,
+    .set_title           = _weston_desktop_xdg_surface_protocol_set_title,
+    .set_app_id          = _weston_desktop_xdg_surface_protocol_set_app_id,
+    .show_window_menu    = _weston_desktop_xdg_surface_protocol_show_window_menu,
+    .move                = _weston_desktop_xdg_surface_protocol_move,
+    .resize              = _weston_desktop_xdg_surface_protocol_resize,
+    .ack_configure       = _weston_desktop_xdg_surface_protocol_ack_configure,
+    .set_window_geometry = _weston_desktop_xdg_surface_protocol_set_window_geometry,
+    .set_maximized       = _weston_desktop_xdg_surface_protocol_set_maximized,
+    .unset_maximized     = _weston_desktop_xdg_surface_protocol_unset_maximized,
+    .set_fullscreen      = _weston_desktop_xdg_surface_protocol_set_fullscreen,
+    .unset_fullscreen    = _weston_desktop_xdg_surface_protocol_unset_fullscreen,
+    .set_minimized       = _weston_desktop_xdg_surface_protocol_set_minimized,
+};
+
+static const struct weston_desktop_surface_implementation _weston_desktop_xdg_surface_internal_implementation = {
+    .set_maximized = _weston_desktop_xdg_surface_set_maximized,
+    .set_fullscreen = _weston_desktop_xdg_surface_set_fullscreen,
+    .set_resizing = _weston_desktop_xdg_surface_set_resizing,
+    .set_activated = _weston_desktop_xdg_surface_set_activated,
+    .set_size = _weston_desktop_xdg_surface_set_size,
+    .commit = _weston_desktop_xdg_surface_commit,
+    .ping = _weston_desktop_xdg_surface_ping,
+    .close = _weston_desktop_xdg_surface_close,
+
+    .get_maximized = _weston_desktop_xdg_surface_get_maximized,
+    .get_fullscreen = _weston_desktop_xdg_surface_get_fullscreen,
+    .get_resizing = _weston_desktop_xdg_surface_get_resizing,
+    .get_activated = _weston_desktop_xdg_surface_get_activated,
+    .get_geometry = _weston_desktop_xdg_surface_get_geometry,
+
+    .free = _weston_desktop_xdg_surface_free,
+};
+
+static void
+_weston_desktop_xdg_popup_close(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_popup *self = user_data;
+
+    xdg_popup_send_popup_done(self->resource);
+}
+
+static void
+_weston_desktop_xdg_popup_free(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct weston_desktop_xdg_popup *self = user_data;
+
+    if ( weston_desktop_surface_get_grab(self->popup) )
+    {
+        struct weston_desktop_surface *topmost;
+        struct wl_resource *resource = weston_desktop_client_get_resource(weston_desktop_surface_get_client(self->popup));
+
+        topmost = weston_desktop_seat_grab_get_topmost_surface(self->seat);
+        if ( topmost != self->popup )
+            wl_resource_post_error(resource, XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was destroyed while it was not the topmost popup.");
+        weston_desktop_surface_ungrab(self->popup, self->seat);
+    }
+
+    free(self);
+}
+
+static const struct xdg_popup_interface _weston_desktop_xdg_popup_implementation = {
+    .destroy             = weston_desktop_destroy_request,
+};
+
+static const struct weston_desktop_surface_implementation _weston_desktop_xdg_popup_internal_implementation = {
+    .close = _weston_desktop_xdg_popup_close,
+
+    .free = _weston_desktop_xdg_popup_free,
+};
+
+static void
+_weston_desktop_xdg_shell_protocol_use_unstable_version(struct wl_client *wl_client, struct wl_resource *resource, int32_t version)
+{
+    if ( version > 1 )
+    {
+        wl_resource_post_error(resource, 1, "xdg_shell version not supported");
+        return;
+    }
+}
+
+static void
+_weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource)
+{
+    struct weston_desktop_client *client = wl_resource_get_user_data(resource);
+    struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
+    struct weston_desktop_xdg_surface *self;
+
+    if ( weston_surface_set_role(surface, "xdg_surface", resource, XDG_SHELL_ERROR_ROLE) < 0 )
+        return;
+
+    self = zalloc(sizeof(struct weston_desktop_xdg_surface));
+    if ( self == NULL )
+    {
+        wl_client_post_no_memory(wl_client);
+        return;
+    }
+
+    self->client = client;
+    self->desktop = weston_desktop_client_get_desktop(self->client);
+
+    self->surface = weston_desktop_surface_create(self->desktop, self->client, surface, &_weston_desktop_xdg_surface_internal_implementation, self);
+    if ( self->surface == NULL )
+    {
+        free(self);
+        return;
+    }
+
+    self->resource = weston_desktop_surface_add_resource(self->surface, &xdg_surface_interface, &_weston_desktop_xdg_surface_implementation, id, NULL);
+    if ( self->resource == NULL )
+        return;
+
+    weston_desktop_api_surface_new(self->desktop, self->surface);
+}
+
+static void
+_weston_desktop_xdg_shell_protocol_get_xdg_popup(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y)
+{
+    struct weston_desktop_client *client = wl_resource_get_user_data(resource);
+    struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
+    struct weston_surface *wparent = wl_resource_get_user_data(parent_resource);
+    struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
+    struct weston_desktop_seat *seat = weston_seat_get_desktop_seat(wseat);
+    struct weston_desktop_surface *parent, *topmost;
+    bool parent_is_popup;
+    struct weston_desktop_xdg_popup *self;
+
+    if ( weston_surface_set_role(surface, "xdg_popup", resource, XDG_SHELL_ERROR_ROLE) < 0 )
+        return;
+
+    if ( ! weston_surface_is_desktop_surface(wparent) )
+    {
+        wl_resource_post_error(resource, XDG_SHELL_ERROR_INVALID_POPUP_PARENT, "xdg_popup parent was invalid");
+        return;
+    }
+
+    parent = weston_surface_get_desktop_surface(wparent);
+    parent_is_popup = weston_desktop_surface_has_implementation(parent, &_weston_desktop_xdg_popup_internal_implementation);
+
+    if ( ( ! weston_desktop_surface_has_implementation(parent, &_weston_desktop_xdg_surface_internal_implementation) ) && ( ! parent_is_popup ) )
+    {
+        wl_resource_post_error(resource, XDG_SHELL_ERROR_INVALID_POPUP_PARENT, "xdg_popup parent was invalid");
+        return;
+    }
+
+    topmost = weston_desktop_seat_grab_get_topmost_surface(seat);
+    if ( ( ( topmost == NULL ) && parent_is_popup ) || ( ( topmost != NULL ) && ( topmost != parent ) ) )
+    {
+        wl_resource_post_error(resource, XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was not created on the topmost popup");
+        return;
+    }
+
+    self = zalloc(sizeof(struct weston_desktop_xdg_popup));
+    if ( self == NULL )
+    {
+        wl_client_post_no_memory(wl_client);
+        return;
+    }
+
+    self->desktop = weston_desktop_client_get_desktop(client);
+    self->display = weston_desktop_get_display(self->desktop);
+    self->seat = seat;
+
+    self->popup = weston_desktop_surface_create(self->desktop, client, surface, &_weston_desktop_xdg_popup_internal_implementation, self);
+    if ( self->popup == NULL )
+    {
+        free(self);
+        return;
+    }
+
+    self->resource = weston_desktop_surface_add_resource(self->popup, &xdg_popup_interface, &_weston_desktop_xdg_popup_implementation, id, NULL);
+    if ( self->resource == NULL )
+        return;
+
+    weston_desktop_surface_set_parent(self->popup, parent, x, y);
+    weston_desktop_surface_grab(self->popup, self->seat, serial);
+}
+
+static void
+_weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial)
+{
+    struct weston_desktop_client *client = wl_resource_get_user_data(resource);
+
+    weston_desktop_client_pong(client, serial);
+}
+
+static const struct xdg_shell_interface _weston_desktop_xdg_shell_implementation = {
+    .destroy = weston_desktop_destroy_request,
+    .use_unstable_version = _weston_desktop_xdg_shell_protocol_use_unstable_version,
+    .get_xdg_surface = _weston_desktop_xdg_shell_protocol_get_xdg_surface,
+    .get_xdg_popup = _weston_desktop_xdg_shell_protocol_get_xdg_popup,
+    .pong = _weston_desktop_xdg_shell_protocol_pong,
+};
+
+
+static int
+xdg_shell_unversioned_dispatch(const void *implementation, void *_target, uint32_t opcode, const struct wl_message *message, union wl_argument *args)
+{
+    struct wl_resource *resource = _target;
+    struct weston_desktop_client *client = wl_resource_get_user_data(resource);
+
+    if ( opcode != 1 /* XDG_SHELL_USE_UNSTABLE_VERSION */ )
+    {
+        wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "must call use_unstable_version first");
+        return 0;
+    }
+
+#define XDG_SERVER_VERSION 5
+
+    if ( args[0].i != XDG_SERVER_VERSION )
+    {
+        wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "incompatible version, server is %d " "client wants %d", XDG_SERVER_VERSION, args[0].i);
+        return 0;
+    }
+
+    wl_resource_set_implementation(resource, &_weston_desktop_xdg_shell_implementation, client, implementation);
+
+    return 1;
+}
+
+static void
+_weston_desktop_xdg_shell_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+    struct weston_desktop *desktop = data;
+
+    weston_desktop_client_create(desktop, client, xdg_shell_unversioned_dispatch, &xdg_shell_interface, NULL, version, id);
+}
+
+struct wl_global *
+weston_desktop_xdg_shell_v5_create(struct weston_desktop *desktop, struct wl_display *display)
+{
+    return wl_global_create(display, &xdg_shell_interface, WD_XDG_SHELL_PROTOCOL_VERSION, desktop, _weston_desktop_xdg_shell_bind);
+}
diff --git a/libweston-desktop/xwayland.c b/libweston-desktop/xwayland.c
new file mode 100644
index 0000000..e7a73d4
--- /dev/null
+++ b/libweston-desktop/xwayland.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright © 2010-2012 Intel Corporation
+ * Copyright © 2011-2012 Collabora, Ltd.
+ * Copyright © 2013 Raspberry Pi Foundation
+ * Copyright © 2016 Quentin "Sardem FF7" Glidic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "zalloc.h"
+
+#include "libweston-desktop.h"
+#include "internal.h"
+
+enum shell_surface_state {
+    TOPLEVEL,
+    MAXIMIZED,
+    FULLSCREEN,
+    TRANSIENT,
+    XWAYLAND,
+};
+
+struct weston_desktop_xwayland {
+    struct weston_desktop *desktop;
+    struct weston_layer layer;
+    struct wl_listener transform_listener;
+};
+
+struct shell_surface {
+    struct weston_desktop_xwayland *xwayland;
+    struct weston_desktop *desktop;
+    struct weston_desktop_surface *surface;
+    const struct weston_shell_client *client;
+    struct weston_desktop_surface_geometry next_geometry;
+    struct weston_desktop_surface_geometry geometry;
+    bool has_geometry;
+    enum shell_surface_state state;
+};
+
+static void
+_weston_desktop_xwayland_surface_commit(struct weston_desktop_surface *surface, void *user_data, int32_t sx, int32_t sy)
+{
+    struct shell_surface *self = user_data;
+
+    if ( self->has_geometry )
+        self->geometry = self->next_geometry;
+
+    weston_desktop_api_commit(self->desktop, self->surface, sx, sy);
+}
+
+static void
+_weston_desktop_xwayland_surface_set_size(struct weston_desktop_surface *surface, void *user_data, int32_t width, int32_t height)
+{
+    struct shell_surface *self = user_data;
+
+    self->client->send_configure(weston_desktop_surface_get_surface(self->surface), width, height);
+}
+
+static void
+_weston_desktop_xwayland_surface_free(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct shell_surface *self = user_data;
+
+    if ( ( self->state == TOPLEVEL ) || ( self->state == MAXIMIZED ) || ( self->state == FULLSCREEN ) )
+        weston_desktop_api_surface_free(self->desktop, self->surface);
+
+    free(self);
+}
+
+static bool
+_weston_desktop_xwayland_surface_get_maximized(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct shell_surface *self = user_data;
+
+    return ( self->state == MAXIMIZED );
+}
+
+static bool
+_weston_desktop_xwayland_surface_get_fullscreen(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct shell_surface *self = user_data;
+
+    return ( self->state == FULLSCREEN );
+}
+
+static struct weston_desktop_surface_geometry
+_weston_desktop_xwayland_surface_get_geometry(struct weston_desktop_surface *surface, void *user_data)
+{
+    struct shell_surface *self = user_data;
+
+    if ( self->has_geometry )
+        return self->geometry;
+    return weston_surface_get_bounding_box(weston_desktop_surface_get_surface(self->surface));
+}
+
+static const struct weston_desktop_surface_implementation _weston_desktop_xwayland_surface_internal_implementation = {
+    .commit = _weston_desktop_xwayland_surface_commit,
+    .set_size = _weston_desktop_xwayland_surface_set_size,
+
+    .get_maximized = _weston_desktop_xwayland_surface_get_maximized,
+    .get_fullscreen = _weston_desktop_xwayland_surface_get_fullscreen,
+    .get_geometry = _weston_desktop_xwayland_surface_get_geometry,
+
+    .free = _weston_desktop_xwayland_surface_free,
+};
+static struct shell_surface *
+create_shell_surface(void *shell, struct weston_surface *surface, const struct weston_shell_client *client)
+{
+    struct weston_desktop_xwayland *xwayland = shell;
+    struct shell_surface *self;
+
+    self = zalloc(sizeof(struct shell_surface));
+    if ( self == NULL )
+        return NULL;
+
+    self->xwayland = xwayland;
+    self->desktop = xwayland->desktop;
+    self->client = client;
+
+    self->surface = weston_desktop_surface_create(self->desktop, NULL, surface, &_weston_desktop_xwayland_surface_internal_implementation, self);
+    if ( self->surface == NULL )
+    {
+        free(self);
+        return NULL;
+    }
+
+    return self;
+}
+
+static void
+set_toplevel(struct shell_surface *self)
+{
+    weston_desktop_api_surface_new(self->desktop, self->surface);
+}
+
+
+static void
+set_transient(struct shell_surface *self, struct weston_surface *parent, int x, int y, uint32_t flags)
+{
+    if ( ! weston_surface_is_desktop_surface(parent) )
+        return;
+    self->state = TRANSIENT;
+    weston_desktop_surface_set_parent(self->surface, weston_surface_get_desktop_surface(parent), x, y);
+}
+
+static void
+set_fullscreen(struct shell_surface *self, uint32_t method, uint32_t framerate, struct weston_output *output)
+{
+    self->state = FULLSCREEN;
+    weston_desktop_api_surface_new(self->desktop, self->surface);
+}
+
+static void
+set_xwayland(struct shell_surface *self, int x, int y, uint32_t flags)
+{
+    struct weston_view *view = weston_desktop_surface_get_view(self->surface);
+
+    self->state = XWAYLAND;
+    weston_layer_entry_insert(&self->xwayland->layer.view_list, &view->layer_link);
+    weston_view_set_position(view, x, y);
+}
+
+static int
+move(struct shell_surface *self, struct weston_pointer *pointer)
+{
+    weston_desktop_api_move(self->desktop, self->surface, pointer->seat, pointer->grab_serial);
+    return 0;
+}
+
+static int
+resize(struct shell_surface *self, struct weston_pointer *pointer, uint32_t edges)
+{
+    weston_desktop_api_resize(self->desktop, self->surface, pointer->seat, pointer->grab_serial, edges);
+    return 0;
+}
+
+static void
+set_title(struct shell_surface *self, const char *title)
+{
+    weston_desktop_surface_set_title(self->surface, title);
+}
+
+static void
+set_window_geometry(struct shell_surface *self, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+    self->has_geometry = true;
+    self->next_geometry.x = x;
+    self->next_geometry.y = y;
+    self->next_geometry.width = width;
+    self->next_geometry.height = height;
+}
+
+static void
+set_maximized(struct shell_surface *self)
+{
+    self->state = MAXIMIZED;
+    weston_desktop_api_surface_new(self->desktop, self->surface);
+}
+
+static void
+set_pid(struct shell_surface *self, pid_t pid)
+{
+}
+
+static void
+transform_handler(struct wl_listener *listener, void *data)
+{
+    struct weston_surface *surface = data;
+    struct weston_desktop_surface *desktop_surface = weston_surface_get_desktop_surface(surface);
+    struct shell_surface *self;
+    struct weston_view *view;
+    int x, y;
+
+    if (!desktop_surface)
+        return;
+
+    if (!weston_desktop_surface_has_implementation(desktop_surface, &_weston_desktop_xwayland_surface_internal_implementation))
+        return;
+
+    self = weston_desktop_surface_get_implementation_data(desktop_surface);
+    view = weston_desktop_surface_get_view(desktop_surface);
+    if (!weston_view_is_mapped(view))
+            return;
+
+    x = view->geometry.x;
+    y = view->geometry.y;
+
+    self->client->send_position(surface, x, y);
+}
+
+
+void
+weston_desktop_xwayland_init(struct weston_desktop *desktop)
+{
+    struct weston_compositor *compositor = weston_desktop_get_compositor(desktop);
+    struct weston_desktop_xwayland *self;
+
+    self = zalloc(sizeof(struct weston_desktop_xwayland));
+    if ( self == NULL )
+        return;
+
+    self->desktop = desktop;
+
+    weston_layer_init(&self->layer, &compositor->cursor_layer.link);
+
+    self->transform_listener.notify = transform_handler;
+    wl_signal_add(&compositor->transform_signal, &self->transform_listener);
+
+    compositor->shell_interface.shell = self;
+    compositor->shell_interface.create_shell_surface = create_shell_surface;
+    compositor->shell_interface.set_toplevel = set_toplevel;
+    compositor->shell_interface.set_transient = set_transient;
+    compositor->shell_interface.set_fullscreen = set_fullscreen;
+    compositor->shell_interface.set_xwayland = set_xwayland;
+    compositor->shell_interface.move = move;
+    compositor->shell_interface.resize = resize;
+    compositor->shell_interface.set_title = set_title;
+    compositor->shell_interface.set_window_geometry = set_window_geometry;
+    compositor->shell_interface.set_maximized = set_maximized;
+    compositor->shell_interface.set_pid = set_pid;
+}
-- 
2.9.0



More information about the wayland-devel mailing list