FreeRDP
Loading...
Searching...
No Matches
sdl_rail_platform.cpp
1
19#include "sdl_rail_platform.hpp"
20#include "sdl_utils.hpp"
21#include "sdl_wayland.hpp"
22#include "sdl_win32.hpp"
23#include "sdl_x11.hpp"
24
25#include <freerdp/log.h>
26#include <freerdp/rail.h>
27
28#define TAG CLIENT_TAG("sdl.rail")
29
30static RailPlatformCaps detectRailPlatformCaps()
31{
33 if (sdl::utils::isWaylandDriver())
34 {
35 /* Wayland: toplevels can't be positioned or queried; its compositor always composites. */
36 caps.kind = RailPlatformKind::Wayland;
37 caps.supportsWindowPositions = false;
38 caps.supportsTransparentWindows = true;
39 caps.supportsRestack = false;
40 caps.band = RailBandMechanism::None;
41 caps.drag = RailDragModel::CompositorResize;
42 }
43 else if (sdl::utils::isX11Driver())
44 {
45 /* X11: transparent resize band requires compositing (_GTK_FRAME_EXTENTS). */
46 caps.kind = RailPlatformKind::X11;
47 caps.supportsWindowPositions = true;
48 caps.supportsTransparentWindows = sdl_x11_has_compositor();
49 caps.supportsRestack = true;
50 caps.band = caps.supportsTransparentWindows ? RailBandMechanism::FrameExtents
51 : RailBandMechanism::None;
52 caps.drag = RailDragModel::WmMoveResize;
53 }
54 else if (sdl::utils::isWindowsDriver())
55 {
56 /* Windows: DWM always composites; the band is the native sizing frame. */
57 caps.kind = RailPlatformKind::Win32;
58 caps.supportsWindowPositions = true;
59 caps.supportsTransparentWindows = true;
60 caps.supportsRestack = true;
61 caps.band = RailBandMechanism::NativeFrame;
62 caps.drag = RailDragModel::ModalLoop;
63 }
64 return caps;
65}
66
67const RailPlatformCaps& railPlatformCaps()
68{
69 static const RailPlatformCaps caps = detectRailPlatformCaps();
70 return caps;
71}
72
73/* RAIL_WMSZ_* -> _NET_WM_MOVERESIZE direction (0..7 = resize edges, 8 = move). */
74[[nodiscard]] static int railToNetDirection(uint16_t moveType)
75{
76 switch (moveType)
77 {
78 case RAIL_WMSZ_TOPLEFT:
79 return 0;
80 case RAIL_WMSZ_TOP:
81 return 1;
82 case RAIL_WMSZ_TOPRIGHT:
83 return 2;
84 case RAIL_WMSZ_RIGHT:
85 return 3;
86 case RAIL_WMSZ_BOTTOMRIGHT:
87 return 4;
88 case RAIL_WMSZ_BOTTOM:
89 return 5;
90 case RAIL_WMSZ_BOTTOMLEFT:
91 return 6;
92 case RAIL_WMSZ_LEFT:
93 return 7;
94 case RAIL_WMSZ_MOVE:
95 default:
96 return 8;
97 }
98}
99
100static constexpr struct
101{
102 uint16_t rail;
103 uint32_t xdg;
104} kRailXdgEdges[] = {
105 { RAIL_WMSZ_TOP, 1 }, { RAIL_WMSZ_BOTTOM, 2 }, { RAIL_WMSZ_LEFT, 4 },
106 { RAIL_WMSZ_TOPLEFT, 5 }, { RAIL_WMSZ_BOTTOMLEFT, 6 }, { RAIL_WMSZ_RIGHT, 8 },
107 { RAIL_WMSZ_TOPRIGHT, 9 }, { RAIL_WMSZ_BOTTOMRIGHT, 10 },
108};
109
110/* RAIL_WMSZ_* -> XDG_TOPLEVEL_RESIZE_EDGE_* (0 = none, e.g. RAIL_WMSZ_MOVE). */
111[[nodiscard]] static uint32_t railToXdgEdge(uint16_t moveType)
112{
113 for (const auto& e : kRailXdgEdges)
114 if (e.rail == moveType)
115 return e.xdg;
116 return 0;
117}
118
119RailEdges railEdges(uint16_t moveType)
120{
121 return { (moveType == RAIL_WMSZ_TOPLEFT) || (moveType == RAIL_WMSZ_LEFT) ||
122 (moveType == RAIL_WMSZ_BOTTOMLEFT),
123 (moveType == RAIL_WMSZ_TOPRIGHT) || (moveType == RAIL_WMSZ_RIGHT) ||
124 (moveType == RAIL_WMSZ_BOTTOMRIGHT),
125 (moveType == RAIL_WMSZ_TOPLEFT) || (moveType == RAIL_WMSZ_TOP) ||
126 (moveType == RAIL_WMSZ_TOPRIGHT),
127 (moveType == RAIL_WMSZ_BOTTOMLEFT) || (moveType == RAIL_WMSZ_BOTTOM) ||
128 (moveType == RAIL_WMSZ_BOTTOMRIGHT) };
129}
130
131void railPlatformPrepareWindow(SDL_Window* window)
132{
133 switch (railPlatformCaps().kind)
134 {
135 case RailPlatformKind::Wayland:
136 sdl_wayland_move_prepare(window);
137 break;
138 case RailPlatformKind::Win32:
139 if (!sdl_win32_use_native_frame(window))
140 WLog_WARN(TAG, "native window frame not available");
141 break;
142 default:
143 break;
144 }
145}
146
147bool railPlatformSetWindowRect(SDL_Window* window, const SDL_Rect& rect)
148{
149 if (railPlatformCaps().kind == RailPlatformKind::Win32)
150 return sdl_win32_set_client_rect(window, rect);
151 return false;
152}
153
154void railPlatformSetNativeLoopHandler(const RailNativeLoopHandler& handler)
155{
156 /* WMSZ_* equals RAIL_WMSZ_*. */
157 if (railPlatformCaps().kind == RailPlatformKind::Win32)
158 sdl_win32_set_size_move_handler({ handler.userdata, handler.redraw, handler.resize });
159}
160
161bool railPlatformSetBand(SDL_Window* window, const SDL_Rect& insets)
162{
163 const auto& caps = railPlatformCaps();
164 if (caps.band == RailBandMechanism::None)
165 return false;
166 switch (caps.kind)
167 {
168 case RailPlatformKind::X11:
169 return sdl_x11_set_frame_extents(window, insets.x, insets.w, insets.y, insets.h);
170 case RailPlatformKind::Win32: /* nothing to declare, the OS owns the frame */
171 default:
172 return false;
173 }
174}
175
176bool railPlatformRestack(const std::vector<SDL_Window*>& topToBottom)
177{
178 switch (railPlatformCaps().kind)
179 {
180 case RailPlatformKind::X11:
181 return sdl_x11_restack_windows(topToBottom);
182 case RailPlatformKind::Win32:
183 return sdl_win32_restack_windows(topToBottom);
184 default:
185 return false;
186 }
187}
188
189bool railPlatformBeginDrag(SDL_Window* window, uint16_t moveType)
190{
191 switch (railPlatformCaps().kind)
192 {
193 case RailPlatformKind::Wayland:
194 if (moveType == RAIL_WMSZ_MOVE)
195 return sdl_wayland_begin_move(window);
196 return sdl_wayland_begin_resize(window, railToXdgEdge(moveType));
197 case RailPlatformKind::X11:
198 {
199 if (!sdl_x11_begin_move_size(window, railToNetDirection(moveType)))
200 return false;
201 /* Bit gravity keeps the content at the fixed edge while the WM resizes. */
202 const RailEdges e = railEdges(moveType);
203 const int row = e.top ? 2 : (e.bottom ? 0 : 1);
204 const int col = e.left ? 2 : (e.right ? 0 : 1);
205 if (!sdl_x11_set_bit_gravity(window, row * 3 + col + 1))
206 WLog_DBG(TAG, "setting the X11 bit gravity failed");
207 return true;
208 }
209 case RailPlatformKind::Win32:
210 /* Only validated here; railPlatformRunModalDrag runs it once the caller is unlocked. */
211 return sdl_win32_can_move_size(window, moveType == RAIL_WMSZ_MOVE, moveType);
212 default:
213 return false;
214 }
215}
216
217void railPlatformRunModalDrag(SDL_Window* window, uint16_t moveType)
218{
219 /* RAIL_WMSZ_* edges have the same values as WMSZ_*. */
220 if (railPlatformCaps().kind == RailPlatformKind::Win32)
221 sdl_win32_run_move_size(window, moveType == RAIL_WMSZ_MOVE, moveType);
222}
223
224bool railPlatformReleaseButton(SDL_Window* window)
225{
226 switch (railPlatformCaps().kind)
227 {
228 case RailPlatformKind::X11:
229 return sdl_x11_send_left_button_release(window);
230 case RailPlatformKind::Win32:
231 return sdl_win32_send_left_button_release(window);
232 default:
233 return false;
234 }
235}
236
237bool railPlatformRaiseOwned(SDL_Window* window)
238{
239 /* Elsewhere the owner relation keeps the window above its owner. */
240 if (railPlatformCaps().kind != RailPlatformKind::X11)
241 return true;
242 return sdl_x11_raise_window(window);
243}
244
245void railPlatformEndDrag(SDL_Window* window)
246{
247 if (railPlatformCaps().kind == RailPlatformKind::X11)
248 if (!sdl_x11_set_bit_gravity(window, 0 /* reset to default */))
249 WLog_DBG(TAG, "resetting the X11 bit gravity failed");
250}
-aad-helper