22 #include <freerdp/config.h>
28 #include <X11/Xutil.h>
30 #include <winpr/assert.h>
31 #include <winpr/cast.h>
32 #include <winpr/crt.h>
34 #include <freerdp/log.h>
36 #define TAG CLIENT_TAG("x11")
39 #include <X11/extensions/Xinerama.h>
43 #include <X11/extensions/Xrandr.h>
44 #include <X11/extensions/randr.h>
46 #if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
52 #include "xf_monitor.h"
57 int xf_list_monitors(xfContext* xfc)
59 Display* display = NULL;
63 display = XOpenDisplay(NULL);
67 WLog_ERR(TAG,
"failed to open X display");
71 #if defined(USABLE_XRANDR)
73 if (XRRQueryExtension(display, &major, &minor) &&
74 (XRRQueryVersion(display, &major, &minor) == True) && (major * 100 + minor >= 105))
76 XRRMonitorInfo* monitors =
77 XRRGetMonitors(display, DefaultRootWindow(display), 1, &nmonitors);
79 for (
int i = 0; i < nmonitors; i++)
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);
85 XRRFreeMonitors(monitors);
90 if (XineramaQueryExtension(display, &major, &minor))
92 if (XineramaIsActive(display))
94 XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors);
96 for (
int i = 0; i < nmonitors; i++)
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);
108 Screen* screen = ScreenOfDisplay(display, DefaultScreen(display));
109 printf(
" * [0] %dx%d\t+0+0\n", WidthOfScreen(screen), HeightOfScreen(screen));
113 XCloseDisplay(display);
117 static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32
id)
119 const rdpSettings* settings = NULL;
123 settings = xfc->common.context.settings;
124 WINPR_ASSERT(settings);
127 if (NumMonitorIds == 0)
130 for (UINT32 index = 0; index < NumMonitorIds; index++)
132 const UINT32* cur = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index);
133 if (cur && (*cur ==
id))
140 BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
143 UINT32 monitor_index = 0;
144 BOOL primaryMonitorFound = FALSE;
145 VIRTUAL_SCREEN* vscreen = NULL;
146 rdpSettings* settings = NULL;
151 UINT32 current_monitor = 0;
152 Screen* screen = NULL;
153 #if defined WITH_XINERAMA || defined WITH_XRANDR
157 #if defined(USABLE_XRANDR)
158 XRRMonitorInfo* rrmonitors = NULL;
159 BOOL useXRandr = FALSE;
162 if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->common.context.settings)
165 settings = xfc->common.context.settings;
166 vscreen = &xfc->vscreen;
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;
184 #if defined(USABLE_XRANDR)
186 if (XRRQueryExtension(xfc->display, &major, &minor) &&
187 (XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105))
190 rrmonitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &nmonitors);
192 if ((nmonitors < 0) || (nmonitors > 16))
193 vscreen->nmonitors = 0;
195 vscreen->nmonitors = (UINT32)nmonitors;
197 if (vscreen->nmonitors)
199 for (UINT32 i = 0; i < vscreen->nmonitors; i++)
201 MONITOR_INFO* cur_vscreen = &vscreen->monitors[i];
202 const XRRMonitorInfo* cur_monitor = &rrmonitors[i];
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;
219 if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display))
222 XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &nmonitors);
224 if ((nmonitors < 0) || (nmonitors > 16))
225 vscreen->nmonitors = 0;
227 vscreen->nmonitors = (UINT32)nmonitors;
229 if (vscreen->nmonitors)
231 for (UINT32 i = 0; i < vscreen->nmonitors; i++)
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);
247 xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left =
248 xfc->fullscreenMonitors.right = 0;
251 if (vscreen->monitors)
253 for (UINT32 i = 0; i < vscreen->nmonitors; i++)
255 const MONITOR_INFO* monitor = &vscreen->monitors[i];
257 if ((mouse_x >= monitor->area.left) && (mouse_x <= monitor->area.right) &&
258 (mouse_y >= monitor->area.top) && (mouse_y <= monitor->area.bottom))
283 UINT32
id = current_monitor;
309 (vscreen->nmonitors > current_monitor))
311 MONITOR_INFO* monitor = vscreen->monitors + current_monitor;
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;
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));
332 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
333 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
337 *pMaxWidth = xfc->workArea.width;
338 *pMaxHeight = xfc->workArea.height;
345 if (vscreen->nmonitors > 0)
347 if (!vscreen->monitors)
350 const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
353 *pMaxWidth = area->right - area->left + 1;
354 *pMaxHeight = area->bottom - area->top + 1;
357 *pMaxWidth = ((area->right - area->left + 1) *
362 *pMaxHeight = ((area->bottom - area->top + 1) *
368 *pMaxWidth = xfc->workArea.width;
369 *pMaxHeight = xfc->workArea.height;
372 *pMaxWidth = (xfc->workArea.width *
377 *pMaxHeight = (xfc->workArea.height *
400 for (UINT32 i = 0; i < vscreen->nmonitors; i++)
404 if (!xf_is_monitor_id_active(xfc, i))
407 if (!vscreen->monitors)
410 rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
411 settings, FreeRDP_MonitorDefArray, WINPR_ASSERTING_INT_CAST(
size_t, nmonitors));
413 WINPR_ASSERTING_INT_CAST(
414 int32_t, vscreen->monitors[i].area.left*(
420 WINPR_ASSERTING_INT_CAST(
421 int32_t, vscreen->monitors[i].area.top*(
427 WINPR_ASSERTING_INT_CAST(
429 (vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1) *
435 WINPR_ASSERTING_INT_CAST(
437 (vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1) *
442 monitor->orig_screen = i;
445 if (useXRandr && rrmonitors)
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;
460 monitor->is_primary = TRUE;
462 WINPR_ASSERTING_INT_CAST(uint32_t, monitor->x)))
465 WINPR_ASSERTING_INT_CAST(uint32_t, monitor->y)))
467 primaryMonitorFound = TRUE;
476 if (nmonitors == 0 && vscreen->nmonitors > 0)
478 if (!vscreen->monitors)
481 const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
484 const INT32 width = area->right - area->left + 1;
485 const INT32 height = area->bottom - area->top + 1;
487 ((width < 0) || ((UINT32)width < *pMaxWidth)) ? width : (INT32)*pMaxWidth;
489 ((height < 0) || ((UINT32)height < *pMaxHeight)) ? width : (INT32)*pMaxHeight;
492 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, 0);
496 monitor->x = area->left;
497 monitor->y = area->top;
498 monitor->width = maxw;
499 monitor->height = maxh;
500 monitor->orig_screen = current_monitor;
505 WINPR_ASSERTING_INT_CAST(uint32_t, nmonitors)))
512 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, 0);
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;
530 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
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);
539 xfc->fullscreenMonitors.left = monitor->orig_screen;
542 xfc->fullscreenMonitors.top = monitor->orig_screen;
545 xfc->fullscreenMonitors.right = monitor->orig_screen;
548 xfc->fullscreenMonitors.bottom = monitor->orig_screen;
551 WINPR_ASSERT(ps <= 100);
557 vX = (destX * psuw) / 100;
558 vY = (destY * psuh) / 100;
559 vR = (destR * psuw) / 100;
560 vB = (destB * psuh) / 100;
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);
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);
577 if (!primaryMonitorFound)
584 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorIds, 0);
586 monitor_index = *ids;
594 screen = DefaultScreenOfDisplay(xfc->display);
595 monitor_index = WINPR_ASSERTING_INT_CAST(uint32_t, XScreenNumberOfScreen(screen));
598 UINT32 j = monitor_index;
600 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, j);
603 if ((pmonitor->x != 0) || (pmonitor->y != 0))
605 pmonitor->is_primary = TRUE;
607 WINPR_ASSERTING_INT_CAST(uint32_t, pmonitor->x)))
610 WINPR_ASSERTING_INT_CAST(uint32_t, pmonitor->y)))
620 rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
621 settings, FreeRDP_MonitorDefArray, i);
622 if (!primaryMonitorFound && monitor->x == 0 && monitor->y == 0)
624 monitor->is_primary = TRUE;
626 settings, FreeRDP_MonitorLocalShiftX,
627 WINPR_ASSERTING_INT_CAST(uint32_t, monitor->x)))
630 settings, FreeRDP_MonitorLocalShiftY,
631 WINPR_ASSERTING_INT_CAST(uint32_t, monitor->y)))
633 primaryMonitorFound = TRUE;
649 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
652 WINPR_ASSERTING_INT_CAST(
656 WINPR_ASSERTING_INT_CAST(
662 *pMaxWidth = MIN(*pMaxWidth, (UINT32)vscreen->area.right - vscreen->area.left + 1);
663 *pMaxHeight = MIN(*pMaxHeight, (UINT32)vscreen->area.bottom - vscreen->area.top + 1);
680 XRRFreeMonitors(rrmonitors);
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.