cube: Port Wayland impl from wl-shell to xdg-shell
authorManuel Stoeckl <code@mstoeckl.com>
Thu, 27 Jun 2019 00:55:53 +0000 (20:55 -0400)
committerTony-LunarG <tony@lunarg.com>
Mon, 25 Nov 2019 21:25:34 +0000 (14:25 -0700)
This change ports vkcube in both C and C++ versions to use the stable
xdg-shell protocol for Wayland compositors. The original wl-shell
protocol has been deprecated and is being removed from major compositor
libraries; wlroots has already dropped support.

New cmake modules have been added to look for Wayland-Protocols
(containing XML descriptions of all common protocols) and
`wayland-scanner`, the tool used to convert the XML files to a usable C
interface.

The change also adds support for the xdg-decoration protocol, which for
some compositors is provided and needed to let them know that they
should draw a titlebar, borders with resize controls, and other standard
features.

Change-Id: I39bedda93a7c5d0aeeb59c68023552723b413567

cmake/FindWaylandProtocols.cmake [new file with mode: 0644]
cmake/FindWaylandScanner.cmake [new file with mode: 0644]
cube/CMakeLists.txt
cube/cube.c
cube/cube.cpp

diff --git a/cmake/FindWaylandProtocols.cmake b/cmake/FindWaylandProtocols.cmake
new file mode 100644 (file)
index 0000000..17859ed
--- /dev/null
@@ -0,0 +1,13 @@
+# Wayland protocols Defines:
+#
+# * WAYLAND_PROTOCOLS_FOUND    True if the wayland-protocols data path is found
+# * WAYLAND_PROTOCOLS_PATH     Path to the wayland-scanner executable
+#
+
+if(NOT WIN32)
+    find_package(PkgConfig)
+    pkg_check_modules(PKG_WAYLAND_PROTOCOLS QUIET wayland-protocols)
+    set(WAYLAND_PROTOCOLS_PATH ${PKG_WAYLAND_PROTOCOLS_PREFIX}/share/wayland-protocols)
+    find_package_handle_standard_args(WAYLAND DEFAULT_MSG WAYLAND_PROTOCOLS_PATH)
+    mark_as_advanced(WAYLAND_PROTOCOLS_PATH)
+endif()
diff --git a/cmake/FindWaylandScanner.cmake b/cmake/FindWaylandScanner.cmake
new file mode 100644 (file)
index 0000000..cd93d90
--- /dev/null
@@ -0,0 +1,14 @@
+# Wayland scanner Defines:
+#
+# * WAYLAND_SCANNER_FOUND         True if wayland-scanner is found
+# * WAYLAND_SCANNER_EXECUTABLE    Path to the wayland-scanner executable
+#
+
+if(NOT WIN32)
+    # Delegate to pkg-config for our first guess
+    find_package(PkgConfig)
+    pkg_check_modules(PKG_WAYLAND_SCANNER QUIET wayland-scanner)
+    find_program(WAYLAND_SCANNER_EXECUTABLE wayland-scanner ${PKG_WAYLAND_SCANNER_PREFIX}/bin/wayland-scanner)
+    find_package_handle_standard_args(WAYLAND DEFAULT_MSG WAYLAND_SCANNER_EXECUTABLE)
+    mark_as_advanced(WAYLAND_SCANNER_EXECUTABLE)
+endif()
index 451303f..4fc0034 100644 (file)
@@ -58,6 +58,8 @@ if(UNIX AND NOT APPLE) # i.e. Linux
 
     if(BUILD_WSI_WAYLAND_SUPPORT)
         find_package(Wayland REQUIRED)
+        find_package(WaylandScanner REQUIRED)
+        find_package(WaylandProtocols REQUIRED)
         include_directories(${WAYLAND_CLIENT_INCLUDE_DIR})
     endif()
 endif()
@@ -101,6 +103,50 @@ elseif(UNIX AND NOT APPLE) # i.e. Linux
         set(CUBE_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIR} ${CUBE_INCLUDE_DIRS})
         link_libraries(${WAYLAND_CLIENT_LIBRARIES})
         add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR)
