From 203ea178d01fbeae4fa34684116915b456f464bf Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Wed, 16 Jan 2019 01:16:58 -0700 Subject: [PATCH] wayland: Port to xdg-shell stable Wayland compositors and clients are expected to support the xdg-shell stable protocol over the deprecated wl_shell protocol. --- CMakeLists.txt | 18 +++++++- base/vulkanexamplebase.cpp | 89 +++++++++++++++++++++++++++++--------- base/vulkanexamplebase.h | 10 +++-- examples/CMakeLists.txt | 4 ++ 4 files changed, 97 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c9f9a14..c13eedff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,28 @@ IF(USE_D2D_WSI) MESSAGE("Using direct to display extension...") add_definitions(-D_DIRECT2DISPLAY) ELSEIF(USE_WAYLAND_WSI) + find_program(PKG_CONFIG pkg-config) + if (NOT PKG_CONFIG) + message(FATAL_ERROR "pkg-config binary not found") + endif () find_package(Wayland REQUIRED) if (NOT WAYLAND_FOUND) message(FATAL_ERROR "Wayland development package not found") endif () + pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols) + if (NOT WAYLAND_PROTOCOLS_FOUND) + message(FATAL_ERROR "Wayland protocols package not found") + endif () + find_program(WAYLAND_SCANNER wayland-scanner) + if (NOT WAYLAND_SCANNER) + message(FATAL_ERROR "wayland-scanner binary not found") + endif () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WAYLAND_KHR") include_directories(${WAYLAND_INCLUDE_DIR}) + execute_process(COMMAND ${PKG_CONFIG} --variable=pkgdatadir wayland-protocols OUTPUT_VARIABLE protocol_dir OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${WAYLAND_SCANNER} client-header ${protocol_dir}/stable/xdg-shell/xdg-shell.xml xdg-shell-client-protocol.h + COMMAND ${WAYLAND_SCANNER} private-code ${protocol_dir}/stable/xdg-shell/xdg-shell.xml xdg-shell-protocol.c) + include_directories(${CMAKE_BINARY_DIR}) ELSE(USE_D2D_WSI) find_package(XCB REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR") @@ -78,7 +94,7 @@ endif() add_definitions(-D_CRT_SECURE_NO_WARNINGS) -add_definitions(-std=c++11) +set(CXXFLAGS -std=c++11) file(GLOB SOURCE *.cpp ) diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index 6fbc6103..d509f1c9 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -456,6 +456,8 @@ void VulkanExampleBase::renderLoop() viewChanged(); } + while (!configured) + wl_display_dispatch(display); while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); wl_display_flush(display); @@ -487,7 +489,7 @@ void VulkanExampleBase::renderLoop() if (!settings.overlay) { std::string windowTitle = getWindowTitle(); - wl_shell_surface_set_title(shell_surface, windowTitle.c_str()); + xdg_toplevel_set_title(xdg_toplevel, windowTitle.c_str()); } lastFPS = (float)frameCounter * (1000.0f / fpsTimer); fpsTimer = 0.0f; @@ -800,14 +802,15 @@ VulkanExampleBase::~VulkanExampleBase() #if defined(_DIRECT2DISPLAY) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) - wl_shell_surface_destroy(shell_surface); + xdg_toplevel_destroy(xdg_toplevel); + xdg_surface_destroy(xdg_surface); wl_surface_destroy(surface); if (keyboard) wl_keyboard_destroy(keyboard); if (pointer) wl_pointer_destroy(pointer); wl_seat_destroy(seat); - wl_shell_destroy(shell); + xdg_wm_base_destroy(shell); wl_compositor_destroy(compositor); wl_registry_destroy(registry); wl_display_disconnect(display); @@ -1631,6 +1634,15 @@ void VulkanExampleBase::seatCapabilities(wl_seat *seat, uint32_t caps) } } +static void xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) +{ + xdg_wm_base_pong(shell, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + xdg_wm_base_ping, +}; + void VulkanExampleBase::registryGlobal(wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { @@ -1639,10 +1651,11 @@ void VulkanExampleBase::registryGlobal(wl_registry *registry, uint32_t name, compositor = (wl_compositor *) wl_registry_bind(registry, name, &wl_compositor_interface, 3); } - else if (strcmp(interface, "wl_shell") == 0) + else if (strcmp(interface, "xdg_wm_base") == 0) { - shell = (wl_shell *) wl_registry_bind(registry, name, - &wl_shell_interface, 1); + shell = (xdg_wm_base *) wl_registry_bind(registry, name, + &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(shell, &xdg_wm_base_listener, nullptr); } else if (strcmp(interface, "wl_seat") == 0) { @@ -1691,34 +1704,70 @@ void VulkanExampleBase::initWaylandConnection() } } -static void PingCb(void *data, struct wl_shell_surface *shell_surface, - uint32_t serial) +void VulkanExampleBase::setSize(int width, int height) { - wl_shell_surface_pong(shell_surface, serial); + if (width <= 0 || height <= 0) + return; + + destWidth = width; + destHeight = height; + + windowResize(); } -static void ConfigureCb(void *data, struct wl_shell_surface *shell_surface, - uint32_t edges, int32_t width, int32_t height) +static void +xdg_surface_handle_configure(void *data, struct xdg_surface *surface, + uint32_t serial) { + VulkanExampleBase *base = (VulkanExampleBase *) data; + + xdg_surface_ack_configure(surface, serial); + base->configured = true; } -static void PopupDoneCb(void *data, struct wl_shell_surface *shell_surface) +static const struct xdg_surface_listener xdg_surface_listener = { + xdg_surface_handle_configure, +}; + + +static void +xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, + int32_t width, int32_t height, + struct wl_array *states) { + VulkanExampleBase *base = (VulkanExampleBase *) data; + + base->setSize(width, height); } -wl_shell_surface *VulkanExampleBase::setupWindow() +static void +xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) +{ + VulkanExampleBase *base = (VulkanExampleBase *) data; + + base->quit = true; +} + + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + xdg_toplevel_handle_configure, + xdg_toplevel_handle_close, +}; + + +struct xdg_surface *VulkanExampleBase::setupWindow() { surface = wl_compositor_create_surface(compositor); - shell_surface = wl_shell_get_shell_surface(shell, surface); + xdg_surface = xdg_wm_base_get_xdg_surface(shell, surface); - static const struct wl_shell_surface_listener shell_surface_listener = - { PingCb, ConfigureCb, PopupDoneCb }; + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, this); + xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, this); - wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, this); - wl_shell_surface_set_toplevel(shell_surface); std::string windowTitle = getWindowTitle(); - wl_shell_surface_set_title(shell_surface, windowTitle.c_str()); - return shell_surface; + xdg_toplevel_set_title(xdg_toplevel, windowTitle.c_str()); + wl_surface_commit(surface); + return xdg_surface; } #elif defined(VK_USE_PLATFORM_XCB_KHR) diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index cc4f42ba..90cc73b3 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -22,6 +22,7 @@ #include "VulkanAndroid.h" #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #include +#include "xdg-shell-client-protocol.h" #elif defined(_DIRECT2DISPLAY) // #elif defined(VK_USE_PLATFORM_XCB_KHR) @@ -227,13 +228,15 @@ public: wl_display *display = nullptr; wl_registry *registry = nullptr; wl_compositor *compositor = nullptr; - wl_shell *shell = nullptr; + struct xdg_wm_base *shell = nullptr; wl_seat *seat = nullptr; wl_pointer *pointer = nullptr; wl_keyboard *keyboard = nullptr; wl_surface *surface = nullptr; - wl_shell_surface *shell_surface = nullptr; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; bool quit = false; + bool configured = false; #elif defined(_DIRECT2DISPLAY) bool quit = false; @@ -265,8 +268,9 @@ public: #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) void* setupWindow(void* view); #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) - wl_shell_surface *setupWindow(); + struct xdg_surface *setupWindow(); void initWaylandConnection(); + void setSize(int width, int height); static void registryGlobalCb(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); void registryGlobal(struct wl_registry *registry, uint32_t name, diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 97f7e42e..77119f5c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -13,6 +13,10 @@ function(buildExample EXAMPLE_NAME) file(GLOB ADD_SOURCE "../external/imgui/*.cpp") SET(SOURCE ${SOURCE} ${ADD_SOURCE}) ENDIF() + # wayland requires additional source files + IF(USE_WAYLAND_WSI) + SET(SOURCE ${SOURCE} ${CMAKE_BINARY_DIR}/xdg-shell-client-protocol.h ${CMAKE_BINARY_DIR}/xdg-shell-protocol.c) + ENDIF() # Add shaders set(SHADER_DIR "../data/shaders/${EXAMPLE_NAME}") file(GLOB SHADERS "${SHADER_DIR}/*.vert" "${SHADER_DIR}/*.frag" "${SHADER_DIR}/*.comp" "${SHADER_DIR}/*.geom" "${SHADER_DIR}/*.tesc" "${SHADER_DIR}/*.tese")