diff --git a/.gitignore b/.gitignore index f1b615f48c..27325e00c9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ __pycache__/ *.rdbg ._* .DS_Store +external/wayland-protocols/ diff --git a/framework/application/wayland_context.cpp b/framework/application/wayland_context.cpp index ac4ebb761c..591ab8839c 100644 --- a/framework/application/wayland_context.cpp +++ b/framework/application/wayland_context.cpp @@ -37,6 +37,7 @@ struct wl_keyboard_listener WaylandContext::keyboard_listener_; struct wl_seat_listener WaylandContext::seat_listener_; struct wl_registry_listener WaylandContext::registry_listener_; struct wl_output_listener WaylandContext::output_listener_; +struct xdg_wm_base_listener WaylandContext::xdg_wm_base_listener_; WaylandContext::WaylandContext(Application* application) : WsiContext(application) { @@ -65,6 +66,8 @@ WaylandContext::WaylandContext(Application* application) : WsiContext(applicatio output_listener_.done = HandleOutputDone; output_listener_.scale = HandleOutputScale; + xdg_wm_base_listener_.ping = HandleXdgWmBasePing; + success = wayland_loader_.Initialize(); auto& wl = wayland_loader_.GetFunctionTable(); @@ -99,7 +102,7 @@ WaylandContext::WaylandContext(Application* application) : WsiContext(applicatio GFXRECON_LOG_ERROR("Failed to bind Wayland compositor"); success = false; } - else if (shell_ == nullptr) + else if (shell_ == nullptr && xdg_wm_base_ == nullptr) { GFXRECON_LOG_ERROR("Failed to bind Wayland shell"); success = false; @@ -135,6 +138,11 @@ WaylandContext::~WaylandContext() wl.shell_destroy(shell_); } + if (xdg_wm_base_) + { + wl.xdg->xdg_wm_base_destroy(xdg_wm_base_); + } + if (compositor_) { wl.compositor_destroy(compositor_); @@ -199,22 +207,28 @@ void WaylandContext::HandleRegistryGlobal( { auto wayland_context = reinterpret_cast(data); auto& wl = wayland_context->GetWaylandFunctionTable(); - if (util::platform::StringCompare(interface, "wl_compositor") == 0) + if (util::platform::StringCompare(interface, wl.compositor_interface->name) == 0) { // wl_compositor needs to support wl_surface::set_buffer_scale request wayland_context->compositor_ = reinterpret_cast( wl.registry_bind(registry, id, wl.compositor_interface, WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)); } - else if (util::platform::StringCompare(interface, "wl_shell") == 0) + else if (util::platform::StringCompare(interface, wl.shell_interface->name) == 0) { wayland_context->shell_ = reinterpret_cast(wl.registry_bind(registry, id, wl.shell_interface, 1)); } - else if (util::platform::StringCompare(interface, "wl_seat") == 0) + else if (util::platform::StringCompare(interface, wl.xdg->xdg_wm_base_interface.name) == 0) + { + wayland_context->xdg_wm_base_ = + reinterpret_cast(wl.registry_bind(registry, id, &wl.xdg->xdg_wm_base_interface, 1)); + wl.xdg->xdg_wm_base_add_listener(wayland_context->xdg_wm_base_, &xdg_wm_base_listener_, wayland_context); + } + else if (util::platform::StringCompare(interface, wl.seat_interface->name) == 0) { wayland_context->seat_ = reinterpret_cast(wl.registry_bind(registry, id, wl.seat_interface, 1)); wl.seat_add_listener(wayland_context->seat_, &seat_listener_, wayland_context); } - else if (util::platform::StringCompare(interface, "wl_output") == 0) + else if (util::platform::StringCompare(interface, wl.output_interface->name) == 0) { // wl_output needs to support wl_output::scale event auto output = reinterpret_cast( @@ -398,5 +412,11 @@ void WaylandContext::HandleOutputScale(void* data, struct wl_output* wl_output, output_info.scale = factor; } +void WaylandContext::HandleXdgWmBasePing(void* data, struct xdg_wm_base* xdg_wm_base, uint32_t serial) +{ + auto& wl = reinterpret_cast(data)->GetWaylandFunctionTable(); + wl.xdg->xdg_wm_base_pong(xdg_wm_base, serial); +} + GFXRECON_END_NAMESPACE(application) GFXRECON_END_NAMESPACE(gfxrecon) diff --git a/framework/application/wayland_context.h b/framework/application/wayland_context.h index 9fefd3b18d..92d8a15ecc 100644 --- a/framework/application/wayland_context.h +++ b/framework/application/wayland_context.h @@ -59,6 +59,8 @@ class WaylandContext : public WsiContext struct wl_shell* GetShell() const { return shell_; } + struct xdg_wm_base* GetXdgWmBase() const { return xdg_wm_base_; } + struct wl_compositor* GetCompositor() const { return compositor_; } const OutputInfo& GetOutputInfo(const struct wl_output* wl_output) { return output_info_map_[wl_output]; } @@ -129,6 +131,8 @@ class WaylandContext : public WsiContext static void HandleOutputDone(void* data, struct wl_output* wl_output); static void HandleOutputScale(void* data, struct wl_output* wl_output, int32_t factor); + static void HandleXdgWmBasePing(void* data, struct xdg_wm_base* xdg_wm_base, uint32_t serial); + typedef std::unordered_map WaylandWindowMap; typedef std::unordered_map OutputInfoMap; @@ -137,8 +141,10 @@ class WaylandContext : public WsiContext static struct wl_seat_listener seat_listener_; static struct wl_registry_listener registry_listener_; static struct wl_output_listener output_listener_; + static struct xdg_wm_base_listener xdg_wm_base_listener_; struct wl_display* display_{}; struct wl_shell* shell_{}; + struct xdg_wm_base* xdg_wm_base_{}; struct wl_compositor* compositor_{}; struct wl_registry* registry_{}; struct wl_seat* seat_{}; diff --git a/framework/application/wayland_window.cpp b/framework/application/wayland_window.cpp index 55d7d7d216..a6366cd206 100644 --- a/framework/application/wayland_window.cpp +++ b/framework/application/wayland_window.cpp @@ -33,10 +33,12 @@ GFXRECON_BEGIN_NAMESPACE(application) struct wl_surface_listener WaylandWindow::surface_listener_; struct wl_shell_surface_listener WaylandWindow::shell_surface_listener_; +struct xdg_surface_listener WaylandWindow::xdg_surface_listener_; +struct xdg_toplevel_listener WaylandWindow::xdg_toplevel_listener_; WaylandWindow::WaylandWindow(WaylandContext* wayland_context) : - wayland_context_(wayland_context), surface_(nullptr), shell_surface_(nullptr), width_(0), height_(0), scale_(1), - output_(nullptr) + wayland_context_(wayland_context), surface_(nullptr), shell_surface_(nullptr), xdg_surface_(nullptr), + xdg_toplevel_(nullptr), width_(0), height_(0), scale_(1), output_(nullptr), xdg_surface_configured_(false) { assert(wayland_context_ != nullptr); @@ -44,17 +46,28 @@ WaylandWindow::WaylandWindow(WaylandContext* wayland_context) : surface_listener_.enter = HandleSurfaceEnter; surface_listener_.leave = HandleSurfaceLeave; - shell_surface_listener_.ping = HandlePing; - shell_surface_listener_.configure = HandleConfigure; - shell_surface_listener_.popup_done = HandlePopupDone; + shell_surface_listener_.ping = HandleShellSurfacePing; + shell_surface_listener_.configure = HandleShellSurfaceConfigure; + shell_surface_listener_.popup_done = HandleShellSurfacePopupDone; + + xdg_surface_listener_.configure = HandleXdgSurfaceConfigure; + + xdg_toplevel_listener_.configure = HandleXdgToplevelConfigure; + xdg_toplevel_listener_.close = HandleXdgToplevelClose; } WaylandWindow::~WaylandWindow() { - auto& wl = wayland_context_->GetWaylandFunctionTable(); - if (surface_) + if (surface_ != nullptr) { - if (shell_surface_) + auto& wl = wayland_context_->GetWaylandFunctionTable(); + + if (xdg_toplevel_ != nullptr) + { + wl.xdg->xdg_toplevel_destroy(xdg_toplevel_); + wl.xdg->xdg_surface_destroy(xdg_surface_); + } + else if (shell_surface_ != nullptr) { wl.shell_surface_destroy(shell_surface_); } @@ -78,18 +91,59 @@ bool WaylandWindow::Create( return false; } - shell_surface_ = wl.shell_get_shell_surface(wayland_context_->GetShell(), surface_); - if (!shell_surface_) + // If we have the choice between xdg_toplevel and wl_shell_surface, chose the xdg_toplevel + + if (wayland_context_->GetXdgWmBase() != nullptr) { - GFXRECON_LOG_ERROR("Failed to create Wayland shell surface"); - return false; + xdg_surface_ = wl.xdg->xdg_wm_base_get_xdg_surface(wayland_context_->GetXdgWmBase(), surface_); + if (xdg_surface_ != nullptr) + { + wl.xdg->xdg_surface_add_listener(xdg_surface_, &WaylandWindow::xdg_surface_listener_, this); + xdg_toplevel_ = wl.xdg->xdg_surface_get_toplevel(xdg_surface_); + } + } + + if (xdg_toplevel_ == nullptr && wayland_context_->GetShell() != nullptr) + { + shell_surface_ = wl.shell_get_shell_surface(wayland_context_->GetShell(), surface_); } + // Check what was created, setup listener for it, and clean up if nothing was successfuly created + wayland_context_->RegisterWaylandWindow(this); + if (xdg_toplevel_ != nullptr) + { + wl.xdg->xdg_toplevel_add_listener(xdg_toplevel_, &WaylandWindow::xdg_toplevel_listener_, this); + } + else if (shell_surface_ != nullptr) + { + wl.shell_surface_add_listener(shell_surface_, &WaylandWindow::shell_surface_listener_, this); + } + else + { + if (xdg_surface_ != nullptr) + { + wl.xdg->xdg_surface_destroy(xdg_surface_); + xdg_surface_ = nullptr; + } + + GFXRECON_LOG_ERROR("Failed to create Wayland shell surface"); + return false; + } + wl.surface_add_listener(surface_, &WaylandWindow::surface_listener_, this); - wl.shell_surface_add_listener(shell_surface_, &WaylandWindow::shell_surface_listener_, this); - wl.shell_surface_set_title(shell_surface_, title.c_str()); + + SetTitle(title); + + if (xdg_toplevel_ != nullptr) + { + wl.surface_commit(surface_); + while (!xdg_surface_configured_) + { + wl.display_dispatch(wayland_context_->GetDisplay()); + } + } width_ = width; height_ = height; @@ -100,18 +154,30 @@ bool WaylandWindow::Create( bool WaylandWindow::Destroy() { - if (surface_) + if (surface_ != nullptr) { + wayland_context_->UnregisterWaylandWindow(this); + auto& wl = wayland_context_->GetWaylandFunctionTable(); - if (shell_surface_) + + if (xdg_toplevel_ != nullptr) + { + wl.xdg->xdg_toplevel_destroy(xdg_toplevel_); + xdg_toplevel_ = nullptr; + wl.xdg->xdg_surface_destroy(xdg_surface_); + xdg_surface_ = nullptr; + + xdg_surface_configured_ = false; + } + else if (shell_surface_ != nullptr) { wl.shell_surface_destroy(shell_surface_); shell_surface_ = nullptr; } wl.surface_destroy(surface_); - wayland_context_->UnregisterWaylandWindow(this); surface_ = nullptr; + return true; } @@ -121,7 +187,14 @@ bool WaylandWindow::Destroy() void WaylandWindow::SetTitle(const std::string& title) { auto& wl = wayland_context_->GetWaylandFunctionTable(); - wl.shell_surface_set_title(shell_surface_, title.c_str()); + if (xdg_toplevel_ != nullptr) + { + wl.xdg->xdg_toplevel_set_title(xdg_toplevel_, title.c_str()); + } + else if (shell_surface_ != nullptr) + { + wl.shell_surface_set_title(shell_surface_, title.c_str()); + } } void WaylandWindow::SetPosition(const int32_t x, const int32_t y) @@ -215,14 +288,21 @@ void WaylandWindow::UpdateWindowSize() if (output_info.width == width_ && output_info.height == height_) { - wl.shell_surface_set_fullscreen(shell_surface_, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output_); + if (xdg_toplevel_ != nullptr) + { + wl.xdg->xdg_toplevel_set_fullscreen(xdg_toplevel_, output_); + } + else if (shell_surface_ != nullptr) + { + wl.shell_surface_set_fullscreen(shell_surface_, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output_); + } } - else + else if (shell_surface_ != nullptr) { wl.shell_surface_set_toplevel(shell_surface_); } } - else + else if (shell_surface_ != nullptr) { wl.shell_surface_set_toplevel(shell_surface_); } @@ -238,17 +318,33 @@ void WaylandWindow::HandleSurfaceEnter(void* data, struct wl_surface* surface, s void WaylandWindow::HandleSurfaceLeave(void* data, struct wl_surface* surface, struct wl_output* output) {} -void WaylandWindow::HandlePing(void* data, wl_shell_surface* shell_surface, uint32_t serial) +void WaylandWindow::HandleShellSurfacePing(void* data, wl_shell_surface* shell_surface, uint32_t serial) { auto& wl = reinterpret_cast(data)->wayland_context_->GetWaylandFunctionTable(); wl.shell_surface_pong(shell_surface, serial); } -void WaylandWindow::HandleConfigure( +void WaylandWindow::HandleShellSurfaceConfigure( void* data, wl_shell_surface* shell_surface, uint32_t edges, int32_t width, int32_t height) {} -void WaylandWindow::HandlePopupDone(void* data, wl_shell_surface* shell_surface) {} +void WaylandWindow::HandleShellSurfacePopupDone(void* data, wl_shell_surface* shell_surface) {} + +void WaylandWindow::HandleXdgSurfaceConfigure(void* data, struct xdg_surface* xdg_surface, uint32_t serial) +{ + WaylandWindow* window = reinterpret_cast(data); + + auto& wl = window->wayland_context_->GetWaylandFunctionTable(); + + wl.xdg->xdg_surface_ack_configure(xdg_surface, serial); + window->xdg_surface_configured_ = true; +} + +void WaylandWindow::HandleXdgToplevelConfigure( + void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height, struct wl_array* states) +{} + +void WaylandWindow::HandleXdgToplevelClose(void* data, struct xdg_toplevel* xdg_toplevel) {} WaylandWindowFactory::WaylandWindowFactory(WaylandContext* wayland_context) : wayland_context_(wayland_context) { diff --git a/framework/application/wayland_window.h b/framework/application/wayland_window.h index a4966557d2..e1ee53a96e 100644 --- a/framework/application/wayland_window.h +++ b/framework/application/wayland_window.h @@ -44,6 +44,8 @@ class WaylandWindow : public decode::Window struct wl_shell_surface* GetShellSurface() const { return shell_surface_; } + struct xdg_toplevel* GetXdgToplevel() const { return xdg_toplevel_; } + virtual bool Create(const std::string& title, const int32_t x, const int32_t y, @@ -80,25 +82,34 @@ class WaylandWindow : public decode::Window static void HandleSurfaceEnter(void* data, struct wl_surface* surface, struct wl_output* output); static void HandleSurfaceLeave(void* data, struct wl_surface* surface, struct wl_output* output); - static void HandlePing(void* data, wl_shell_surface* shell_surface, uint32_t serial); + static void HandleShellSurfacePing(void* data, wl_shell_surface* shell_surface, uint32_t serial); + static void HandleShellSurfaceConfigure( + void* data, wl_shell_surface* shell_surface, uint32_t edges, int32_t width, int32_t height); + static void HandleShellSurfacePopupDone(void* data, wl_shell_surface* shell_surface); - static void - HandleConfigure(void* data, wl_shell_surface* shell_surface, uint32_t edges, int32_t width, int32_t height); + static void HandleXdgSurfaceConfigure(void* data, struct xdg_surface* xdg_surface, uint32_t serial); - static void HandlePopupDone(void* data, wl_shell_surface* shell_surface); + static void HandleXdgToplevelConfigure( + void* data, struct xdg_toplevel* xdg_toplevel, int32_t width, int32_t height, struct wl_array* states); + static void HandleXdgToplevelClose(void* data, struct xdg_toplevel* xdg_toplevel); void UpdateWindowSize(); private: static struct wl_surface_listener surface_listener_; static struct wl_shell_surface_listener shell_surface_listener_; + static struct xdg_surface_listener xdg_surface_listener_; + static struct xdg_toplevel_listener xdg_toplevel_listener_; WaylandContext* wayland_context_; struct wl_surface* surface_; struct wl_shell_surface* shell_surface_; + struct xdg_surface* xdg_surface_; + struct xdg_toplevel* xdg_toplevel_; uint32_t width_; uint32_t height_; int32_t scale_; struct wl_output* output_; + bool xdg_surface_configured_; }; class WaylandWindowFactory : public decode::WindowFactory @@ -124,4 +135,4 @@ class WaylandWindowFactory : public decode::WindowFactory GFXRECON_END_NAMESPACE(util) GFXRECON_END_NAMESPACE(gfxrecon) -#endif // GFXRECON_APPLICATION_WAYLAND_WINDOW_H \ No newline at end of file +#endif // GFXRECON_APPLICATION_WAYLAND_WINDOW_H diff --git a/framework/generated/generate_wayland.py b/framework/generated/generate_wayland.py new file mode 100644 index 0000000000..2a78977eec --- /dev/null +++ b/framework/generated/generate_wayland.py @@ -0,0 +1,414 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024 LunarG, Inc. +# Copyright (c) 2024 Arm Limited and/or its affiliates +# +# 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 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. + + +from io import TextIOWrapper +import itertools +import os +import subprocess +import xml.etree.ElementTree as ET + + +SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) +PROTOCOLS_DIR = os.path.normpath( + os.path.join(SCRIPT_DIR, '..', '..', 'external', 'wayland-protocols') +) + + +COPYRIGHT = '''/* +** Copyright (c) 2024 LunarG, Inc. +** Copyright (c) 2024 Arm Limited and/or its affiliates +** +** 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 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. +*/ +''' + + +def wayland_arg_to_cpp_type(arg: ET.Element) -> str: + + arg_type = arg.attrib['type'] + + if arg_type == 'int' or arg_type == 'enum' or arg_type == 'fd': + return 'int32_t' + elif arg_type == 'uint': + return 'uint32_t' + elif arg_type == 'fixed': + return 'wl_fixed' + elif arg_type == 'object' or arg_type == 'new_id': + return arg.attrib['interface'] + '*' + elif arg_type == 'string': + return 'const char*' + elif arg_type == 'array': + return 'wl_array*' + else: + raise Exception(f'Unknown arg type: "{arg_type}"') + + +def generate_request(file: TextIOWrapper, interface_name: str, request: ET.Element, opcode: int) -> None: + + return_type = 'void' + args = list() + + for arg in request.findall('arg'): + if arg.attrib['type'] == 'new_id': + if return_type != 'void': + raise Exception('Two objects created by the same request: Case not handled.') + return_type = wayland_arg_to_cpp_type(arg) + else: + args.append((wayland_arg_to_cpp_type(arg), arg.attrib['name'])) + + func_name = interface_name + '_' + request.attrib["name"] + + file.write(f'\t\t{return_type} {func_name}({interface_name}* self{", ".join([""] + [arg[0] + " " + arg[1] for arg in args])}) const\n') + file.write('\t\t{\n') + + if return_type != 'void': + + params = [ + 'reinterpret_cast(self)', + str(opcode), + f'&{return_type[:-1]}_interface', + 'NULL' + ] + + params.extend(arg[1] for arg in args) + + file.write(f'\t\t\treturn reinterpret_cast<{return_type}>(_wl->proxy_marshal_constructor({", ".join(params)}));\n') + + else: + + params = [ + 'reinterpret_cast(self)', + str(opcode) + ] + + params.extend(arg[1] for arg in args) + + file.write(f'\t\t\t_wl->proxy_marshal({", ".join(params)});\n') + + if request.attrib["name"] == 'destroy': + file.write('\t\t\t_wl->proxy_destroy(reinterpret_cast(self));\n') + + + file.write('\t\t}\n') + file.write('\n') + + +def get_message_interface_name(interface: str) -> str: + if interface[:3] == 'wl_': + return f'_wl->{interface[3:]}_interface' + else: + return f'&{interface}_interface' + + +def message_from_func(message_args: list, func: ET.Element) -> list: + + message = [func.attrib['name'], '', 0] + + if 'since' in func.attrib: + message[1] += func.attrib['since'] + + current_args = list() + for arg in func.findall('arg'): + + arg_type = arg.attrib['type'] + + if arg_type == 'int': + message[1] += 'i' + current_args.append('nullptr') + elif arg_type == 'uint': + message[1] += 'u' + current_args.append('nullptr') + elif arg_type == 'fixed': + message[1] += 'f' + current_args.append('nullptr') + elif arg_type == 'object': + message[1] += 'o' + current_args.append(get_message_interface_name(arg.attrib["interface"])) + elif arg_type == 'new_id': + message[1] += 'n' + current_args.append(get_message_interface_name(arg.attrib["interface"])) + elif arg_type == 'string': + message[1] += 's' + current_args.append('nullptr') + elif arg_type == 'array': + message[1] += 'a' + current_args.append('nullptr') + elif arg_type == 'fd': + message[1] += 'h' + current_args.append('nullptr') + elif arg_type == 'enum': + message[1] += 'i' + current_args.append('nullptr') + else: + raise Exception(f'Unknown arg type: "{arg_type}"') + + if 'allow-null' in arg.attrib and arg.attrib['allow-null'] == 'true': + message[1] += '?' + + if len(current_args) == 0: + return message + + for m in range(len(message_args) - len(current_args)): + + found = True + for c, c_arg in enumerate(current_args): + if message_args[m + c] != c_arg: + found = False + break + + if found: + message[2] = m + return message + + + for i in range(len(message_args) - len(current_args), len(message_args)): + if message_args[i:] == current_args[:len(message_args) - i]: + message_args.extend(current_args[len(message_args) - i:]) + message[2] = i + return message + + message[2] = len(message_args) + message_args.extend(current_args) + + return message + + +def generate(protocol_path: str) -> None: + + print(f'Generating protocol sources for "{protocol_path}"') + + tree = ET.parse(protocol_path) + root = tree.getroot() + + protocol_name = root.attrib['name'] + generated_filename = os.path.join(SCRIPT_DIR, f'generated_wayland_{protocol_name}.h') + + with open(generated_filename, 'w') as file: + + # Header of file + + file.write(COPYRIGHT) + file.write('\n') + file.write(f'#ifndef GFXRECON_GENERATED_WAYLAND_{protocol_name.upper()}_H\n') + file.write(f'#define GFXRECON_GENERATED_WAYLAND_{protocol_name.upper()}_H\n') + file.write('\n') + file.write('#include \n') + file.write('\n') + file.write('#include \n') + file.write('\n') + file.write('#include "util/defines.h"\n') + file.write('#include "util/wayland_loader.h"\n') + file.write('\n') + + # Static declarations + + for interface in root.findall('interface'): + file.write(f'struct {interface.attrib["name"]};\n') + + file.write('\n') + + for interface in root.findall('interface'): + + interface_name = interface.attrib['name'] + + file.write(f'// {interface_name} static declarations\n') + file.write('\n') + + # Enums + + for enum in interface.findall('enum'): + file.write(f'enum {interface_name}_{enum.attrib["name"]}\n') + file.write('{\n') + for entry in enum.findall('entry'): + file.write(f'\t{interface_name}_{enum.attrib["name"]}_{entry.attrib["name"]} = {entry.attrib["value"]},\n'.upper()) + file.write('};\n') + file.write('\n') + + # Listeners + + if interface.find('event') is not None: + + file.write(f'struct {interface_name}_listener\n') + file.write('{\n') + + for event in interface.findall('event'): + file.write(f'\tvoid (*{event.attrib["name"]})(void* data, {interface_name}* object') + + for arg in event.findall('arg'): + file.write(f', {wayland_arg_to_cpp_type(arg)} {arg.attrib["name"]}') + + file.write(');\n') + + file.write('};\n') + file.write('\n') + + # Protocol table + + file.write('GFXRECON_BEGIN_NAMESPACE(gfxrecon)\n') + file.write('GFXRECON_BEGIN_NAMESPACE(util)\n') + file.write('\n') + file.write(f'// Global to {protocol_name}\n') + file.write('\n') + file.write(f'class wayland_{protocol_name}_table\n') + file.write('{\n') + file.write('\tprivate:\n') + file.write('\n') + file.write('\t\tconst WaylandLoader::FunctionTable* _wl;\n') + file.write('\t\tstd::vector _messages;\n') + file.write('\t\tstd::vector _messageArgs;\n') + file.write('\n') + file.write('\tpublic:\n') + file.write('\n') + + # Per-interface dynamic declarations + + for interface in root.findall('interface'): + + interface_name = interface.attrib['name'] + + file.write(f'\t\t// {interface_name} dynamic declarations\n') + file.write('\n') + + # Interfaces + + file.write(f'\t\twl_interface {interface.attrib["name"]}_interface;\n') + file.write('\n') + + # Listeners + + if interface.find('event') is not None: + + file.write(f'\t\tint {interface_name}_add_listener({interface_name}* self, {interface_name}_listener* listener, void* data) const\n') + file.write('\t\t{\n') + file.write('\t\t\treturn _wl->proxy_add_listener(reinterpret_cast(self), reinterpret_cast(listener), data);\n') + file.write('\t\t}\n') + file.write('\n') + + # Requests + + destroy_found = False + for opcode, request in enumerate(interface.findall('request')): + generate_request(file, interface_name, request, opcode) + if request.attrib['name'] == 'destroy': + destroy_found = True + + if not destroy_found: + file.write(f'\t\tvoid {interface_name}_destroy({interface_name}* self) const\n') + file.write('\t\t{\n') + file.write('\t\t\t_wl->proxy_destroy(reinterpret_cast(self));\n') + file.write('\t\t}\n') + file.write('\n') + + # Initialize func + + file.write('\t\t// Call this once libwayland-client is successfully loaded\n') + file.write('\n') + file.write('\t\tvoid initialize(const WaylandLoader* waylandLoader)\n') + file.write('\t\t{\n') + + file.write('\t\t\t_wl = &waylandLoader->GetFunctionTable();\n') + file.write('\n') + + messages = dict() + message_args = list() + for interface in root.findall('interface'): + interface_name = interface.attrib['name'] + messages[interface_name] = [list(), list()] + for request in interface.findall('request'): + messages[interface_name][0].append(message_from_func(message_args, request)) + for event in interface.findall('event'): + messages[interface_name][1].append(message_from_func(message_args, event)) + + file.write('\t\t\t_messageArgs = {\n') + for arg in message_args: + file.write(f'\t\t\t\t{arg},\n') + file.write('\t\t\t};\n') + file.write('\n') + + file.write('\t\t\t_messages = {\n') + for interface in root.findall('interface'): + for message in itertools.chain(messages[interface.attrib['name']][0], messages[interface.attrib['name']][1]): + file.write(f'\t\t\t\t{{ "{message[0]}", "{message[1]}", _messageArgs.data() + {message[2]} }},\n') + + file.write('\t\t\t};\n') + file.write('\n') + + counter = 0 + for interface in root.findall('interface'): + + interface_name = interface.attrib["name"] + request_count = len(messages[interface_name][0]) + event_count = len(messages[interface_name][1]) + + file.write(f'\t\t\t{interface_name}_interface = {{ "{interface_name}", {interface.attrib["version"]},') + file.write(f' {request_count}, _messages.data() + {counter},') + counter += request_count + file.write(f' {event_count}, _messages.data() + {counter} }};\n') + counter += event_count + + file.write('\t\t}\n') + file.write('};\n') + file.write('\n') + + # Footer of file + + file.write('GFXRECON_END_NAMESPACE(util)\n') + file.write('GFXRECON_END_NAMESPACE(gfxrecon)\n') + file.write('\n') + file.write(f'#endif // GFXRECON_GENERATED_WAYLAND_{protocol_name.upper()}_H\n') + + +def clone_wayland_protocols(): + + print('Cloning/Pulling wayland-protocols git repository...') + + if os.path.exists(PROTOCOLS_DIR): + subprocess.run(['git', 'pull'], cwd=PROTOCOLS_DIR) + else: + subprocess.run(['git', 'clone', 'https://gitlab.freedesktop.org/wayland/wayland-protocols.git', PROTOCOLS_DIR]) + + +def main(): + clone_wayland_protocols() + generate(os.path.join(PROTOCOLS_DIR, 'stable', 'xdg-shell', 'xdg-shell.xml')) + + +if __name__ == '__main__': + main() diff --git a/framework/generated/generated_wayland_xdg_shell.h b/framework/generated/generated_wayland_xdg_shell.h new file mode 100644 index 0000000000..af62a260d9 --- /dev/null +++ b/framework/generated/generated_wayland_xdg_shell.h @@ -0,0 +1,510 @@ +/* +** Copyright (c) 2024 LunarG, Inc. +** Copyright (c) 2024 Arm Limited and/or its affiliates +** +** 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 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 GFXRECON_GENERATED_WAYLAND_XDG_SHELL_H +#define GFXRECON_GENERATED_WAYLAND_XDG_SHELL_H + +#include + +#include + +#include "util/defines.h" +#include "util/wayland_loader.h" + +struct xdg_wm_base; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_popup; + +// xdg_wm_base static declarations + +enum xdg_wm_base_error +{ + XDG_WM_BASE_ERROR_ROLE = 0, + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; + +struct xdg_wm_base_listener +{ + void (*ping)(void* data, xdg_wm_base* object, uint32_t serial); +}; + +// xdg_positioner static declarations + +enum xdg_positioner_error +{ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; + +enum xdg_positioner_anchor +{ + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; + +enum xdg_positioner_gravity +{ + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; + +enum xdg_positioner_constraint_adjustment +{ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; + +// xdg_surface static declarations + +enum xdg_surface_error +{ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; + +struct xdg_surface_listener +{ + void (*configure)(void* data, xdg_surface* object, uint32_t serial); +}; + +// xdg_toplevel static declarations + +enum xdg_toplevel_error +{ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; + +enum xdg_toplevel_resize_edge +{ + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; + +enum xdg_toplevel_state +{ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + XDG_TOPLEVEL_STATE_RESIZING = 3, + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + XDG_TOPLEVEL_STATE_SUSPENDED = 9, +}; + +enum xdg_toplevel_wm_capabilities +{ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; + +struct xdg_toplevel_listener +{ + void (*configure)(void* data, xdg_toplevel* object, int32_t width, int32_t height, wl_array* states); + void (*close)(void* data, xdg_toplevel* object); + void (*configure_bounds)(void* data, xdg_toplevel* object, int32_t width, int32_t height); + void (*wm_capabilities)(void* data, xdg_toplevel* object, wl_array* capabilities); +}; + +// xdg_popup static declarations + +enum xdg_popup_error +{ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; + +struct xdg_popup_listener +{ + void (*configure)(void* data, xdg_popup* object, int32_t x, int32_t y, int32_t width, int32_t height); + void (*popup_done)(void* data, xdg_popup* object); + void (*repositioned)(void* data, xdg_popup* object, uint32_t token); +}; + +GFXRECON_BEGIN_NAMESPACE(gfxrecon) +GFXRECON_BEGIN_NAMESPACE(util) + +// Global to xdg_shell + +class wayland_xdg_shell_table +{ + private: + + const WaylandLoader::FunctionTable* _wl; + std::vector _messages; + std::vector _messageArgs; + + public: + + // xdg_wm_base dynamic declarations + + wl_interface xdg_wm_base_interface; + + int xdg_wm_base_add_listener(xdg_wm_base* self, xdg_wm_base_listener* listener, void* data) const + { + return _wl->proxy_add_listener(reinterpret_cast(self), reinterpret_cast(listener), data); + } + + void xdg_wm_base_destroy(xdg_wm_base* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 0); + _wl->proxy_destroy(reinterpret_cast(self)); + } + + xdg_positioner* xdg_wm_base_create_positioner(xdg_wm_base* self) const + { + return reinterpret_cast(_wl->proxy_marshal_constructor(reinterpret_cast(self), 1, &xdg_positioner_interface, NULL)); + } + + xdg_surface* xdg_wm_base_get_xdg_surface(xdg_wm_base* self, wl_surface* surface) const + { + return reinterpret_cast(_wl->proxy_marshal_constructor(reinterpret_cast(self), 2, &xdg_surface_interface, NULL, surface)); + } + + void xdg_wm_base_pong(xdg_wm_base* self, uint32_t serial) const + { + _wl->proxy_marshal(reinterpret_cast(self), 3, serial); + } + + // xdg_positioner dynamic declarations + + wl_interface xdg_positioner_interface; + + void xdg_positioner_destroy(xdg_positioner* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 0); + _wl->proxy_destroy(reinterpret_cast(self)); + } + + void xdg_positioner_set_size(xdg_positioner* self, int32_t width, int32_t height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 1, width, height); + } + + void xdg_positioner_set_anchor_rect(xdg_positioner* self, int32_t x, int32_t y, int32_t width, int32_t height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 2, x, y, width, height); + } + + void xdg_positioner_set_anchor(xdg_positioner* self, uint32_t anchor) const + { + _wl->proxy_marshal(reinterpret_cast(self), 3, anchor); + } + + void xdg_positioner_set_gravity(xdg_positioner* self, uint32_t gravity) const + { + _wl->proxy_marshal(reinterpret_cast(self), 4, gravity); + } + + void xdg_positioner_set_constraint_adjustment(xdg_positioner* self, uint32_t constraint_adjustment) const + { + _wl->proxy_marshal(reinterpret_cast(self), 5, constraint_adjustment); + } + + void xdg_positioner_set_offset(xdg_positioner* self, int32_t x, int32_t y) const + { + _wl->proxy_marshal(reinterpret_cast(self), 6, x, y); + } + + void xdg_positioner_set_reactive(xdg_positioner* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 7); + } + + void xdg_positioner_set_parent_size(xdg_positioner* self, int32_t parent_width, int32_t parent_height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 8, parent_width, parent_height); + } + + void xdg_positioner_set_parent_configure(xdg_positioner* self, uint32_t serial) const + { + _wl->proxy_marshal(reinterpret_cast(self), 9, serial); + } + + // xdg_surface dynamic declarations + + wl_interface xdg_surface_interface; + + int xdg_surface_add_listener(xdg_surface* self, xdg_surface_listener* listener, void* data) const + { + return _wl->proxy_add_listener(reinterpret_cast(self), reinterpret_cast(listener), data); + } + + void xdg_surface_destroy(xdg_surface* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 0); + _wl->proxy_destroy(reinterpret_cast(self)); + } + + xdg_toplevel* xdg_surface_get_toplevel(xdg_surface* self) const + { + return reinterpret_cast(_wl->proxy_marshal_constructor(reinterpret_cast(self), 1, &xdg_toplevel_interface, NULL)); + } + + xdg_popup* xdg_surface_get_popup(xdg_surface* self, xdg_surface* parent, xdg_positioner* positioner) const + { + return reinterpret_cast(_wl->proxy_marshal_constructor(reinterpret_cast(self), 2, &xdg_popup_interface, NULL, parent, positioner)); + } + + void xdg_surface_set_window_geometry(xdg_surface* self, int32_t x, int32_t y, int32_t width, int32_t height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 3, x, y, width, height); + } + + void xdg_surface_ack_configure(xdg_surface* self, uint32_t serial) const + { + _wl->proxy_marshal(reinterpret_cast(self), 4, serial); + } + + // xdg_toplevel dynamic declarations + + wl_interface xdg_toplevel_interface; + + int xdg_toplevel_add_listener(xdg_toplevel* self, xdg_toplevel_listener* listener, void* data) const + { + return _wl->proxy_add_listener(reinterpret_cast(self), reinterpret_cast(listener), data); + } + + void xdg_toplevel_destroy(xdg_toplevel* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 0); + _wl->proxy_destroy(reinterpret_cast(self)); + } + + void xdg_toplevel_set_parent(xdg_toplevel* self, xdg_toplevel* parent) const + { + _wl->proxy_marshal(reinterpret_cast(self), 1, parent); + } + + void xdg_toplevel_set_title(xdg_toplevel* self, const char* title) const + { + _wl->proxy_marshal(reinterpret_cast(self), 2, title); + } + + void xdg_toplevel_set_app_id(xdg_toplevel* self, const char* app_id) const + { + _wl->proxy_marshal(reinterpret_cast(self), 3, app_id); + } + + void xdg_toplevel_show_window_menu(xdg_toplevel* self, wl_seat* seat, uint32_t serial, int32_t x, int32_t y) const + { + _wl->proxy_marshal(reinterpret_cast(self), 4, seat, serial, x, y); + } + + void xdg_toplevel_move(xdg_toplevel* self, wl_seat* seat, uint32_t serial) const + { + _wl->proxy_marshal(reinterpret_cast(self), 5, seat, serial); + } + + void xdg_toplevel_resize(xdg_toplevel* self, wl_seat* seat, uint32_t serial, uint32_t edges) const + { + _wl->proxy_marshal(reinterpret_cast(self), 6, seat, serial, edges); + } + + void xdg_toplevel_set_max_size(xdg_toplevel* self, int32_t width, int32_t height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 7, width, height); + } + + void xdg_toplevel_set_min_size(xdg_toplevel* self, int32_t width, int32_t height) const + { + _wl->proxy_marshal(reinterpret_cast(self), 8, width, height); + } + + void xdg_toplevel_set_maximized(xdg_toplevel* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 9); + } + + void xdg_toplevel_unset_maximized(xdg_toplevel* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 10); + } + + void xdg_toplevel_set_fullscreen(xdg_toplevel* self, wl_output* output) const + { + _wl->proxy_marshal(reinterpret_cast(self), 11, output); + } + + void xdg_toplevel_unset_fullscreen(xdg_toplevel* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 12); + } + + void xdg_toplevel_set_minimized(xdg_toplevel* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 13); + } + + // xdg_popup dynamic declarations + + wl_interface xdg_popup_interface; + + int xdg_popup_add_listener(xdg_popup* self, xdg_popup_listener* listener, void* data) const + { + return _wl->proxy_add_listener(reinterpret_cast(self), reinterpret_cast(listener), data); + } + + void xdg_popup_destroy(xdg_popup* self) const + { + _wl->proxy_marshal(reinterpret_cast(self), 0); + _wl->proxy_destroy(reinterpret_cast(self)); + } + + void xdg_popup_grab(xdg_popup* self, wl_seat* seat, uint32_t serial) const + { + _wl->proxy_marshal(reinterpret_cast(self), 1, seat, serial); + } + + void xdg_popup_reposition(xdg_popup* self, xdg_positioner* positioner, uint32_t token) const + { + _wl->proxy_marshal(reinterpret_cast(self), 2, positioner, token); + } + + // Call this once libwayland-client is successfully loaded + + void initialize(const WaylandLoader* waylandLoader) + { + _wl = &waylandLoader->GetFunctionTable(); + + _messageArgs = { + &xdg_positioner_interface, + &xdg_surface_interface, + _wl->surface_interface, + nullptr, + nullptr, + nullptr, + nullptr, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + _wl->seat_interface, + nullptr, + nullptr, + nullptr, + _wl->output_interface, + &xdg_positioner_interface, + nullptr, + }; + + _messages = { + { "destroy", "", _messageArgs.data() + 0 }, + { "create_positioner", "n", _messageArgs.data() + 0 }, + { "get_xdg_surface", "no", _messageArgs.data() + 1 }, + { "pong", "u", _messageArgs.data() + 3 }, + { "ping", "u", _messageArgs.data() + 3 }, + { "destroy", "", _messageArgs.data() + 0 }, + { "set_size", "ii", _messageArgs.data() + 3 }, + { "set_anchor_rect", "iiii", _messageArgs.data() + 3 }, + { "set_anchor", "u", _messageArgs.data() + 3 }, + { "set_gravity", "u", _messageArgs.data() + 3 }, + { "set_constraint_adjustment", "u", _messageArgs.data() + 3 }, + { "set_offset", "ii", _messageArgs.data() + 3 }, + { "set_reactive", "3", _messageArgs.data() + 0 }, + { "set_parent_size", "3ii", _messageArgs.data() + 3 }, + { "set_parent_configure", "3u", _messageArgs.data() + 3 }, + { "destroy", "", _messageArgs.data() + 0 }, + { "get_toplevel", "n", _messageArgs.data() + 7 }, + { "get_popup", "no?o", _messageArgs.data() + 8 }, + { "set_window_geometry", "iiii", _messageArgs.data() + 3 }, + { "ack_configure", "u", _messageArgs.data() + 3 }, + { "configure", "u", _messageArgs.data() + 3 }, + { "destroy", "", _messageArgs.data() + 0 }, + { "set_parent", "o?", _messageArgs.data() + 7 }, + { "set_title", "s", _messageArgs.data() + 3 }, + { "set_app_id", "s", _messageArgs.data() + 3 }, + { "show_window_menu", "ouii", _messageArgs.data() + 11 }, + { "move", "ou", _messageArgs.data() + 11 }, + { "resize", "ouu", _messageArgs.data() + 11 }, + { "set_max_size", "ii", _messageArgs.data() + 3 }, + { "set_min_size", "ii", _messageArgs.data() + 3 }, + { "set_maximized", "", _messageArgs.data() + 0 }, + { "unset_maximized", "", _messageArgs.data() + 0 }, + { "set_fullscreen", "o?", _messageArgs.data() + 15 }, + { "unset_fullscreen", "", _messageArgs.data() + 0 }, + { "set_minimized", "", _messageArgs.data() + 0 }, + { "configure", "iia", _messageArgs.data() + 3 }, + { "close", "", _messageArgs.data() + 0 }, + { "configure_bounds", "4ii", _messageArgs.data() + 3 }, + { "wm_capabilities", "5a", _messageArgs.data() + 3 }, + { "destroy", "", _messageArgs.data() + 0 }, + { "grab", "ou", _messageArgs.data() + 11 }, + { "reposition", "3ou", _messageArgs.data() + 16 }, + { "configure", "iiii", _messageArgs.data() + 3 }, + { "popup_done", "", _messageArgs.data() + 0 }, + { "repositioned", "3u", _messageArgs.data() + 3 }, + }; + + xdg_wm_base_interface = { "xdg_wm_base", 6, 4, _messages.data() + 0, 1, _messages.data() + 4 }; + xdg_positioner_interface = { "xdg_positioner", 6, 10, _messages.data() + 5, 0, _messages.data() + 15 }; + xdg_surface_interface = { "xdg_surface", 6, 5, _messages.data() + 15, 1, _messages.data() + 20 }; + xdg_toplevel_interface = { "xdg_toplevel", 6, 14, _messages.data() + 21, 4, _messages.data() + 35 }; + xdg_popup_interface = { "xdg_popup", 6, 3, _messages.data() + 39, 3, _messages.data() + 42 }; + } +}; + +GFXRECON_END_NAMESPACE(util) +GFXRECON_END_NAMESPACE(gfxrecon) + +#endif // GFXRECON_GENERATED_WAYLAND_XDG_SHELL_H diff --git a/framework/util/CMakeLists.txt b/framework/util/CMakeLists.txt index 9f9b086946..6a1a9c29a1 100644 --- a/framework/util/CMakeLists.txt +++ b/framework/util/CMakeLists.txt @@ -108,6 +108,7 @@ target_sources(gfxrecon_util $<$:${CMAKE_CURRENT_LIST_DIR}/xlib_loader.cpp> $<$:${CMAKE_CURRENT_LIST_DIR}/wayland_loader.h> $<$:${CMAKE_CURRENT_LIST_DIR}/wayland_loader.cpp> + $<$:${CMAKE_SOURCE_DIR}/framework/generated/generated_wayland_xdg_shell.h> ) diff --git a/framework/util/wayland_loader.cpp b/framework/util/wayland_loader.cpp index 53565d8078..27d5d4687d 100644 --- a/framework/util/wayland_loader.cpp +++ b/framework/util/wayland_loader.cpp @@ -70,12 +70,6 @@ bool WaylandLoader::Initialize() util::platform::GetProcAddress(libwayland_, "wl_display_flush")); function_table_.display_roundtrip = reinterpret_cast( util::platform::GetProcAddress(libwayland_, "wl_display_roundtrip")); - function_table_.compositor_interface = reinterpret_cast( - util::platform::GetProcAddress(libwayland_, "wl_compositor_interface")); - function_table_.shell_interface = reinterpret_cast( - util::platform::GetProcAddress(libwayland_, "wl_shell_interface")); - function_table_.seat_interface = reinterpret_cast( - util::platform::GetProcAddress(libwayland_, "wl_seat_interface")); // Proxy functions function_table_.proxy_add_listener = reinterpret_cast( @@ -91,6 +85,12 @@ bool WaylandLoader::Initialize() util::platform::GetProcAddress(libwayland_, "wl_proxy_marshal_constructor_versioned")); // Interfaces + function_table_.compositor_interface = reinterpret_cast( + util::platform::GetProcAddress(libwayland_, "wl_compositor_interface")); + function_table_.shell_interface = reinterpret_cast( + util::platform::GetProcAddress(libwayland_, "wl_shell_interface")); + function_table_.seat_interface = reinterpret_cast( + util::platform::GetProcAddress(libwayland_, "wl_seat_interface")); function_table_.registry_interface = reinterpret_cast( util::platform::GetProcAddress(libwayland_, "wl_registry_interface")); function_table_.keyboard_interface = reinterpret_cast( @@ -99,10 +99,14 @@ bool WaylandLoader::Initialize() util::platform::GetProcAddress(libwayland_, "wl_output_interface")); function_table_.pointer_interface = reinterpret_cast( util::platform::GetProcAddress(libwayland_, "wl_pointer_interface")); - function_table_.shell_surface_interface = reinterpret_cast( - util::platform::GetProcAddress(libwayland_, "wl_shell_surface_interface")); function_table_.surface_interface = reinterpret_cast( util::platform::GetProcAddress(libwayland_, "wl_surface_interface")); + function_table_.shell_surface_interface = reinterpret_cast( + util::platform::GetProcAddress(libwayland_, "wl_shell_surface_interface")); + + // additional protocols + function_table_.xdg = std::make_unique(); + function_table_.xdg->initialize(this); } else { diff --git a/framework/util/wayland_loader.h b/framework/util/wayland_loader.h index 8c704670da..65b82fb37d 100644 --- a/framework/util/wayland_loader.h +++ b/framework/util/wayland_loader.h @@ -24,20 +24,21 @@ #ifndef GFXRECON_UTIL_WAYLAND_LOADER_H #define GFXRECON_UTIL_WAYLAND_LOADER_H +#include + #include "util/defines.h" #include "util/platform.h" -#include - GFXRECON_BEGIN_NAMESPACE(gfxrecon) GFXRECON_BEGIN_NAMESPACE(util) +class wayland_xdg_shell_table; + class WaylandLoader { public: - class FunctionTable + struct FunctionTable { - public: // client functions decltype(wl_display_connect)* display_connect; decltype(wl_display_disconnect)* display_disconnect; @@ -45,9 +46,6 @@ class WaylandLoader decltype(wl_display_dispatch_pending)* display_dispatch_pending; decltype(wl_display_flush)* display_flush; decltype(wl_display_roundtrip)* display_roundtrip; - decltype(wl_compositor_interface)* compositor_interface; - decltype(wl_shell_interface)* shell_interface; - decltype(wl_seat_interface)* seat_interface; // proxy functions decltype(wl_proxy_add_listener)* proxy_add_listener; @@ -57,12 +55,18 @@ class WaylandLoader decltype(wl_proxy_marshal_constructor_versioned)* proxy_marshal_constructor_versioned; // interfaces + decltype(wl_compositor_interface)* compositor_interface; + decltype(wl_shell_interface)* shell_interface; + decltype(wl_seat_interface)* seat_interface; decltype(wl_registry_interface)* registry_interface; decltype(wl_keyboard_interface)* keyboard_interface; decltype(wl_output_interface)* output_interface; decltype(wl_pointer_interface)* pointer_interface; - decltype(wl_shell_surface_interface)* shell_surface_interface; decltype(wl_surface_interface)* surface_interface; + decltype(wl_shell_surface_interface)* shell_surface_interface; + + // additional protocols + std::unique_ptr xdg; // inline functions, adapted from wayland-client-protocol.h struct wl_surface* compositor_create_surface(struct wl_compositor* wl_compositor) const @@ -258,10 +262,14 @@ class WaylandLoader this->proxy_marshal(reinterpret_cast(wl_surface), WL_SURFACE_SET_BUFFER_SCALE, scale); } + void surface_commit(struct wl_surface* wl_surface) const + { + this->proxy_marshal(reinterpret_cast(wl_surface), WL_SURFACE_COMMIT); + } + void surface_destroy(struct wl_surface* wl_surface) const { this->proxy_marshal(reinterpret_cast(wl_surface), WL_SURFACE_DESTROY); - this->proxy_destroy(reinterpret_cast(wl_surface)); } }; @@ -283,4 +291,6 @@ class WaylandLoader GFXRECON_END_NAMESPACE(util) GFXRECON_END_NAMESPACE(gfxrecon) +#include "generated/generated_wayland_xdg_shell.h" + #endif // GFXRECON_UTIL_WAYLAND_LOADER_H