+
+        set(XDG_SHELL_PROTOCOL ${WAYLAND_PROTOCOLS_PATH}/stable/xdg-shell/xdg-shell.xml)
+        add_custom_command(COMMENT "Generating xdg-shell protocol dispatch data"
+                           OUTPUT xdg-shell-code.c
+                           COMMAND ${WAYLAND_SCANNER_EXECUTABLE}
+                                   private-code
+                                   ${XDG_SHELL_PROTOCOL}
+                                   ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-code.c
+                           MAIN_DEPENDENCY ${XDG_SHELL_PROTOCOL}
+                           DEPENDS ${XDG_SHELL_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE})
+        add_custom_command(COMMENT "Generating xdg-shell protocol header"
+                           OUTPUT xdg-shell-client-header.h
+                           COMMAND ${WAYLAND_SCANNER_EXECUTABLE}
+                                   client-header
+                                   ${XDG_SHELL_PROTOCOL}
+                                   ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-header.h
+                           MAIN_DEPENDENCY ${XDG_SHELL_PROTOCOL}
+                           DEPENDS ${XDG_SHELL_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE})
+
+        set(XDG_DECORATION_PROTOCOL ${WAYLAND_PROTOCOLS_PATH}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml)
+        add_custom_command(COMMENT "Generating xdg-decoration protocol dispatch data"
+                           OUTPUT xdg-decoration-code.c
+                           COMMAND ${WAYLAND_SCANNER_EXECUTABLE}
+                                   private-code
+                                   ${XDG_DECORATION_PROTOCOL}
+                                   ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-code.c
+                           MAIN_DEPENDENCY ${XDG_DECORATION_PROTOCOL}
+                           DEPENDS ${XDG_DECORATION_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE})
+        add_custom_command(COMMENT "Generating xdg-decoration protocol header"
+                           OUTPUT xdg-decoration-client-header.h
+                           COMMAND ${WAYLAND_SCANNER_EXECUTABLE}
+                                   client-header
+                                   ${XDG_DECORATION_PROTOCOL}
+                                   ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h
+                           MAIN_DEPENDENCY ${XDG_DECORATION_PROTOCOL}
+                           DEPENDS ${XDG_DECORATION_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE})
+
+        set(OPTIONAL_WAYLAND_DATA_FILES
+            ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-code.c
+            ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-header.h
+            ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-code.c
+            ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h)
+        include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
     elseif(CUBE_WSI_SELECTION STREQUAL "DISPLAY")
         add_definitions(-DVK_USE_PLATFORM_DISPLAY_KHR)
     else()
@@ -172,7 +218,8 @@ elseif(NOT WIN32)
                        ${PROJECT_SOURCE_DIR}/cube/cube.vert
                        ${PROJECT_SOURCE_DIR}/cube/cube.frag
                        cube.vert.inc
-                       cube.frag.inc)
+                       cube.frag.inc
+                       ${OPTIONAL_WAYLAND_DATA_FILES})
         target_link_libraries(vkcube Vulkan::Vulkan)
         CHECK_LIBRARY_EXISTS("rt" clock_gettime "" NEED_RT)
         if (NEED_RT)
@@ -221,7 +268,8 @@ elseif(NOT WIN32)
                        ${PROJECT_SOURCE_DIR}/cube/cube.vert
                        ${PROJECT_SOURCE_DIR}/cube/cube.frag
                        cube.vert.inc
-                       cube.frag.inc)
+                       cube.frag.inc
+                       ${OPTIONAL_WAYLAND_DATA_FILES})
         target_link_libraries(vkcubepp Vulkan::Vulkan)
     endif()
 else()
index 09a243a..5382cd0 100644 (file)
@@ -37,6 +37,8 @@
 #include <X11/Xutil.h>
 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 #include <linux/input.h>
+#include "xdg-shell-client-header.h"
+#include "xdg-decoration-client-header.h"
 #endif
 
 #ifdef _WIN32
