FreeRDP
Loading...
Searching...
No Matches
wlf_disp.c
1
21#include <winpr/sysinfo.h>
22#include <winpr/cast.h>
23
24#include "wlf_disp.h"
25
26#define TAG CLIENT_TAG("wayland.disp")
27
28#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
29
30struct s_wlfDispContext
31{
32 wlfContext* wlc;
33 DispClientContext* disp;
34 BOOL haveXRandr;
35 int eventBase, errorBase;
36 int lastSentWidth, lastSentHeight;
37 UINT64 lastSentDate;
38 int targetWidth, targetHeight;
39 BOOL activated;
40 BOOL waitingResize;
41 BOOL fullscreen;
42 UINT16 lastSentDesktopOrientation;
43 UINT32 lastSentDesktopScaleFactor;
44 UINT32 lastSentDeviceScaleFactor;
45};
46
47static UINT wlf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
48 size_t nmonitors);
49
50static BOOL wlf_disp_settings_changed(wlfDispContext* wlfDisp)
51{
52 rdpSettings* settings = NULL;
53
54 WINPR_ASSERT(wlfDisp);
55 WINPR_ASSERT(wlfDisp->wlc);
56
57 settings = wlfDisp->wlc->common.context.settings;
58 WINPR_ASSERT(settings);
59
60 if (wlfDisp->lastSentWidth != wlfDisp->targetWidth)
61 return TRUE;
62
63 if (wlfDisp->lastSentHeight != wlfDisp->targetHeight)
64 return TRUE;
65
66 if (wlfDisp->lastSentDesktopOrientation !=
67 freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation))
68 return TRUE;
69
70 if (wlfDisp->lastSentDesktopScaleFactor !=
71 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor))
72 return TRUE;
73
74 if (wlfDisp->lastSentDeviceScaleFactor !=
75 freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor))
76 return TRUE;
77
78 if (wlfDisp->fullscreen != wlfDisp->wlc->fullscreen)
79 return TRUE;
80
81 return FALSE;
82}
83
84static BOOL wlf_update_last_sent(wlfDispContext* wlfDisp)
85{
86 rdpSettings* settings = NULL;
87
88 WINPR_ASSERT(wlfDisp);
89 WINPR_ASSERT(wlfDisp->wlc);
90
91 settings = wlfDisp->wlc->common.context.settings;
92 WINPR_ASSERT(settings);
93
94 wlfDisp->lastSentWidth = wlfDisp->targetWidth;
95 wlfDisp->lastSentHeight = wlfDisp->targetHeight;
96 wlfDisp->lastSentDesktopOrientation =
97 freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
98 wlfDisp->lastSentDesktopScaleFactor =
99 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
100 wlfDisp->lastSentDeviceScaleFactor =
101 freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
102 wlfDisp->fullscreen = wlfDisp->wlc->fullscreen;
103 return TRUE;
104}
105
106static BOOL wlf_disp_sendResize(wlfDispContext* wlfDisp)
107{
109 wlfContext* wlc = NULL;
110 rdpSettings* settings = NULL;
111
112 if (!wlfDisp || !wlfDisp->wlc)
113 return FALSE;
114
115 wlc = wlfDisp->wlc;
116 settings = wlc->common.context.settings;
117
118 if (!settings)
119 return FALSE;
120
121 if (!wlfDisp->activated || !wlfDisp->disp)
122 return TRUE;
123
124 if (GetTickCount64() - wlfDisp->lastSentDate < RESIZE_MIN_DELAY)
125 return TRUE;
126
127 wlfDisp->lastSentDate = GetTickCount64();
128
129 if (!wlf_disp_settings_changed(wlfDisp))
130 return TRUE;
131
132 if (wlc->fullscreen && (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0))
133 {
134 const rdpMonitor* monitors =
135 freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
136 const size_t nmonitors = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
137 if (wlf_disp_sendLayout(wlfDisp->disp, monitors, nmonitors) != CHANNEL_RC_OK)
138 return FALSE;
139 }
140 else
141 {
142 wlfDisp->waitingResize = TRUE;
143 layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
144 layout.Top = layout.Left = 0;
145 layout.Width = WINPR_ASSERTING_INT_CAST(uint32_t, wlfDisp->targetWidth);
146 layout.Height = WINPR_ASSERTING_INT_CAST(uint32_t, wlfDisp->targetHeight);
147 layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
148 layout.DesktopScaleFactor =
149 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
150 layout.DeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
151 layout.PhysicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, wlfDisp->targetWidth);
152 layout.PhysicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, wlfDisp->targetHeight);
153
154 if (IFCALLRESULT(CHANNEL_RC_OK, wlfDisp->disp->SendMonitorLayout, wlfDisp->disp, 1,
155 &layout) != CHANNEL_RC_OK)
156 return FALSE;
157 }
158 return wlf_update_last_sent(wlfDisp);
159}
160
161static BOOL wlf_disp_set_window_resizable(WINPR_ATTR_UNUSED wlfDispContext* wlfDisp)
162{
163 WLog_ERR("TODO", "TODO: implement");
164 return TRUE;
165}
166
167static BOOL wlf_disp_check_context(void* context, wlfContext** ppwlc, wlfDispContext** ppwlfDisp,
168 rdpSettings** ppSettings)
169{
170 wlfContext* wlc = NULL;
171
172 if (!context)
173 return FALSE;
174
175 wlc = (wlfContext*)context;
176
177 if (!(wlc->disp))
178 return FALSE;
179
180 if (!wlc->common.context.settings)
181 return FALSE;
182
183 *ppwlc = wlc;
184 *ppwlfDisp = wlc->disp;
185 *ppSettings = wlc->common.context.settings;
186 return TRUE;
187}
188
189static void wlf_disp_OnActivated(void* context, const ActivatedEventArgs* e)
190{
191 wlfContext* wlc = NULL;
192 wlfDispContext* wlfDisp = NULL;
193 rdpSettings* settings = NULL;
194
195 if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
196 return;
197
198 wlfDisp->waitingResize = FALSE;
199
200 if (wlfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
201 {
202 wlf_disp_set_window_resizable(wlfDisp);
203
204 if (e->firstActivation)
205 return;
206
207 wlf_disp_sendResize(wlfDisp);
208 }
209}
210
211static void wlf_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
212{
213 wlfContext* wlc = NULL;
214 wlfDispContext* wlfDisp = NULL;
215 rdpSettings* settings = NULL;
216
217 WINPR_UNUSED(e);
218 if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
219 return;
220
221 wlfDisp->waitingResize = FALSE;
222
223 if (wlfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
224 {
225 wlf_disp_set_window_resizable(wlfDisp);
226 wlf_disp_sendResize(wlfDisp);
227 }
228}
229
230static void wlf_disp_OnTimer(void* context, const TimerEventArgs* e)
231{
232 wlfContext* wlc = NULL;
233 wlfDispContext* wlfDisp = NULL;
234 rdpSettings* settings = NULL;
235
236 WINPR_UNUSED(e);
237 if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
238 return;
239
240 if (!wlfDisp->activated || freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
241 return;
242
243 wlf_disp_sendResize(wlfDisp);
244}
245
246wlfDispContext* wlf_disp_new(wlfContext* wlc)
247{
248 wlfDispContext* ret = NULL;
249 wPubSub* pubSub = NULL;
250 rdpSettings* settings = NULL;
251
252 if (!wlc || !wlc->common.context.settings || !wlc->common.context.pubSub)
253 return NULL;
254
255 settings = wlc->common.context.settings;
256 pubSub = wlc->common.context.pubSub;
257 ret = calloc(1, sizeof(wlfDispContext));
258
259 if (!ret)
260 return NULL;
261
262 ret->wlc = wlc;
263 ret->lastSentWidth = ret->targetWidth =
264 WINPR_ASSERTING_INT_CAST(int, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth));
265 ret->lastSentHeight = ret->targetHeight =
266 WINPR_ASSERTING_INT_CAST(int, freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
267 PubSub_SubscribeActivated(pubSub, wlf_disp_OnActivated);
268 PubSub_SubscribeGraphicsReset(pubSub, wlf_disp_OnGraphicsReset);
269 PubSub_SubscribeTimer(pubSub, wlf_disp_OnTimer);
270 return ret;
271}
272
273void wlf_disp_free(wlfDispContext* disp)
274{
275 if (!disp)
276 return;
277
278 if (disp->wlc)
279 {
280 wPubSub* pubSub = disp->wlc->common.context.pubSub;
281 PubSub_UnsubscribeActivated(pubSub, wlf_disp_OnActivated);
282 PubSub_UnsubscribeGraphicsReset(pubSub, wlf_disp_OnGraphicsReset);
283 PubSub_UnsubscribeTimer(pubSub, wlf_disp_OnTimer);
284 }
285
286 free(disp);
287}
288
289UINT wlf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors, size_t nmonitors)
290{
291 UINT ret = CHANNEL_RC_OK;
292 DISPLAY_CONTROL_MONITOR_LAYOUT* layouts = NULL;
293 wlfDispContext* wlfDisp = NULL;
294 rdpSettings* settings = NULL;
295
296 WINPR_ASSERT(disp);
297 WINPR_ASSERT(monitors);
298 WINPR_ASSERT(nmonitors > 0);
299 WINPR_ASSERT(nmonitors <= UINT32_MAX);
300
301 wlfDisp = (wlfDispContext*)disp->custom;
302 WINPR_ASSERT(wlfDisp);
303 WINPR_ASSERT(wlfDisp->wlc);
304
305 settings = wlfDisp->wlc->common.context.settings;
306 WINPR_ASSERT(settings);
307
308 layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
309
310 if (!layouts)
311 return CHANNEL_RC_NO_MEMORY;
312
313 for (size_t i = 0; i < nmonitors; i++)
314 {
315 const rdpMonitor* monitor = &monitors[i];
316 DISPLAY_CONTROL_MONITOR_LAYOUT* layout = &layouts[i];
317
318 layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
319 layout->Left = monitor->x;
320 layout->Top = monitor->y;
321 layout->Width = WINPR_ASSERTING_INT_CAST(UINT32, monitor->width);
322 layout->Height = WINPR_ASSERTING_INT_CAST(UINT32, monitor->height);
323 layout->Orientation = ORIENTATION_LANDSCAPE;
324 layout->PhysicalWidth = monitor->attributes.physicalWidth;
325 layout->PhysicalHeight = monitor->attributes.physicalHeight;
326
327 switch (monitor->attributes.orientation)
328 {
329 case 90:
330 layout->Orientation = ORIENTATION_PORTRAIT;
331 break;
332
333 case 180:
334 layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
335 break;
336
337 case 270:
338 layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
339 break;
340
341 case 0:
342 default:
343 /* MS-RDPEDISP - 2.2.2.2.1:
344 * Orientation (4 bytes): A 32-bit unsigned integer that specifies the
345 * orientation of the monitor in degrees. Valid values are 0, 90, 180
346 * or 270
347 *
348 * So we default to ORIENTATION_LANDSCAPE
349 */
350 layout->Orientation = ORIENTATION_LANDSCAPE;
351 break;
352 }
353
354 layout->DesktopScaleFactor =
355 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
356 layout->DeviceScaleFactor =
357 freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
358 }
359
360 ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, (UINT32)nmonitors, layouts);
361 free(layouts);
362 return ret;
363}
364
365BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height)
366{
367 if (!disp)
368 return FALSE;
369
370 disp->targetWidth = width;
371 disp->targetHeight = height;
372 return wlf_disp_sendResize(disp);
373}
374
375static UINT wlf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
376 UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
377{
378 /* we're called only if dynamic resolution update is activated */
379 wlfDispContext* wlfDisp = NULL;
380 rdpSettings* settings = NULL;
381
382 WINPR_ASSERT(disp);
383
384 wlfDisp = (wlfDispContext*)disp->custom;
385 WINPR_ASSERT(wlfDisp);
386 WINPR_ASSERT(wlfDisp->wlc);
387
388 settings = wlfDisp->wlc->common.context.settings;
389 WINPR_ASSERT(settings);
390
391 WLog_DBG(TAG,
392 "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
393 " MaxMonitorAreaFactorB: %" PRIu32 "",
394 maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
395 wlfDisp->activated = TRUE;
396
397 if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
398 return CHANNEL_RC_OK;
399
400 WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
401 return wlf_disp_set_window_resizable(wlfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
402}
403
404BOOL wlf_disp_init(wlfDispContext* wlfDisp, DispClientContext* disp)
405{
406 rdpSettings* settings = NULL;
407
408 if (!wlfDisp || !wlfDisp->wlc || !disp)
409 return FALSE;
410
411 settings = wlfDisp->wlc->common.context.settings;
412
413 if (!settings)
414 return FALSE;
415
416 wlfDisp->disp = disp;
417 disp->custom = (void*)wlfDisp;
418
419 if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
420 {
421 disp->DisplayControlCaps = wlf_DisplayControlCaps;
422 }
423
424 return TRUE;
425}
426
427BOOL wlf_disp_uninit(wlfDispContext* wlfDisp, DispClientContext* disp)
428{
429 if (!wlfDisp || !disp)
430 return FALSE;
431
432 wlfDisp->disp = NULL;
433 return TRUE;
434}
435
436int wlf_list_monitors(wlfContext* wlc)
437{
438 uint32_t nmonitors = UwacDisplayGetNbOutputs(wlc->display);
439
440 for (uint32_t i = 0; i < nmonitors; i++)
441 {
442 const UwacOutput* monitor =
443 UwacDisplayGetOutput(wlc->display, WINPR_ASSERTING_INT_CAST(int, i));
444 UwacSize resolution;
445 UwacPosition pos;
446
447 if (!monitor)
448 continue;
449 UwacOutputGetPosition(monitor, &pos);
450 UwacOutputGetResolution(monitor, &resolution);
451
452 printf(" %s [%u] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, resolution.width,
453 resolution.height, pos.x, pos.y);
454 }
455
456 return 0;
457}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.