19#include "sdl_wayland.hpp"
20#include "sdl_utils.hpp"
24#include <winpr/platform.h>
26#if defined(WITH_SDL_WAYLAND_NATIVE)
28#include <wayland-client.h>
29#include "xdg-shell-client-protocol.h"
34 wl_display* display =
nullptr;
35 wl_event_queue* queue =
nullptr;
36 wl_registry* registry =
nullptr;
37 wl_seat* seat =
nullptr;
38 wl_pointer* pointer =
nullptr;
39 uint32_t buttonSerial = 0;
40 bool initTried =
false;
44static void pointer_enter(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
45 WINPR_ATTR_UNUSED uint32_t serial, WINPR_ATTR_UNUSED wl_surface* surface,
46 WINPR_ATTR_UNUSED wl_fixed_t sx, WINPR_ATTR_UNUSED wl_fixed_t sy)
49static void pointer_leave(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
50 WINPR_ATTR_UNUSED uint32_t serial, WINPR_ATTR_UNUSED wl_surface* surface)
53static void pointer_motion(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
54 WINPR_ATTR_UNUSED uint32_t time, WINPR_ATTR_UNUSED wl_fixed_t sx,
55 WINPR_ATTR_UNUSED wl_fixed_t sy)
58static void pointer_button(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
59 uint32_t serial, WINPR_ATTR_UNUSED uint32_t time,
60 WINPR_ATTR_UNUSED uint32_t button, uint32_t state)
62 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
63 g_wl.buttonSerial = serial;
65static void pointer_axis(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
66 WINPR_ATTR_UNUSED uint32_t time, WINPR_ATTR_UNUSED uint32_t axis,
67 WINPR_ATTR_UNUSED wl_fixed_t value)
70static void pointer_frame(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer)
73static void pointer_axis_source(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
74 WINPR_ATTR_UNUSED uint32_t axisSource)
77static void pointer_axis_stop(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
78 WINPR_ATTR_UNUSED uint32_t time, WINPR_ATTR_UNUSED uint32_t axis)
81static void pointer_axis_discrete(WINPR_ATTR_UNUSED
void* data,
82 WINPR_ATTR_UNUSED wl_pointer* pointer,
83 WINPR_ATTR_UNUSED uint32_t axis,
84 WINPR_ATTR_UNUSED int32_t discrete)
89static const wl_pointer_listener& pointerListener()
91 static const wl_pointer_listener listener = []
93 wl_pointer_listener l = {};
94 l.enter = pointer_enter;
95 l.leave = pointer_leave;
96 l.motion = pointer_motion;
97 l.button = pointer_button;
98 l.axis = pointer_axis;
99 l.frame = pointer_frame;
100 l.axis_source = pointer_axis_source;
101 l.axis_stop = pointer_axis_stop;
102 l.axis_discrete = pointer_axis_discrete;
108static void seat_capabilities(WINPR_ATTR_UNUSED
void* data, wl_seat* seat, uint32_t caps)
110 if (((caps & WL_SEAT_CAPABILITY_POINTER) != 0) && !g_wl.pointer)
112 g_wl.pointer = wl_seat_get_pointer(seat);
114 wl_pointer_add_listener(g_wl.pointer, &pointerListener(),
nullptr);
117static void seat_name(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_seat* seat,
118 WINPR_ATTR_UNUSED
const char* name)
121static const wl_seat_listener s_seat_listener = { seat_capabilities, seat_name };
123static void registry_global(WINPR_ATTR_UNUSED
void* data, wl_registry* reg, uint32_t name,
124 const char* iface, uint32_t version)
126 if (!g_wl.seat && (strcmp(iface, wl_seat_interface.name) == 0))
128 const uint32_t v = (version < 5) ? version : 5;
129 g_wl.seat =
static_cast<wl_seat*
>(wl_registry_bind(reg, name, &wl_seat_interface, v));
131 wl_seat_add_listener(g_wl.seat, &s_seat_listener,
nullptr);
134static void registry_global_remove(WINPR_ATTR_UNUSED
void* data, WINPR_ATTR_UNUSED wl_registry* reg,
135 WINPR_ATTR_UNUSED uint32_t name)
138static const wl_registry_listener s_registry_listener = { registry_global, registry_global_remove };
140static bool ensure_init(SDL_Window* window)
146 g_wl.initTried =
true;
148 auto props = SDL_GetWindowProperties(window);
149 g_wl.display =
static_cast<wl_display*
>(
150 SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER,
nullptr));
154 g_wl.queue = wl_display_create_queue(g_wl.display);
158 auto wrapped =
static_cast<wl_display*
>(wl_proxy_create_wrapper(g_wl.display));
161 wl_proxy_set_queue(
reinterpret_cast<wl_proxy*
>(wrapped), g_wl.queue);
162 g_wl.registry = wl_display_get_registry(wrapped);
163 wl_proxy_wrapper_destroy(wrapped);
167 wl_registry_add_listener(g_wl.registry, &s_registry_listener,
nullptr);
169 wl_display_roundtrip_queue(g_wl.display, g_wl.queue);
170 wl_display_roundtrip_queue(g_wl.display, g_wl.queue);
171 return g_wl.pointer !=
nullptr;
174void sdl_wayland_move_prepare(SDL_Window* window)
176 if (window && sdl::utils::isWaylandDriver())
177 (void)ensure_init(window);
180static bool sdl_wayland_begin_interactive(SDL_Window* window,
bool move, uint32_t xdgEdge)
182 if (!window || !sdl::utils::isWaylandDriver())
184 if (!ensure_init(window))
188 wl_display_roundtrip_queue(g_wl.display, g_wl.queue);
190 auto props = SDL_GetWindowProperties(window);
191 auto toplevel =
static_cast<xdg_toplevel*
>(
192 SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER,
nullptr));
193 if (!toplevel || !g_wl.seat || (g_wl.buttonSerial == 0))
197 xdg_toplevel_move(toplevel, g_wl.seat, g_wl.buttonSerial);
199 xdg_toplevel_resize(toplevel, g_wl.seat, g_wl.buttonSerial, xdgEdge);
200 wl_display_flush(g_wl.display);
204bool sdl_wayland_begin_move(SDL_Window* window)
206 return sdl_wayland_begin_interactive(window,
true, 0);
209bool sdl_wayland_begin_resize(SDL_Window* window, uint32_t xdgEdge)
211 return sdl_wayland_begin_interactive(window,
false, xdgEdge);
216void sdl_wayland_move_prepare(WINPR_ATTR_UNUSED SDL_Window* window)
220bool sdl_wayland_begin_move(WINPR_ATTR_UNUSED SDL_Window* window)
225bool sdl_wayland_begin_resize(WINPR_ATTR_UNUSED SDL_Window* window,
226 WINPR_ATTR_UNUSED uint32_t xdgEdge)