@@ -321,8 +323,12 @@ struct demo {
     struct wl_registry *registry;
     struct wl_compositor *compositor;
     struct wl_surface *window;
-    struct wl_shell *shell;
-    struct wl_shell_surface *shell_surface;
+    struct xdg_wm_base *xdg_wm_base;
+    struct zxdg_decoration_manager_v1 *xdg_decoration_mgr;
+    struct zxdg_toplevel_decoration_v1 *toplevel_decoration;
+    struct xdg_surface *xdg_surface;
+    int xdg_surface_has_been_configured;
+    struct xdg_toplevel *xdg_toplevel;
     struct wl_seat *seat;
     struct wl_pointer *pointer;
     struct wl_keyboard *keyboard;
@@ -2359,9 +2365,14 @@ static void demo_cleanup(struct demo *demo) {
     wl_keyboard_destroy(demo->keyboard);
     wl_pointer_destroy(demo->pointer);
     wl_seat_destroy(demo->seat);
-    wl_shell_surface_destroy(demo->shell_surface);
+    xdg_toplevel_destroy(demo->xdg_toplevel);
+    xdg_surface_destroy(demo->xdg_surface);
     wl_surface_destroy(demo->window);
-    wl_shell_destroy(demo->shell);
+    xdg_wm_base_destroy(demo->xdg_wm_base);
+    if (demo->xdg_decoration_mgr) {
+        zxdg_toplevel_decoration_v1_destroy(demo->toplevel_decoration);
+        zxdg_decoration_manager_v1_destroy(demo->xdg_decoration_mgr);
+    }
     wl_compositor_destroy(demo->compositor);
     wl_registry_destroy(demo->registry);
     wl_display_disconnect(demo->display);
@@ -2737,18 +2748,39 @@ static void demo_run(struct demo *demo) {
     }
 }
 
-static void handle_ping(void *data UNUSED, struct wl_shell_surface *shell_surface, uint32_t serial) {
-    wl_shell_surface_pong(shell_surface, serial);
+static void handle_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
+    struct demo *demo = (struct demo *)data;
+    xdg_surface_ack_configure(xdg_surface, serial);
+    if (demo->xdg_surface_has_been_configured) {
+        demo_resize(demo);
+    }
+    demo->xdg_surface_has_been_configured = 1;
 }
 
-static void handle_configure(void *data UNUSED, struct wl_shell_surface *shell_surface UNUSED, uint32_t edges UNUSED,
-                             int32_t width UNUSED, int32_t height UNUSED) {}
+static const struct xdg_surface_listener xdg_surface_listener = {handle_surface_configure};
 
-static void handle_popup_done(void *data UNUSED, struct wl_shell_surface *shell_surface UNUSED) {}
+static void handle_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel UNUSED, int32_t width, int32_t height,
+                                      struct wl_array *states UNUSED) {
+    struct demo *demo = (struct demo *)data;
+    demo->width = width;
+    demo->height = height;
+    /* This should be followed by a surface configure */
+}
 
-static const struct wl_shell_surface_listener shell_surface_listener = {handle_ping, handle_configure, handle_popup_done};
+static void handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel UNUSED) {
+    struct demo *demo = (struct demo *)data;
+    demo->quit = true;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {handle_toplevel_configure, handle_toplevel_close};
 
 static void demo_create_window(struct demo *demo) {
+    if (!demo->xdg_wm_base) {
+        printf("Compositor did not provide the standard protocol xdg-wm-base\n");
+        fflush(stdout);
+        exit(1);
+    }
+
     demo->window = wl_compositor_create_surface(demo->compositor);
     if (!demo->window) {
         printf("Can not create wayland_surface from compositor!\n");
@@ -2756,15 +2788,29 @@ static void demo_create_window(struct demo *demo) {
         exit(1);
     }
 
-    demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window);
-    if (!demo->shell_surface) {
-        printf("Can not get shell_surface from wayland_surface!\n");
+    demo->xdg_surface = xdg_wm_base_get_xdg_surface(demo->xdg_wm_base, demo->window);
+    if (!demo->xdg_surface) {
+        printf("Can not get xdg_surface from wayland_surface!\n");
         fflush(stdout);
         exit(1);
     }
-    wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener, demo);
-    wl_shell_surface_set_toplevel(demo->shell_surface);
-    wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
+    demo->xdg_toplevel = xdg_surface_get_toplevel(demo->xdg_surface);
+    if (!demo->xdg_toplevel) {
+        printf("Can not allocate xdg_toplevel for xdg_surface!\n");
+        fflush(stdout);
+        exit(1);
+    }
+    xdg_surface_add_listener(demo->xdg_surface, &xdg_surface_listener, demo);
+    xdg_toplevel_add_listener(demo->xdg_toplevel, &xdg_toplevel_listener, demo);
+    xdg_toplevel_set_title(demo->xdg_toplevel, APP_SHORT_NAME);
+    if (demo->xdg_decoration_mgr) {
+        // if supported, let the compositor render titlebars for us
+        demo->toplevel_decoration =
+            zxdg_decoration_manager_v1_get_toplevel_decoration(demo->xdg_decoration_mgr, demo->xdg_toplevel);
+        zxdg_toplevel_decoration_v1_set_mode(demo->toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+    }
+
+    wl_surface_commit(demo->window);
 }
 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 static void demo_run(struct demo *demo) {
@@ -3568,7 +3614,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
                                   uint32_t state) {
     struct demo *demo = data;
     if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
-        wl_shell_surface_move(demo->shell_surface, demo->seat, serial);
+        xdg_toplevel_move(demo->xdg_toplevel, demo->seat, serial);
     }
 }
 
@@ -3636,21 +3682,31 @@ static const struct wl_seat_listener seat_listener = {
     seat_handle_capabilities,
 };
 
-static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) {
+static void wm_base_ping(void *data UNUSED, struct xdg_wm_base *xdg_wm_base, uint32_t serial) {
+    xdg_wm_base_pong(xdg_wm_base, serial);
+}
+
+static const struct xdg_wm_base_listener wm_base_listener = {wm_base_ping};
+
+static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface,
+                                   uint32_t version UNUSED) {
     struct demo *demo = data;
     // pickup wayland objects when they appear
-    if (strcmp(interface, "wl_compositor") == 0) {
+    if (strcmp(interface, wl_compositor_interface.name) == 0) {
         uint32_t minVersion = version < 4 ? version : 4;
         demo->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, minVersion);
         if (demo->VK_KHR_incremental_present_enabled && minVersion < 4) {
             fprintf(stderr, "Wayland compositor doesn't support VK_KHR_incremental_present, disabling.\n");
             demo->VK_KHR_incremental_present_enabled = false;
         }
-    } else if (strcmp(interface, "wl_shell") == 0) {
-        demo->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
-    } else if (strcmp(interface, "wl_seat") == 0) {
+    } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
+        demo->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
+        xdg_wm_base_add_listener(demo->xdg_wm_base, &wm_base_listener, NULL);
+    } else if (strcmp(interface, wl_seat_interface.name) == 0) {
         demo->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
         wl_seat_add_listener(demo->seat, &seat_listener, demo);
+    } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
+        demo->xdg_decoration_mgr = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
     }
 }
 
