FreeRDP
Loading...
Searching...
No Matches
sdl_wayland.cpp
1
19#include "sdl_wayland.hpp"
20#include "sdl_utils.hpp"
21
22#include <cstring>
23
24#include <winpr/platform.h>
25
26#if defined(WITH_SDL_WAYLAND_NATIVE)
27
28#include <wayland-client.h>
29#include "xdg-shell-client-protocol.h"
30
31/* Dedicated seat/pointer on private queue to track configure serials independently of SDL. */
32struct WlMoveCtx
33{
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;
41};
42static WlMoveCtx g_wl;
43
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)
47{
48}
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)
51{
52}
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)
56{
57}
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)
61{
62 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
63 g_wl.buttonSerial = serial;
64}
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)
68{
69}
70static void pointer_frame(WINPR_ATTR_UNUSED void* data, WINPR_ATTR_UNUSED wl_pointer* pointer)
71{
72}
73static void pointer_axis_source(WINPR_ATTR_UNUSED void* data, WINPR_ATTR_UNUSED wl_pointer* pointer,
74 WINPR_ATTR_UNUSED uint32_t axisSource)
75{
76}
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)
79{
80}
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)
85{
86}
87
88/* Zero-initialized pointer listener for seat versions <= 5. */
89static const wl_pointer_listener& pointerListener()
90{
91 static const wl_pointer_listener listener = []
92 {
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;
103 return l;
104 }();
105 return listener;
106}
107
108static void seat_capabilities(WINPR_ATTR_UNUSED void* data, wl_seat* seat, uint32_t caps)
109{
110 if (((caps & WL_SEAT_CAPABILITY_POINTER) != 0) && !g_wl.pointer)
111 {
112 g_wl.pointer = wl_seat_get_pointer(seat);
113 if (g_wl.pointer)
114 wl_pointer_add_listener(g_wl.pointer, &pointerListener(), nullptr);
115 }
116}
117static void seat_name(WINPR_ATTR_UNUSED void* data, WINPR_ATTR_UNUSED wl_seat* seat,
118 WINPR_ATTR_UNUSED const char* name)
119{
120}
121static const wl_seat_listener s_seat_listener = { seat_capabilities, seat_name };
122
123static void registry_global(WINPR_ATTR_UNUSED void* data, wl_registry* reg, uint32_t name,
124 const char* iface, uint32_t version)
125{
126 if (!g_wl.seat && (strcmp(iface, wl_seat_interface.name) == 0))
127 {
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));
130 if (g_wl.seat)
131 wl_seat_add_listener(g_wl.seat, &s_seat_listener, nullptr);
132 }
133}
134static void registry_global_remove(WINPR_ATTR_UNUSED void* data, WINPR_ATTR_UNUSED wl_registry* reg,
135 WINPR_ATTR_UNUSED uint32_t name)
136{
137}
138static const wl_registry_listener s_registry_listener = { registry_global, registry_global_remove };
139
140static bool ensure_init(SDL_Window* window)
141{
142 if (g_wl.pointer)
143 return true;
144 if (g_wl.initTried)
145 return false;
146 g_wl.initTried = true;
147
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));
151 if (!g_wl.display)
152 return false;
153
154 g_wl.queue = wl_display_create_queue(g_wl.display);
155 if (!g_wl.queue)
156 return false;
157
158 auto wrapped = static_cast<wl_display*>(wl_proxy_create_wrapper(g_wl.display));
159 if (!wrapped)
160 return false;
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);
164 if (!g_wl.registry)
165 return false;
166
167 wl_registry_add_listener(g_wl.registry, &s_registry_listener, nullptr);
168 /* First roundtrip delivers globals (seat), second the seat capabilities (pointer). */
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;
172}
173
174void sdl_wayland_move_prepare(SDL_Window* window)
175{
176 if (window && sdl::utils::isWaylandDriver())
177 (void)ensure_init(window);
178}
179
180static bool sdl_wayland_begin_interactive(SDL_Window* window, bool move, uint32_t xdgEdge)
181{
182 if (!window || !sdl::utils::isWaylandDriver())
183 return false;
184 if (!ensure_init(window))
185 return false;
186
187 /* Drain queue so buttonSerial reflects the triggering press. */
188 wl_display_roundtrip_queue(g_wl.display, g_wl.queue);
189
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))
194 return false;
195
196 if (move)
197 xdg_toplevel_move(toplevel, g_wl.seat, g_wl.buttonSerial);
198 else
199 xdg_toplevel_resize(toplevel, g_wl.seat, g_wl.buttonSerial, xdgEdge);
200 wl_display_flush(g_wl.display);
201 return true;
202}
203
204bool sdl_wayland_begin_move(SDL_Window* window)
205{
206 return sdl_wayland_begin_interactive(window, true, 0);
207}
208
209bool sdl_wayland_begin_resize(SDL_Window* window, uint32_t xdgEdge)
210{
211 return sdl_wayland_begin_interactive(window, false, xdgEdge);
212}
213
214#else /* !WITH_SDL_WAYLAND_NATIVE */
215
216void sdl_wayland_move_prepare(WINPR_ATTR_UNUSED SDL_Window* window)
217{
218}
219
220bool sdl_wayland_begin_move(WINPR_ATTR_UNUSED SDL_Window* window)
221{
222 return false;
223}
224
225bool sdl_wayland_begin_resize(WINPR_ATTR_UNUSED SDL_Window* window,
226 WINPR_ATTR_UNUSED uint32_t xdgEdge)
227{
228 return false;
229}
230
231#endif