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