index 87b24f9..abe80a8 100644 (file)
@@ -22,6 +22,8 @@
 #include <X11/Xutil.h>
 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 #include <linux/input.h>
+#include "xdg-shell-client-header.h"
+#include "xdg-decoration-client-header.h"
 #endif
 
 #include <cassert>
@@ -289,8 +291,12 @@ struct Demo {
     wl_registry *registry;
     wl_compositor *compositor;
     wl_surface *window;
-    wl_shell *shell;
-    wl_shell_surface *shell_surface;
+    xdg_wm_base *wm_base;
+    zxdg_decoration_manager_v1 *xdg_decoration_mgr;
+    zxdg_toplevel_decoration_v1 *toplevel_decoration;
+    xdg_surface *window_surface;
+    bool xdg_surface_has_been_configured;
+    xdg_toplevel *window_toplevel;
     wl_seat *seat;
     wl_pointer *pointer;
     wl_keyboard *keyboard;
@@ -418,7 +424,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
                                   uint32_t state) {
     Demo *demo = (Demo *)data;
     if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
-        wl_shell_surface_move(demo->shell_surface, demo->seat, serial);
+        xdg_toplevel_move(demo->window_toplevel, demo->seat, serial);
     }
 }
 
@@ -486,16 +492,24 @@ static const wl_seat_listener seat_listener = {
     seat_handle_capabilities,
 };
 
+static void wm_base_ping(void *data, xdg_wm_base *xdg_wm_base, uint32_t serial) { xdg_wm_base_pong(xdg_wm_base, serial); }
+
+static const struct xdg_wm_base_listener wm_base_listener = {wm_base_ping};
+
 static void registry_handle_global(void *data, wl_registry *registry, uint32_t id, const char *interface, uint32_t version) {
     Demo *demo = (Demo *)data;
     // pickup wayland objects when they appear
-    if (strcmp(interface, "wl_compositor") == 0) {
+    if (strcmp(interface, wl_compositor_interface.name) == 0) {
         demo->compositor = (wl_compositor *)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
-    } else if (strcmp(interface, "wl_shell") == 0) {
-        demo->shell = (wl_shell *)wl_registry_bind(registry, id, &wl_shell_interface, 1);
-    } else if (strcmp(interface, "wl_seat") == 0) {
+    } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
+        demo->wm_base = (xdg_wm_base *)wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
+        xdg_wm_base_add_listener(demo->wm_base, &wm_base_listener, nullptr);
+    } else if (strcmp(interface, wl_seat_interface.name) == 0) {
         demo->seat = (wl_seat *)wl_registry_bind(registry, id, &wl_seat_interface, 1);
         wl_seat_add_listener(demo->seat, &seat_listener, demo);
+    } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
+        demo->xdg_decoration_mgr =
+            (zxdg_decoration_manager_v1 *)wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
     }
 }
 
