FreeRDP
xf_monitor.c
1 
22 #include <freerdp/config.h>
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 
30 #include <winpr/assert.h>
31 #include <winpr/cast.h>
32 #include <winpr/crt.h>
33 
34 #include <freerdp/log.h>
35 
36 #define TAG CLIENT_TAG("x11")
37 
38 #ifdef WITH_XINERAMA
39 #include <X11/extensions/Xinerama.h>
40 #endif
41 
42 #ifdef WITH_XRANDR
43 #include <X11/extensions/Xrandr.h>
44 #include <X11/extensions/randr.h>
45 
46 #if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
47 #define USABLE_XRANDR
48 #endif
49 
50 #endif
51 
52 #include "xf_monitor.h"
53 
54 /* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
55  */
56 
57 int xf_list_monitors(xfContext* xfc)
58 {
59  Display* display = NULL;
60  int major = 0;
61  int minor = 0;
62  int nmonitors = 0;
63  display = XOpenDisplay(NULL);
64 
65  if (!display)
66  {
67  WLog_ERR(TAG, "failed to open X display");
68  return -1;
69  }
70 
71 #if defined(USABLE_XRANDR)
72 
73  if (XRRQueryExtension(display, &major, &minor) &&
74  (XRRQueryVersion(display, &major, &minor) == True) && (major * 100 + minor >= 105))
75  {
76  XRRMonitorInfo* monitors =
77  XRRGetMonitors(display, DefaultRootWindow(display), 1, &nmonitors);
78 
79  for (int i = 0; i < nmonitors; i++)
80  {
81  printf(" %s [%d] %dx%d\t+%d+%d\n", monitors[i].primary ? "*" : " ", i,
82  monitors[i].width, monitors[i].height, monitors[i].x, monitors[i].y);
83  }
84 
85  XRRFreeMonitors(monitors);
86  }
87  else
88 #endif
89 #ifdef WITH_XINERAMA
90  if (XineramaQueryExtension(display, &major, &minor))
91  {
92  if (XineramaIsActive(display))
93  {
94  XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors);
95 
96  for (int i = 0; i < nmonitors; i++)
97  {
98  printf(" %s [%d] %hdx%hd\t+%hd+%hd\n", (i == 0) ? "*" : " ", i,
99  screen[i].width, screen[i].height, screen[i].x_org, screen[i].y_org);
100  }
101 
102  XFree(screen);
103  }
104  }
105  else
106 #else
107  {
108  Screen* screen = ScreenOfDisplay(display, DefaultScreen(display));
109  printf(" * [0] %dx%d\t+0+0\n", WidthOfScreen(screen), HeightOfScreen(screen));
110  }
111 
112 #endif
113  XCloseDisplay(display);
114  return 0;
115 }
116 
117 static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id)
118 {
119  const rdpSettings* settings = NULL;
120 
121  WINPR_ASSERT(xfc);
122 
123  settings = xfc->common.context.settings;
124  WINPR_ASSERT(settings);
125 
126  const UINT32 NumMonitorIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
127  if (NumMonitorIds == 0)
128  return TRUE;
129 
130  for (UINT32 index = 0; index < NumMonitorIds; index++)
131  {
132  const UINT32* cur = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index);
133  if (cur && (*cur == id))
134  return TRUE;
135  }
136 
137  return FALSE;
138 }
139 
140 BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
141 {
142  BOOL rc = FALSE;
143  UINT32 monitor_index = 0;
144  BOOL primaryMonitorFound = FALSE;
145  VIRTUAL_SCREEN* vscreen = NULL;
146  rdpSettings* settings = NULL;
147  int mouse_x = 0;
148  int mouse_y = 0;
149  int _dummy_i = 0;
150  Window _dummy_w = 0;
151  UINT32 current_monitor = 0;
152  Screen* screen = NULL;
153 #if defined WITH_XINERAMA || defined WITH_XRANDR
154  int major = 0;
155  int minor = 0;
156 #endif
157 #if defined(USABLE_XRANDR)
158  XRRMonitorInfo* rrmonitors = NULL;
159  BOOL useXRandr = FALSE;
160 #endif
161 
162  if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->common.context.settings)
163  return FALSE;
164 
165  settings = xfc->common.context.settings;
166  vscreen = &xfc->vscreen;
167  *pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
168  *pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
169 
170  if (freerdp_settings_get_uint64(settings, FreeRDP_ParentWindowId) > 0)
171  {
172  xfc->workArea.x = 0;
173  xfc->workArea.y = 0;
174  xfc->workArea.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
175  xfc->workArea.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
176  return TRUE;
177  }
178 
179  /* get mouse location */
180  if (!XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &_dummy_w, &_dummy_w,
181  &mouse_x, &mouse_y, &_dummy_i, &_dummy_i, (void*)&_dummy_i))
182  mouse_x = mouse_y = 0;
183 
184 #if defined(USABLE_XRANDR)
185 
186  if (XRRQueryExtension(xfc->display, &major, &minor) &&
187  (XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105))
188  {
189  int nmonitors = 0;
190  rrmonitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &nmonitors);
191 
192  if ((nmonitors < 0) || (nmonitors > 16))
193  vscreen->nmonitors = 0;
194  else
195  vscreen->nmonitors = (UINT32)nmonitors;
196 
197  if (vscreen->nmonitors)
198  {
199  for (UINT32 i = 0; i < vscreen->nmonitors; i++)
200  {
201  MONITOR_INFO* cur_vscreen = &vscreen->monitors[i];
202  const XRRMonitorInfo* cur_monitor = &rrmonitors[i];
203 
204  cur_vscreen->area.left = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x);
205  cur_vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y);
206  cur_vscreen->area.right =
207  WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x + cur_monitor->width - 1);
208  cur_vscreen->area.bottom =
209  WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y + cur_monitor->height - 1);
210  cur_vscreen->primary = cur_monitor->primary > 0;
211  }
212  }
213 
214  useXRandr = TRUE;
215  }
216  else
217 #endif
218 #ifdef WITH_XINERAMA
219  if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display))
220  {
221  int nmonitors = 0;
222  XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &nmonitors);
223 
224  if ((nmonitors < 0) || (nmonitors > 16))
225  vscreen->nmonitors = 0;
226  else
227  vscreen->nmonitors = (UINT32)nmonitors;
228 
229  if (vscreen->nmonitors)
230  {
231  for (UINT32 i = 0; i < vscreen->nmonitors; i++)
232  {
233  MONITOR_INFO* monitor = &vscreen->monitors[i];
234  monitor->area.left = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].x_org);
235  monitor->area.top = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].y_org);
236  monitor->area.right = WINPR_ASSERTING_INT_CAST(
237  uint16_t, screenInfo[i].x_org + screenInfo[i].width - 1);
238  monitor->area.bottom = WINPR_ASSERTING_INT_CAST(
239  uint16_t, screenInfo[i].y_org + screenInfo[i].height - 1);
240  }
241  }
242 
243  XFree(screenInfo);
244  }
245 
246 #endif
247  xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left =
248  xfc->fullscreenMonitors.right = 0;
249 
250  /* Determine which monitor that the mouse cursor is on */
251  if (vscreen->monitors)
252  {
253  for (UINT32 i = 0; i < vscreen->nmonitors; i++)
254  {
255  const MONITOR_INFO* monitor = &vscreen->monitors[i];
256 
257  if ((mouse_x >= monitor->area.left) && (mouse_x <= monitor->area.right) &&
258  (mouse_y >= monitor->area.top) && (mouse_y <= monitor->area.bottom))
259  {
260  current_monitor = i;
261  break;
262  }
263  }
264  }
265 
266  /*
267  Even for a single monitor, we need to calculate the virtual screen to support
268  window managers that do not implement all X window state hints.
269 
270  If the user did not request multiple monitor or is using workarea
271  without remote app, we force the number of monitors be 1 so later
272  the rest of the client don't end up using more monitors than the user desires.
273  */
274  if ((!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon) &&
275  !freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors)) ||
276  (freerdp_settings_get_bool(settings, FreeRDP_Workarea) &&
277  !freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode)))
278  {
279  /* If no monitors were specified on the command-line then set the current monitor as active
280  */
281  if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0)
282  {
283  UINT32 id = current_monitor;
284  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1))
285  goto fail;
286  }
287 
288  /* Always sets number of monitors from command-line to just 1.
289  * If the monitor is invalid then we will default back to current monitor
290  * later as a fallback. So, there is no need to validate command-line entry here.
291  */
292  if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1))
293  goto fail;
294  }
295 
296  /* WORKAROUND: With Remote Application Mode - using NET_WM_WORKAREA
297  * causes issues with the ability to fully size the window vertically
298  * (the bottom of the window area is never updated). So, we just set
299  * the workArea to match the full Screen width/height.
300  */
301  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode) || !xf_GetWorkArea(xfc))
302  {
303  /*
304  if only 1 monitor is enabled, use monitor area
305  this is required in case of a screen composed of more than one monitor
306  but user did not enable multimonitor
307  */
308  if ((freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 1) &&
309  (vscreen->nmonitors > current_monitor))
310  {
311  MONITOR_INFO* monitor = vscreen->monitors + current_monitor;
312 
313  if (!monitor)
314  goto fail;
315 
316  xfc->workArea.x = monitor->area.left;
317  xfc->workArea.y = monitor->area.top;
318  xfc->workArea.width = monitor->area.right - monitor->area.left + 1;
319  xfc->workArea.height = monitor->area.bottom - monitor->area.top + 1;
320  }
321  else
322  {
323  xfc->workArea.x = 0;
324  xfc->workArea.y = 0;
325  xfc->workArea.width = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
326  xfc->workArea.height = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
327  }
328  }
329 
330  if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
331  {
332  *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
333  *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
334  }
335  else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
336  {
337  *pMaxWidth = xfc->workArea.width;
338  *pMaxHeight = xfc->workArea.height;
339  }
340  else if (freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen))
341  {
342  /* If we have specific monitor information then limit the PercentScreen value
343  * to only affect the current monitor vs. the entire desktop
344  */
345  if (vscreen->nmonitors > 0)
346  {
347  if (!vscreen->monitors)
348  goto fail;
349 
350  const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
351  const RECTANGLE_16* area = &vmonitor->area;
352 
353  *pMaxWidth = area->right - area->left + 1;
354  *pMaxHeight = area->bottom - area->top + 1;
355 
356  if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
357  *pMaxWidth = ((area->right - area->left + 1) *
358  freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
359  100;
360 
361  if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
362  *pMaxHeight = ((area->bottom - area->top + 1) *
363  freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
364  100;
365  }
366  else
367  {
368  *pMaxWidth = xfc->workArea.width;
369  *pMaxHeight = xfc->workArea.height;
370 
371  if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
372  *pMaxWidth = (xfc->workArea.width *
373  freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
374  100;
375 
376  if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
377  *pMaxHeight = (xfc->workArea.height *
378  freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
379  100;
380  }
381  }
382  else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) &&
383  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight))
384  {
385  *pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
386  *pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
387  }
388 
389  /* Create array of all active monitors by taking into account monitors requested on the
390  * command-line */
391  int nmonitors = 0;
392  {
393  UINT32 nr = 0;
394 
395  {
396  const UINT32* ids = freerdp_settings_get_pointer(settings, FreeRDP_MonitorIds);
397  if (ids)
398  nr = *ids;
399  }
400  for (UINT32 i = 0; i < vscreen->nmonitors; i++)
401  {
402  MONITOR_ATTRIBUTES* attrs = NULL;
403 
404  if (!xf_is_monitor_id_active(xfc, i))
405  continue;
406 
407  if (!vscreen->monitors)
408  goto fail;
409 
410  rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
411  settings, FreeRDP_MonitorDefArray, WINPR_ASSERTING_INT_CAST(size_t, nmonitors));
412  monitor->x =
413  WINPR_ASSERTING_INT_CAST(
414  int32_t, vscreen->monitors[i].area.left*(
415  freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
416  ? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
417  : 100)) /
418  100;
419  monitor->y =
420  WINPR_ASSERTING_INT_CAST(
421  int32_t, vscreen->monitors[i].area.top*(
422  freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
423  ? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
424  : 100)) /
425  100;
426  monitor->width =
427  WINPR_ASSERTING_INT_CAST(
428  int32_t,
429  (vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1) *
430  (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
431  ? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
432  : 100)) /
433  100;
434  monitor->height =
435  WINPR_ASSERTING_INT_CAST(
436  int32_t,
437  (vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1) *
438  (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
439  ? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
440  : 100)) /
441  100;
442  monitor->orig_screen = i;
443 #ifdef USABLE_XRANDR
444 
445  if (useXRandr && rrmonitors)
446  {
447  Rotation rot = 0;
448  Rotation ret = 0;
449  attrs = &monitor->attributes;
450  attrs->physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mwidth);
451  attrs->physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mheight);
452  ret = XRRRotations(xfc->display, WINPR_ASSERTING_INT_CAST(int, i), &rot);
453  attrs->orientation = ret;
454  }
455 
456 #endif
457 
458  if (i == nr)
459  {
460  monitor->is_primary = TRUE;
461  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX,
462  WINPR_ASSERTING_INT_CAST(uint32_t, monitor->x)))
463  goto fail;
464  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY,
465  WINPR_ASSERTING_INT_CAST(uint32_t, monitor->y)))
466  goto fail;
467  primaryMonitorFound = TRUE;
468  }
469 
470  nmonitors++;
471  }
472  }
473 
474  /* If no monitor is active(bogus command-line monitor specification) - then lets try to fallback
475  * to go fullscreen on the current monitor only */
476  if (nmonitors == 0 && vscreen->nmonitors > 0)
477  {
478  if (!vscreen->monitors)
479  goto fail;
480 
481  const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
482  const RECTANGLE_16* area = &vmonitor->area;
483 
484  const INT32 width = area->right - area->left + 1;
485  const INT32 height = area->bottom - area->top + 1;
486  const INT32 maxw =
487  ((width < 0) || ((UINT32)width < *pMaxWidth)) ? width : (INT32)*pMaxWidth;
488  const INT32 maxh =
489  ((height < 0) || ((UINT32)height < *pMaxHeight)) ? width : (INT32)*pMaxHeight;
490 
491  rdpMonitor* monitor =
492  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, 0);
493  if (!monitor)
494  goto fail;
495 
496  monitor->x = area->left;
497  monitor->y = area->top;
498  monitor->width = maxw;
499  monitor->height = maxh;
500  monitor->orig_screen = current_monitor;
501  nmonitors = 1;
502  }
503 
504  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount,
505  WINPR_ASSERTING_INT_CAST(uint32_t, nmonitors)))
506  goto fail;
507 
508  /* If we have specific monitor information */
509  if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0)
510  {
511  const rdpMonitor* cmonitor =
512  freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, 0);
513  if (!cmonitor)
514  goto fail;
515 
516  /* Initialize bounding rectangle for all monitors */
517  int vX = cmonitor->x;
518  int vY = cmonitor->y;
519  int vR = vX + cmonitor->width;
520  int vB = vY + cmonitor->height;
521  xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom =
522  xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = cmonitor->orig_screen;
523 
524  /* Calculate bounding rectangle around all monitors to be used AND
525  * also set the Xinerama indices which define left/top/right/bottom monitors.
526  */
527  for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
528  {
529  rdpMonitor* monitor =
530  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
531 
532  /* does the same as gdk_rectangle_union */
533  int destX = MIN(vX, monitor->x);
534  int destY = MIN(vY, monitor->y);
535  int destR = MAX(vR, monitor->x + monitor->width);
536  int destB = MAX(vB, monitor->y + monitor->height);
537 
538  if (vX != destX)
539  xfc->fullscreenMonitors.left = monitor->orig_screen;
540 
541  if (vY != destY)
542  xfc->fullscreenMonitors.top = monitor->orig_screen;
543 
544  if (vR != destR)
545  xfc->fullscreenMonitors.right = monitor->orig_screen;
546 
547  if (vB != destB)
548  xfc->fullscreenMonitors.bottom = monitor->orig_screen;
549 
550  const UINT32 ps = freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen);
551  WINPR_ASSERT(ps <= 100);
552 
553  const int psuw =
554  freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth) ? (int)ps : 100;
555  const int psuh =
556  freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight) ? (int)ps : 100;
557  vX = (destX * psuw) / 100;
558  vY = (destY * psuh) / 100;
559  vR = (destR * psuw) / 100;
560  vB = (destB * psuh) / 100;
561  }
562 
563  vscreen->area.left = 0;
564  const int r = vR - vX - 1;
565  vscreen->area.right = WINPR_ASSERTING_INT_CAST(UINT16, r);
566  vscreen->area.top = 0;
567  const int b = vB - vY - 1;
568  vscreen->area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, b);
569 
570  if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
571  {
572  vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, xfc->workArea.y);
573  vscreen->area.bottom =
574  WINPR_ASSERTING_INT_CAST(UINT16, xfc->workArea.height + xfc->workArea.y - 1);
575  }
576 
577  if (!primaryMonitorFound)
578  {
579  /* If we have a command line setting we should use it */
580  if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) > 0)
581  {
582  /* The first monitor is the first in the setting which should be used */
583  UINT32* ids =
584  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorIds, 0);
585  if (ids)
586  monitor_index = *ids;
587  }
588  else
589  {
590  /* This is the same as when we would trust the Xinerama results..
591  and set the monitor index to zero.
592  The monitor listed with /list:monitor on index zero is always the primary
593  */
594  screen = DefaultScreenOfDisplay(xfc->display);
595  monitor_index = WINPR_ASSERTING_INT_CAST(uint32_t, XScreenNumberOfScreen(screen));
596  }
597 
598  UINT32 j = monitor_index;
599  rdpMonitor* pmonitor =
600  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, j);
601 
602  /* If the "default" monitor is not 0,0 use it */
603  if ((pmonitor->x != 0) || (pmonitor->y != 0))
604  {
605  pmonitor->is_primary = TRUE;
606  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX,
607  WINPR_ASSERTING_INT_CAST(uint32_t, pmonitor->x)))
608  goto fail;
609  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY,
610  WINPR_ASSERTING_INT_CAST(uint32_t, pmonitor->y)))
611  goto fail;
612  }
613  else
614  {
615  /* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a
616  * fallback*/
617  for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
618  i++)
619  {
620  rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
621  settings, FreeRDP_MonitorDefArray, i);
622  if (!primaryMonitorFound && monitor->x == 0 && monitor->y == 0)
623  {
624  monitor->is_primary = TRUE;
626  settings, FreeRDP_MonitorLocalShiftX,
627  WINPR_ASSERTING_INT_CAST(uint32_t, monitor->x)))
628  goto fail;
630  settings, FreeRDP_MonitorLocalShiftY,
631  WINPR_ASSERTING_INT_CAST(uint32_t, monitor->y)))
632  goto fail;
633  primaryMonitorFound = TRUE;
634  }
635  }
636  }
637  }
638 
639  /* Subtract monitor shift from monitor variables for server-side use.
640  * We maintain monitor shift value as Window requires the primary monitor to have a
641  * coordinate of 0,0 In some X configurations, no monitor may have a coordinate of 0,0. This
642  * can also be happen if the user requests specific monitors from the command-line as well.
643  * So, we make sure to translate our primary monitor's upper-left corner to 0,0 on the
644  * server.
645  */
646  for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
647  {
648  rdpMonitor* monitor =
649  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
650  monitor->x =
651  monitor->x -
652  WINPR_ASSERTING_INT_CAST(
653  int32_t, freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftX));
654  monitor->y =
655  monitor->y -
656  WINPR_ASSERTING_INT_CAST(
657  int32_t, freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftY));
658  }
659 
660  /* Set the desktop width and height according to the bounding rectangle around the active
661  * monitors */
662  *pMaxWidth = MIN(*pMaxWidth, (UINT32)vscreen->area.right - vscreen->area.left + 1);
663  *pMaxHeight = MIN(*pMaxHeight, (UINT32)vscreen->area.bottom - vscreen->area.top + 1);
664  }
665 
666  /* some 2008 server freeze at logon if we announce support for monitor layout PDU with
667  * #monitors < 2. So let's announce it only if we have more than 1 monitor.
668  */
669  if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 1)
670  {
671  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
672  goto fail;
673  }
674 
675  rc = TRUE;
676 fail:
677 #ifdef USABLE_XRANDR
678 
679  if (rrmonitors)
680  XRRFreeMonitors(rrmonitors);
681 
682 #endif
683  return rc;
684 }
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 const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
FREERDP_API UINT64 freerdp_settings_get_uint64(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt64 id)
Returns a UINT64 settings value.
FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.