FreeRDP
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 
30 struct 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 
47 static UINT wlf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
48  size_t nmonitors);
49 
50 static 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 
84 static 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 
106 static 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  /* TODO: Multimonitor support for wayland
133  if (wlc->fullscreen && (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount > 0))
134  {
135  if (wlf_disp_sendLayout(wlfDisp->disp, setings->MonitorDefArray,
136  freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) !=
137  CHANNEL_RC_OK) return FALSE;
138  }
139  else
140  */
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 
161 static BOOL wlf_disp_set_window_resizable(wlfDispContext* wlfDisp)
162 {
163 #if 0 // TODO
164 #endif
165  return TRUE;
166 }
167 
168 static BOOL wlf_disp_check_context(void* context, wlfContext** ppwlc, wlfDispContext** ppwlfDisp,
169  rdpSettings** ppSettings)
170 {
171  wlfContext* wlc = NULL;
172 
173  if (!context)
174  return FALSE;
175 
176  wlc = (wlfContext*)context;
177 
178  if (!(wlc->disp))
179  return FALSE;
180 
181  if (!wlc->common.context.settings)
182  return FALSE;
183 
184  *ppwlc = wlc;
185  *ppwlfDisp = wlc->disp;
186  *ppSettings = wlc->common.context.settings;
187  return TRUE;
188 }
189 
190 static void wlf_disp_OnActivated(void* context, const ActivatedEventArgs* e)
191 {
192  wlfContext* wlc = NULL;
193  wlfDispContext* wlfDisp = NULL;
194  rdpSettings* settings = NULL;
195 
196  if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
197  return;
198 
199  wlfDisp->waitingResize = FALSE;
200 
201  if (wlfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
202  {
203  wlf_disp_set_window_resizable(wlfDisp);
204 
205  if (e->firstActivation)
206  return;
207 
208  wlf_disp_sendResize(wlfDisp);
209  }
210 }
211 
212 static void wlf_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
213 {
214  wlfContext* wlc = NULL;
215  wlfDispContext* wlfDisp = NULL;
216  rdpSettings* settings = NULL;
217 
218  WINPR_UNUSED(e);
219  if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
220  return;
221 
222  wlfDisp->waitingResize = FALSE;
223 
224  if (wlfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
225  {
226  wlf_disp_set_window_resizable(wlfDisp);
227  wlf_disp_sendResize(wlfDisp);
228  }
229 }
230 
231 static void wlf_disp_OnTimer(void* context, const TimerEventArgs* e)
232 {
233  wlfContext* wlc = NULL;
234  wlfDispContext* wlfDisp = NULL;
235  rdpSettings* settings = NULL;
236 
237  WINPR_UNUSED(e);
238  if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
239  return;
240 
241  if (!wlfDisp->activated || freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
242  return;
243 
244  wlf_disp_sendResize(wlfDisp);
245 }
246 
247 wlfDispContext* wlf_disp_new(wlfContext* wlc)
248 {
249  wlfDispContext* ret = NULL;
250  wPubSub* pubSub = NULL;
251  rdpSettings* settings = NULL;
252 
253  if (!wlc || !wlc->common.context.settings || !wlc->common.context.pubSub)
254  return NULL;
255 
256  settings = wlc->common.context.settings;
257  pubSub = wlc->common.context.pubSub;
258  ret = calloc(1, sizeof(wlfDispContext));
259 
260  if (!ret)
261  return NULL;
262 
263  ret->wlc = wlc;
264  ret->lastSentWidth = ret->targetWidth =
265  WINPR_ASSERTING_INT_CAST(int, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth));
266  ret->lastSentHeight = ret->targetHeight =
267  WINPR_ASSERTING_INT_CAST(int, freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
268  PubSub_SubscribeActivated(pubSub, wlf_disp_OnActivated);
269  PubSub_SubscribeGraphicsReset(pubSub, wlf_disp_OnGraphicsReset);
270  PubSub_SubscribeTimer(pubSub, wlf_disp_OnTimer);
271  return ret;
272 }
273 
274 void wlf_disp_free(wlfDispContext* disp)
275 {
276  if (!disp)
277  return;
278 
279  if (disp->wlc)
280  {
281  wPubSub* pubSub = disp->wlc->common.context.pubSub;
282  PubSub_UnsubscribeActivated(pubSub, wlf_disp_OnActivated);
283  PubSub_UnsubscribeGraphicsReset(pubSub, wlf_disp_OnGraphicsReset);
284  PubSub_UnsubscribeTimer(pubSub, wlf_disp_OnTimer);
285  }
286 
287  free(disp);
288 }
289 
290 UINT wlf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors, size_t nmonitors)
291 {
292  UINT ret = CHANNEL_RC_OK;
293  DISPLAY_CONTROL_MONITOR_LAYOUT* layouts = NULL;
294  wlfDispContext* wlfDisp = NULL;
295  rdpSettings* settings = NULL;
296 
297  WINPR_ASSERT(disp);
298  WINPR_ASSERT(monitors);
299  WINPR_ASSERT(nmonitors > 0);
300  WINPR_ASSERT(nmonitors <= UINT32_MAX);
301 
302  wlfDisp = (wlfDispContext*)disp->custom;
303  WINPR_ASSERT(wlfDisp);
304  WINPR_ASSERT(wlfDisp->wlc);
305 
306  settings = wlfDisp->wlc->common.context.settings;
307  WINPR_ASSERT(settings);
308 
309  layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
310 
311  if (!layouts)
312  return CHANNEL_RC_NO_MEMORY;
313 
314  for (size_t i = 0; i < nmonitors; i++)
315  {
316  const rdpMonitor* monitor = &monitors[i];
317  DISPLAY_CONTROL_MONITOR_LAYOUT* layout = &layouts[i];
318 
319  layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
320  layout->Left = monitor->x;
321  layout->Top = monitor->y;
322  layout->Width = WINPR_ASSERTING_INT_CAST(UINT32, monitor->width);
323  layout->Height = WINPR_ASSERTING_INT_CAST(UINT32, monitor->height);
324  layout->Orientation = ORIENTATION_LANDSCAPE;
325  layout->PhysicalWidth = monitor->attributes.physicalWidth;
326  layout->PhysicalHeight = monitor->attributes.physicalHeight;
327 
328  switch (monitor->attributes.orientation)
329  {
330  case 90:
331  layout->Orientation = ORIENTATION_PORTRAIT;
332  break;
333 
334  case 180:
335  layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
336  break;
337 
338  case 270:
339  layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
340  break;
341 
342  case 0:
343  default:
344  /* MS-RDPEDISP - 2.2.2.2.1:
345  * Orientation (4 bytes): A 32-bit unsigned integer that specifies the
346  * orientation of the monitor in degrees. Valid values are 0, 90, 180
347  * or 270
348  *
349  * So we default to ORIENTATION_LANDSCAPE
350  */
351  layout->Orientation = ORIENTATION_LANDSCAPE;
352  break;
353  }
354 
355  layout->DesktopScaleFactor =
356  freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
357  layout->DeviceScaleFactor =
358  freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
359  }
360 
361  ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, (UINT32)nmonitors, layouts);
362  free(layouts);
363  return ret;
364 }
365 
366 BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height)
367 {
368  if (!disp)
369  return FALSE;
370 
371  disp->targetWidth = width;
372  disp->targetHeight = height;
373  return wlf_disp_sendResize(disp);
374 }
375 
376 static UINT wlf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
377  UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
378 {
379  /* we're called only if dynamic resolution update is activated */
380  wlfDispContext* wlfDisp = NULL;
381  rdpSettings* settings = NULL;
382 
383  WINPR_ASSERT(disp);
384 
385  wlfDisp = (wlfDispContext*)disp->custom;
386  WINPR_ASSERT(wlfDisp);
387  WINPR_ASSERT(wlfDisp->wlc);
388 
389  settings = wlfDisp->wlc->common.context.settings;
390  WINPR_ASSERT(settings);
391 
392  WLog_DBG(TAG,
393  "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
394  " MaxMonitorAreaFactorB: %" PRIu32 "",
395  maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
396  wlfDisp->activated = TRUE;
397 
398  if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
399  return CHANNEL_RC_OK;
400 
401  WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
402  return wlf_disp_set_window_resizable(wlfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
403 }
404 
405 BOOL wlf_disp_init(wlfDispContext* wlfDisp, DispClientContext* disp)
406 {
407  rdpSettings* settings = NULL;
408 
409  if (!wlfDisp || !wlfDisp->wlc || !disp)
410  return FALSE;
411 
412  settings = wlfDisp->wlc->common.context.settings;
413 
414  if (!settings)
415  return FALSE;
416 
417  wlfDisp->disp = disp;
418  disp->custom = (void*)wlfDisp;
419 
420  if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
421  {
422  disp->DisplayControlCaps = wlf_DisplayControlCaps;
423  }
424 
425  return TRUE;
426 }
427 
428 BOOL wlf_disp_uninit(wlfDispContext* wlfDisp, DispClientContext* disp)
429 {
430  if (!wlfDisp || !disp)
431  return FALSE;
432 
433  wlfDisp->disp = NULL;
434  return TRUE;
435 }
436 
437 int wlf_list_monitors(wlfContext* wlc)
438 {
439  uint32_t nmonitors = UwacDisplayGetNbOutputs(wlc->display);
440 
441  for (uint32_t i = 0; i < nmonitors; i++)
442  {
443  const UwacOutput* monitor =
444  UwacDisplayGetOutput(wlc->display, WINPR_ASSERTING_INT_CAST(int, i));
445  UwacSize resolution;
446  UwacPosition pos;
447 
448  if (!monitor)
449  continue;
450  UwacOutputGetPosition(monitor, &pos);
451  UwacOutputGetResolution(monitor, &resolution);
452 
453  printf(" %s [%u] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, resolution.width,
454  resolution.height, pos.x, pos.y);
455  }
456 
457  return 0;
458 }
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.