@@ -525,8 +539,12 @@ Demo::Demo()
       registry{nullptr},
       compositor{nullptr},
       window{nullptr},
-      shell{nullptr},
-      shell_surface{nullptr},
+      wm_base{nullptr},
+      xdg_decoration_mgr{nullptr},
+      toplevel_decoration{nullptr},
+      window_surface{nullptr},
+      xdg_surface_has_been_configured{false},
+      window_toplevel{nullptr},
       seat{nullptr},
       pointer{nullptr},
       keyboard{nullptr},
@@ -669,9 +687,14 @@ void Demo::cleanup() {
     wl_keyboard_destroy(keyboard);
     wl_pointer_destroy(pointer);
     wl_seat_destroy(seat);
-    wl_shell_surface_destroy(shell_surface);
+    xdg_toplevel_destroy(window_toplevel);
+    xdg_surface_destroy(window_surface);
     wl_surface_destroy(window);
-    wl_shell_destroy(shell);
+    xdg_wm_base_destroy(wm_base);
+    if (xdg_decoration_mgr) {
+        zxdg_toplevel_decoration_v1_destroy(toplevel_decoration);
+        zxdg_decoration_manager_v1_destroy(xdg_decoration_mgr);
+    }
     wl_compositor_destroy(compositor);
     wl_registry_destroy(registry);
     wl_display_disconnect(display);
@@ -2690,7 +2713,39 @@ void Demo::run() {
     }
 }
 
+static void handle_surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial) {
+    Demo *demo = (Demo *)data;
+    xdg_surface_ack_configure(xdg_surface, serial);
+    if (demo->xdg_surface_has_been_configured) {
+        demo->resize();
+    }
+    demo->xdg_surface_has_been_configured = true;
+}
+
+static const xdg_surface_listener surface_listener = {handle_surface_configure};
+
+static void handle_toplevel_configure(void *data, xdg_toplevel *xdg_toplevel, int32_t width, int32_t height,
+                                      struct wl_array *states) {
+    Demo *demo = (Demo *)data;
+    demo->width = width;
+    demo->height = height;
+    // This will be followed by a surface configure
+}
+
+static void handle_toplevel_close(void *data, xdg_toplevel *xdg_toplevel) {
+    Demo *demo = (Demo *)data;
+    demo->quit = true;
+}
+
+static const xdg_toplevel_listener toplevel_listener = {handle_toplevel_configure, handle_toplevel_close};
+
 void Demo::create_window() {
+    if (!wm_base) {
+        printf("Compositor did not provide the standard protocol xdg-wm-base\n");
+        fflush(stdout);
+        exit(1);
+    }
+
     window = wl_compositor_create_surface(compositor);
     if (!window) {
         printf("Can not create wayland_surface from compositor!\n");
@@ -2698,16 +2753,28 @@ void Demo::create_window() {
         exit(1);
     }
 
-    shell_surface = wl_shell_get_shell_surface(shell, window);
-    if (!shell_surface) {
-        printf("Can not get shell_surface from wayland_surface!\n");
+    window_surface = xdg_wm_base_get_xdg_surface(wm_base, window);
+    if (!window_surface) {
+        printf("Can not get xdg_surface from wayland_surface!\n");
         fflush(stdout);
         exit(1);
     }
+    window_toplevel = xdg_surface_get_toplevel(window_surface);
+    if (!window_toplevel) {
+        printf("Can not allocate xdg_toplevel for xdg_surface!\n");
+        fflush(stdout);
+        exit(1);
+    }
+    xdg_surface_add_listener(window_surface, &surface_listener, this);
+    xdg_toplevel_add_listener(window_toplevel, &toplevel_listener, this);
+    xdg_toplevel_set_title(window_toplevel, APP_SHORT_NAME);
+    if (xdg_decoration_mgr) {
+        // if supported, let the compositor render titlebars for us
+        toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(xdg_decoration_mgr, window_toplevel);
+        zxdg_toplevel_decoration_v1_set_mode(toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+    }
 
-    wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, this);
-    wl_shell_surface_set_toplevel(shell_surface);
-    wl_shell_surface_set_title(shell_surface, APP_SHORT_NAME);
+    wl_surface_commit(window);
 }
 #elif defined(VK_USE_PLATFORM_MACOS_MVK)
 void Demo::run() {