FreeRDP
wlf_disp.c
1 
21 #include <winpr/sysinfo.h>
22 
23 #include "wlf_disp.h"
24 
25 #define TAG CLIENT_TAG("wayland.disp")
26 
27 #define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
28 
29 struct s_wlfDispContext
30 {
31  wlfContext* wlc;
32  DispClientContext* disp;
33  BOOL haveXRandr;
34  int eventBase, errorBase;
35  int lastSentWidth, lastSentHeight;
36  UINT64 lastSentDate;
37  int targetWidth, targetHeight;
38  BOOL activated;
39  BOOL waitingResize;
40  BOOL fullscreen;
41  UINT16 lastSentDesktopOrientation;
42  UINT32 lastSentDesktopScaleFactor;
43  UINT32 lastSentDeviceScaleFactor;
44 };
45 
46 static UINT wlf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
47  size_t nmonitors);
48 
49 static BOOL wlf_disp_settings_changed(wlfDispContext* wlfDisp)
50 {
51  rdpSettings* settings = NULL;
52 
53  WINPR_ASSERT(wlfDisp);
54  WINPR_ASSERT(wlfDisp->wlc);
55 
56  settings = wlfDisp->wlc->common.context.settings;
57  WINPR_ASSERT(settings);
58 
59  if (wlfDisp->lastSentWidth != wlfDisp->targetWidth)
60  return TRUE;
61 
62  if (wlfDisp->lastSentHeight != wlfDisp->targetHeight)
63  return TRUE;
64 
65  if (wlfDisp->lastSentDesktopOrientation !=
66  freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation))
67  return TRUE;
68 
69  if (wlfDisp->lastSentDesktopScaleFactor !=
70  freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor))
71  return TRUE;
72 
73  if (wlfDisp->lastSentDeviceScaleFactor !=
74  freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor))
75  return TRUE;
76 
77  if (wlfDisp->fullscreen != wlfDisp->wlc->fullscreen)
78  return TRUE;
79 
80  return FALSE;
81 }
82 
83 static BOOL wlf_update_last_sent(wlfDispContext* wlfDisp)
84 {
85  rdpSettings* settings = NULL;
86 
87  WINPR_ASSERT(wlfDisp);
88  WINPR_ASSERT(wlfDisp->wlc);
89 
90  settings = wlfDisp->wlc->common.context.settings;
91  WINPR_ASSERT(settings);
92 
93  wlfDisp->lastSentWidth = wlfDisp->targetWidth;
94  wlfDisp->lastSentHeight = wlfDisp->targetHeight;
95  wlfDisp->lastSentDesktopOrientation =
96  freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
97  wlfDisp->lastSentDesktopScaleFactor =
98  freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
99  wlfDisp->lastSentDeviceScaleFactor =
100  freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
101  wlfDisp->fullscreen = wlfDisp->wlc->fullscreen;
102  return TRUE;
103 }
104 
105 static BOOL wlf_disp_sendResize(wlfDispContext* wlfDisp)
106 {
108  wlfContext* wlc = NULL;
109  rdpSettings* settings = NULL;
110 
111  if (!wlfDisp || !wlfDisp->wlc)
112  return FALSE;
113 
114  wlc = wlfDisp->wlc;
115  settings = wlc->common.context.settings;
116 
117  if (!settings)
118  return FALSE;
119 
120  if (!wlfDisp->activated || !wlfDisp->disp)
121  return TRUE;
122 
123  if (GetTickCount64() - wlfDisp->lastSentDate < RESIZE_MIN_DELAY)
124  return TRUE;
125 
126  wlfDisp->lastSentDate = GetTickCount64();
127 
128  if (!wlf_disp_settings_changed(wlfDisp))
129  return TRUE;
130 
131  /* TODO: Multimonitor support for wayland
132  if (wlc->fullscreen && (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount > 0))
133  {
134  if (wlf_disp_sendLayout(wlfDisp->disp, setings->MonitorDefArray,
135  freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) !=
136  CHANNEL_RC_OK) return FALSE;
137  }
138  else
139  */
140  {
141  wlfDisp->waitingResize = TRUE;
142  layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
143  layout.Top = layout.Left = 0;
144  layout.Width = wlfDisp->targetWidth;
145  layout.Height = wlfDisp->targetHeight;
146  layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
147  layout.DesktopScaleFactor =
148  freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
149  layout.DeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
150  layout.PhysicalWidth = wlfDisp->targetWidth;
151  layout.PhysicalHeight = wlfDisp->targetHeight;
152 
153  if (IFCALLRESULT(CHANNEL_RC_OK, wlfDisp->disp->SendMonitorLayout, wlfDisp->disp, 1,
154  &layout) != CHANNEL_RC_OK)
155  return FALSE;
156  }
157  return wlf_update_last_sent(wlfDisp);
158 }
159 
160 static BOOL wlf_disp_set_window_resizable(wlfDispContext* wlfDisp)
161 {
162 #if 0 // TODO
163 #endif
164  return TRUE;
165 }
166 
167 static 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 
189 static 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 
211 static 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 
230 static 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 
246 wlfDispContext* 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  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
265  ret->lastSentHeight = ret->targetHeight =
266  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 
273 void 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 
289 UINT 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 = monitor->width;
322  layout->Height = 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 
365 BOOL 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 
375 static 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 
404 BOOL 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 
427 BOOL 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 
436 int 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 = UwacDisplayGetOutput(wlc->display, i);
443  UwacSize resolution;
444  UwacPosition pos;
445 
446  if (!monitor)
447  continue;
448  UwacOutputGetPosition(monitor, &pos);
449  UwacOutputGetResolution(monitor, &resolution);
450 
451  printf(" %s [%u] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, resolution.width,
452  resolution.height, pos.x, pos.y);
453  }
454 
455  return 0;
456 }
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.