FreeRDP/client/X11/xf_monitor.c

655 lines
21 KiB
C
Raw Normal View History

/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 Monitor Handling
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2017 David Fort <contact@hardening-consulting.com>
* Copyright 2018 Kai Harms <kharms@rangee.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <winpr/assert.h>
#include <winpr/crt.h>
2014-09-12 19:13:01 +04:00
#include <freerdp/log.h>
#define TAG CLIENT_TAG("x11")
#ifdef WITH_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
#ifdef WITH_XRANDR
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/randr.h>
#if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
2019-11-06 17:24:51 +03:00
#define USABLE_XRANDR
#endif
#endif
#include "xf_monitor.h"
2019-11-06 17:24:51 +03:00
/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
*/
int xf_list_monitors(xfContext* xfc)
2013-04-29 01:10:43 +04:00
{
Display* display = NULL;
int major = 0;
int minor = 0;
int nmonitors = 0;
display = XOpenDisplay(NULL);
2018-01-22 17:45:27 +03:00
if (!display)
{
WLog_ERR(TAG, "failed to open X display");
return -1;
}
2013-04-29 01:10:43 +04:00
#if defined(USABLE_XRANDR)
2018-01-22 17:45:27 +03:00
2023-11-25 19:23:19 +03:00
if (XRRQueryExtension(display, &major, &minor) &&
(XRRQueryVersion(display, &major, &minor) == True) && (major * 100 + minor >= 105))
{
2019-11-06 17:24:51 +03:00
XRRMonitorInfo* monitors =
2023-11-25 19:23:19 +03:00
XRRGetMonitors(display, DefaultRootWindow(display), 1, &nmonitors);
for (int i = 0; i < nmonitors; i++)
{
2019-11-06 17:24:51 +03:00
printf(" %s [%d] %dx%d\t+%d+%d\n", monitors[i].primary ? "*" : " ", i,
monitors[i].width, monitors[i].height, monitors[i].x, monitors[i].y);
}
2018-01-22 17:45:27 +03:00
XRRFreeMonitors(monitors);
2018-01-22 17:45:27 +03:00
}
else
#endif
#ifdef WITH_XINERAMA
2019-11-06 17:24:51 +03:00
if (XineramaQueryExtension(display, &major, &minor))
{
if (XineramaIsActive(display))
2013-04-29 01:10:43 +04:00
{
2019-11-06 17:24:51 +03:00
XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors);
2013-04-29 01:10:43 +04:00
for (int i = 0; i < nmonitors; i++)
2019-11-06 17:24:51 +03:00
{
printf(" %s [%d] %hdx%hd\t+%hd+%hd\n", (i == 0) ? "*" : " ", i,
screen[i].width, screen[i].height, screen[i].x_org, screen[i].y_org);
2018-01-22 17:45:27 +03:00
}
2019-11-06 17:24:51 +03:00
XFree(screen);
2018-01-22 17:45:27 +03:00
}
2019-11-06 17:24:51 +03:00
}
else
2013-04-29 01:10:43 +04:00
#else
{
Screen* screen = ScreenOfDisplay(display, DefaultScreen(display));
printf(" * [0] %dx%d\t+0+0\n", WidthOfScreen(screen), HeightOfScreen(screen));
}
2015-02-10 23:15:30 +03:00
2018-01-22 17:45:27 +03:00
#endif
2019-11-06 17:24:51 +03:00
XCloseDisplay(display);
2013-04-29 01:10:43 +04:00
return 0;
}
static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id)
{
const rdpSettings* settings = NULL;
WINPR_ASSERT(xfc);
settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
2015-02-10 23:15:30 +03:00
2023-10-13 10:48:44 +03:00
const UINT32 NumMonitorIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
if (NumMonitorIds == 0)
2015-02-10 23:15:30 +03:00
return TRUE;
for (UINT32 index = 0; index < NumMonitorIds; index++)
2015-02-10 23:15:30 +03:00
{
2023-10-13 10:48:44 +03:00
const UINT32* cur = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index);
if (cur && (*cur == id))
2015-02-10 23:15:30 +03:00
return TRUE;
}
return FALSE;
}
BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
2015-02-10 23:15:30 +03:00
{
2021-09-13 09:58:26 +03:00
BOOL rc = FALSE;
2023-10-13 10:48:44 +03:00
UINT32 monitor_index = 0;
BOOL primaryMonitorFound = FALSE;
2022-01-10 18:55:48 +03:00
VIRTUAL_SCREEN* vscreen = NULL;
rdpSettings* settings = NULL;
int mouse_x = 0;
int mouse_y = 0;
int _dummy_i = 0;
2022-01-10 18:55:48 +03:00
Window _dummy_w = 0;
2024-09-04 10:55:55 +03:00
UINT32 current_monitor = 0;
2022-01-10 18:55:48 +03:00
Screen* screen = NULL;
#if defined WITH_XINERAMA || defined WITH_XRANDR
int major = 0;
int minor = 0;
#endif
#if defined(USABLE_XRANDR)
2018-01-22 17:45:27 +03:00
XRRMonitorInfo* rrmonitors = NULL;
BOOL useXRandr = FALSE;
#endif
2019-02-07 16:40:36 +03:00
if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->common.context.settings)
return FALSE;
settings = xfc->common.context.settings;
vscreen = &xfc->vscreen;
2023-10-13 10:48:44 +03:00
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_uint64(settings, FreeRDP_ParentWindowId) > 0)
{
xfc->workArea.x = 0;
xfc->workArea.y = 0;
2023-10-13 10:48:44 +03:00
xfc->workArea.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
xfc->workArea.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
return TRUE;
}
/* get mouse location */
2019-11-06 17:24:51 +03:00
if (!XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &_dummy_w, &_dummy_w,
&mouse_x, &mouse_y, &_dummy_i, &_dummy_i, (void*)&_dummy_i))
mouse_x = mouse_y = 0;
#if defined(USABLE_XRANDR)
2018-01-22 17:45:27 +03:00
if (XRRQueryExtension(xfc->display, &major, &minor) &&
2019-11-06 17:24:51 +03:00
(XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105))
{
int nmonitors = 0;
rrmonitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &nmonitors);
if ((nmonitors < 0) || (nmonitors > 16))
vscreen->nmonitors = 0;
else
vscreen->nmonitors = (UINT32)nmonitors;
if (vscreen->nmonitors)
{
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
{
2021-07-29 11:07:04 +03:00
MONITOR_INFO* cur_vscreen = &vscreen->monitors[i];
2021-09-13 09:58:26 +03:00
const XRRMonitorInfo* cur_monitor = &rrmonitors[i];
2021-07-29 11:07:04 +03:00
cur_vscreen->area.left = cur_monitor->x;
cur_vscreen->area.top = cur_monitor->y;
cur_vscreen->area.right = cur_monitor->x + cur_monitor->width - 1;
cur_vscreen->area.bottom = cur_monitor->y + cur_monitor->height - 1;
cur_vscreen->primary = cur_monitor->primary > 0;
}
}
2018-01-22 17:45:27 +03:00
useXRandr = TRUE;
2018-01-22 17:45:27 +03:00
}
else
#endif
#ifdef WITH_XINERAMA
2019-11-06 17:24:51 +03:00
if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display))
{
int nmonitors = 0;
XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &nmonitors);
if ((nmonitors < 0) || (nmonitors > 16))
2019-11-06 17:24:51 +03:00
vscreen->nmonitors = 0;
else
vscreen->nmonitors = (UINT32)nmonitors;
2019-11-06 17:24:51 +03:00
if (vscreen->nmonitors)
{
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
2019-11-06 17:24:51 +03:00
{
MONITOR_INFO* monitor = &vscreen->monitors[i];
monitor->area.left = screenInfo[i].x_org;
monitor->area.top = screenInfo[i].y_org;
monitor->area.right = screenInfo[i].x_org + screenInfo[i].width - 1;
monitor->area.bottom = screenInfo[i].y_org + screenInfo[i].height - 1;
}
}
2019-11-06 17:24:51 +03:00
XFree(screenInfo);
}
2016-08-03 15:16:20 +03:00
#endif
2019-11-06 17:24:51 +03:00
xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left =
xfc->fullscreenMonitors.right = 0;
/* Determine which monitor that the mouse cursor is on */
if (vscreen->monitors)
{
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
{
const MONITOR_INFO* monitor = &vscreen->monitors[i];
if ((mouse_x >= monitor->area.left) && (mouse_x <= monitor->area.right) &&
(mouse_y >= monitor->area.top) && (mouse_y <= monitor->area.bottom))
{
current_monitor = i;
break;
}
}
}
/*
Even for a single monitor, we need to calculate the virtual screen to support
window managers that do not implement all X window state hints.
If the user did not request multiple monitor or is using workarea
without remote app, we force the number of monitors be 1 so later
the rest of the client don't end up using more monitors than the user desires.
*/
2023-10-13 10:48:44 +03:00
if ((!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon) &&
!freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors)) ||
(freerdp_settings_get_bool(settings, FreeRDP_Workarea) &&
!freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode)))
{
2019-11-06 17:24:51 +03:00
/* If no monitors were specified on the command-line then set the current monitor as active
*/
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0)
{
UINT32 id = current_monitor;
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1))
2021-09-13 09:58:26 +03:00
goto fail;
}
/* Always sets number of monitors from command-line to just 1.
* If the monitor is invalid then we will default back to current monitor
* later as a fallback. So, there is no need to validate command-line entry here.
*/
2023-10-13 10:48:44 +03:00
if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1))
goto fail;
}
/* WORKAROUND: With Remote Application Mode - using NET_WM_WORKAREA
2016-08-03 15:16:20 +03:00
* causes issues with the ability to fully size the window vertically
* (the bottom of the window area is never updated). So, we just set
* the workArea to match the full Screen width/height.
*/
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode) || !xf_GetWorkArea(xfc))
{
/*
if only 1 monitor is enabled, use monitor area
this is required in case of a screen composed of more than one monitor
but user did not enable multimonitor
*/
2023-10-13 10:48:44 +03:00
if ((freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 1) &&
(vscreen->nmonitors > current_monitor))
{
2021-09-13 09:58:26 +03:00
MONITOR_INFO* monitor = vscreen->monitors + current_monitor;
2019-02-07 16:40:36 +03:00
if (!monitor)
2021-09-13 09:58:26 +03:00
goto fail;
xfc->workArea.x = monitor->area.left;
xfc->workArea.y = monitor->area.top;
xfc->workArea.width = monitor->area.right - monitor->area.left + 1;
xfc->workArea.height = monitor->area.bottom - monitor->area.top + 1;
}
else
{
xfc->workArea.x = 0;
xfc->workArea.y = 0;
xfc->workArea.width = WidthOfScreen(xfc->screen);
xfc->workArea.height = HeightOfScreen(xfc->screen);
}
}
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
{
*pMaxWidth = WidthOfScreen(xfc->screen);
*pMaxHeight = HeightOfScreen(xfc->screen);
}
2023-10-13 10:48:44 +03:00
else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
{
*pMaxWidth = xfc->workArea.width;
*pMaxHeight = xfc->workArea.height;
}
2023-10-13 10:48:44 +03:00
else if (freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen))
{
/* If we have specific monitor information then limit the PercentScreen value
* to only affect the current monitor vs. the entire desktop
*/
if (vscreen->nmonitors > 0)
{
if (!vscreen->monitors)
2021-09-13 09:58:26 +03:00
goto fail;
*pMaxWidth = vscreen->monitors[current_monitor].area.right -
vscreen->monitors[current_monitor].area.left + 1;
*pMaxHeight = vscreen->monitors[current_monitor].area.bottom -
vscreen->monitors[current_monitor].area.top + 1;
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
*pMaxWidth = ((vscreen->monitors[current_monitor].area.right -
2019-11-06 17:24:51 +03:00
vscreen->monitors[current_monitor].area.left + 1) *
2023-10-13 10:48:44 +03:00
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
100;
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
*pMaxHeight = ((vscreen->monitors[current_monitor].area.bottom -
2019-11-06 17:24:51 +03:00
vscreen->monitors[current_monitor].area.top + 1) *
2023-10-13 10:48:44 +03:00
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
100;
}
else
{
*pMaxWidth = xfc->workArea.width;
*pMaxHeight = xfc->workArea.height;
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
*pMaxWidth = (xfc->workArea.width *
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
100;
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
*pMaxHeight = (xfc->workArea.height *
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
100;
}
}
2023-10-13 10:48:44 +03:00
else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) &&
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight))
{
2023-10-13 10:48:44 +03:00
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
}
2019-11-06 17:24:51 +03:00
/* Create array of all active monitors by taking into account monitors requested on the
* command-line */
2024-09-04 10:45:00 +03:00
int nmonitors = 0;
Multiple RAIL fixes/improvements 1. Linked Window Manager Maximize/Minimize and Restore operations to those from the Server Rail Window so that they are in sync 2. Enable things like "CTRL-ALT-DELETE" and "WindowsKey-L" to show the full desktop window again since the desktop is not actively monitored since this was still trying to draw to the rail window without updating the size of the window to accomodate the full workspace area. 3. Changed local window coordinates to be based on the visibileOffsetX/Y- while moving server window based on WindowOffsetX/Y. I have seen various issues regarding this when trying to use a maximized window where this is a disconnect between local window coordinates and remote window coordinates. This change clears these things up. 4. Commented the XShapeCombineRectangles calls - this can cause issues where the entire window is not visible and it does not currently play well with the changes from #3. The gain here is greater than the loss. 5. Draw the initial workspace correctly when running across multiple monitors. The correct size was always used, but the window was only starting on the current monitor and thus could draw the window off of the viewable area. Known Issues: Although the changes for #2 worked well in the stable branch that I developed from - the desktop window shown once the rail windows are destroyed does not respond to input unless I minimize/restore the window. Once the window starts responding to input - you can hit cancel to close the desktop window and return to your rail windows again(or launch task manager, etc.). This is still a big step in the right direction as xfreerdp is now correctly acting when the rail server stops Actively Monitoring the desktop. XShapeCombineRectangles needs to be revisited, most windows applications will give you a rectangular window anyways.
2012-08-04 02:35:17 +04:00
{
2022-07-07 17:06:54 +03:00
UINT32 nr = 0;
2019-02-07 16:40:36 +03:00
{
const UINT32* ids = freerdp_settings_get_pointer(settings, FreeRDP_MonitorIds);
if (ids)
nr = *ids;
}
2023-10-13 10:48:44 +03:00
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
2019-02-07 16:40:36 +03:00
{
MONITOR_ATTRIBUTES* attrs = NULL;
2018-01-22 17:45:27 +03:00
2024-08-29 12:11:11 +03:00
if (!xf_is_monitor_id_active(xfc, i))
2019-02-07 16:40:36 +03:00
continue;
2019-02-07 16:40:36 +03:00
if (!vscreen->monitors)
2021-09-13 09:58:26 +03:00
goto fail;
2023-10-13 10:48:44 +03:00
rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
settings, FreeRDP_MonitorDefArray, nmonitors);
monitor->x = (vscreen->monitors[i].area.left *
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
: 100)) /
100;
monitor->y = (vscreen->monitors[i].area.top *
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
: 100)) /
100;
monitor->width =
((vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1) *
2023-10-13 10:48:44 +03:00
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
: 100)) /
100;
2023-10-13 10:48:44 +03:00
monitor->height =
((vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1) *
2023-10-13 10:48:44 +03:00
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
: 100)) /
100;
2023-10-13 10:48:44 +03:00
monitor->orig_screen = i;
#ifdef USABLE_XRANDR
2018-01-22 17:45:27 +03:00
2019-02-07 16:40:36 +03:00
if (useXRandr && rrmonitors)
{
Rotation rot = 0;
Rotation ret = 0;
2023-10-13 10:48:44 +03:00
attrs = &monitor->attributes;
2019-02-07 16:40:36 +03:00
attrs->physicalWidth = rrmonitors[i].mwidth;
attrs->physicalHeight = rrmonitors[i].mheight;
ret = XRRRotations(xfc->display, i, &rot);
2021-06-30 11:19:16 +03:00
attrs->orientation = ret;
2019-02-07 16:40:36 +03:00
}
2018-01-22 17:45:27 +03:00
#endif
2024-08-29 12:11:11 +03:00
if (i == nr)
2019-02-07 16:40:36 +03:00
{
2023-10-13 10:48:44 +03:00
monitor->is_primary = TRUE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, monitor->x))
goto fail;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, monitor->y))
goto fail;
2019-02-07 16:40:36 +03:00
primaryMonitorFound = TRUE;
}
2019-02-07 16:40:36 +03:00
nmonitors++;
}
Multiple RAIL fixes/improvements 1. Linked Window Manager Maximize/Minimize and Restore operations to those from the Server Rail Window so that they are in sync 2. Enable things like "CTRL-ALT-DELETE" and "WindowsKey-L" to show the full desktop window again since the desktop is not actively monitored since this was still trying to draw to the rail window without updating the size of the window to accomodate the full workspace area. 3. Changed local window coordinates to be based on the visibileOffsetX/Y- while moving server window based on WindowOffsetX/Y. I have seen various issues regarding this when trying to use a maximized window where this is a disconnect between local window coordinates and remote window coordinates. This change clears these things up. 4. Commented the XShapeCombineRectangles calls - this can cause issues where the entire window is not visible and it does not currently play well with the changes from #3. The gain here is greater than the loss. 5. Draw the initial workspace correctly when running across multiple monitors. The correct size was always used, but the window was only starting on the current monitor and thus could draw the window off of the viewable area. Known Issues: Although the changes for #2 worked well in the stable branch that I developed from - the desktop window shown once the rail windows are destroyed does not respond to input unless I minimize/restore the window. Once the window starts responding to input - you can hit cancel to close the desktop window and return to your rail windows again(or launch task manager, etc.). This is still a big step in the right direction as xfreerdp is now correctly acting when the rail server stops Actively Monitoring the desktop. XShapeCombineRectangles needs to be revisited, most windows applications will give you a rectangular window anyways.
2012-08-04 02:35:17 +04:00
}
2019-11-06 17:24:51 +03:00
/* If no monitor is active(bogus command-line monitor specification) - then lets try to fallback
* to go fullscreen on the current monitor only */
if (nmonitors == 0 && vscreen->nmonitors > 0)
2019-02-07 16:40:36 +03:00
{
INT32 width = 0;
INT32 height = 0;
if (!vscreen->monitors)
2021-09-13 09:58:26 +03:00
goto fail;
2019-02-07 16:40:36 +03:00
width = vscreen->monitors[current_monitor].area.right -
vscreen->monitors[current_monitor].area.left + 1L;
height = vscreen->monitors[current_monitor].area.bottom -
2019-11-06 17:24:51 +03:00
vscreen->monitors[current_monitor].area.top + 1L;
2019-02-07 16:40:36 +03:00
2023-10-13 10:48:44 +03:00
rdpMonitor* monitor =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, 0);
if (!monitor)
goto fail;
monitor->x = vscreen->monitors[current_monitor].area.left;
monitor->y = vscreen->monitors[current_monitor].area.top;
monitor->width = MIN(width, (INT64)(*pMaxWidth));
monitor->height = MIN(height, (INT64)(*pMaxHeight));
monitor->orig_screen = current_monitor;
nmonitors = 1;
}
2023-10-13 10:48:44 +03:00
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, nmonitors))
goto fail;
/* If we have specific monitor information */
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0)
2013-04-29 03:16:23 +04:00
{
2023-10-13 10:48:44 +03:00
const rdpMonitor* cmonitor =
freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, 0);
if (!cmonitor)
goto fail;
/* Initialize bounding rectangle for all monitors */
2023-10-13 10:48:44 +03:00
int vX = cmonitor->x;
int vY = cmonitor->y;
int vR = vX + cmonitor->width;
int vB = vY + cmonitor->height;
xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom =
2023-10-13 10:48:44 +03:00
xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = cmonitor->orig_screen;
/* Calculate bounding rectangle around all monitors to be used AND
* also set the Xinerama indices which define left/top/right/bottom monitors.
*/
2023-10-13 10:48:44 +03:00
for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
{
2023-10-13 10:48:44 +03:00
rdpMonitor* monitor =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
/* does the same as gdk_rectangle_union */
2023-10-13 10:48:44 +03:00
int destX = MIN(vX, monitor->x);
int destY = MIN(vY, monitor->y);
int destR = MAX(vR, monitor->x + monitor->width);
int destB = MAX(vB, monitor->y + monitor->height);
if (vX != destX)
2023-10-13 10:48:44 +03:00
xfc->fullscreenMonitors.left = monitor->orig_screen;
2016-08-03 15:16:20 +03:00
if (vY != destY)
2023-10-13 10:48:44 +03:00
xfc->fullscreenMonitors.top = monitor->orig_screen;
2016-08-03 15:16:20 +03:00
if (vR != destR)
2023-10-13 10:48:44 +03:00
xfc->fullscreenMonitors.right = monitor->orig_screen;
2016-08-03 15:16:20 +03:00
if (vB != destB)
2023-10-13 10:48:44 +03:00
xfc->fullscreenMonitors.bottom = monitor->orig_screen;
2024-09-02 15:57:55 +03:00
const UINT32 ps = freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen);
WINPR_ASSERT(ps <= 100);
const int psuw =
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth) ? (int)ps : 100;
const int psuh =
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight) ? (int)ps : 100;
vX = (destX * psuw) / 100;
vY = (destY * psuh) / 100;
vR = (destR * psuw) / 100;
vB = (destB * psuh) / 100;
}
2013-04-29 03:16:23 +04:00
vscreen->area.left = 0;
vscreen->area.right = vR - vX - 1;
vscreen->area.top = 0;
vscreen->area.bottom = vB - vY - 1;
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
{
vscreen->area.top = xfc->workArea.y;
vscreen->area.bottom = xfc->workArea.height + xfc->workArea.y - 1;
}
if (!primaryMonitorFound)
2016-08-03 15:16:20 +03:00
{
/* If we have a command line setting we should use it */
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) > 0)
{
/* The first monitor is the first in the setting which should be used */
2023-10-13 10:48:44 +03:00
UINT32* ids =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorIds, 0);
if (ids)
monitor_index = *ids;
}
else
{
/* This is the same as when we would trust the Xinerama results..
and set the monitor index to zero.
The monitor listed with /list:monitor on index zero is always the primary
*/
screen = DefaultScreenOfDisplay(xfc->display);
monitor_index = XScreenNumberOfScreen(screen);
}
2023-10-13 10:48:44 +03:00
UINT32 j = monitor_index;
rdpMonitor* pmonitor =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, j);
/* If the "default" monitor is not 0,0 use it */
2023-10-13 10:48:44 +03:00
if ((pmonitor->x != 0) || (pmonitor->y != 0))
{
2023-10-13 10:48:44 +03:00
pmonitor->is_primary = TRUE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, pmonitor->x))
goto fail;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, pmonitor->y))
goto fail;
}
else
{
2019-11-06 17:24:51 +03:00
/* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a
* fallback*/
2023-10-13 10:48:44 +03:00
for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
i++)
{
2023-10-13 10:48:44 +03:00
rdpMonitor* monitor = freerdp_settings_get_pointer_array_writable(
settings, FreeRDP_MonitorDefArray, i);
if (!primaryMonitorFound && monitor->x == 0 && monitor->y == 0)
{
2023-10-13 10:48:44 +03:00
monitor->is_primary = TRUE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX,
monitor->x))
goto fail;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY,
monitor->y))
goto fail;
primaryMonitorFound = TRUE;
}
}
}
}
2016-08-03 15:16:20 +03:00
/* Subtract monitor shift from monitor variables for server-side use.
2019-11-06 17:24:51 +03:00
* We maintain monitor shift value as Window requires the primary monitor to have a
* coordinate of 0,0 In some X configurations, no monitor may have a coordinate of 0,0. This
* can also be happen if the user requests specific monitors from the command-line as well.
* So, we make sure to translate our primary monitor's upper-left corner to 0,0 on the
* server.
*/
2023-10-13 10:48:44 +03:00
for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
{
2023-10-13 10:48:44 +03:00
rdpMonitor* monitor =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, i);
monitor->x =
monitor->x - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftX);
monitor->y =
monitor->y - freerdp_settings_get_uint32(settings, FreeRDP_MonitorLocalShiftY);
}
2019-11-06 17:24:51 +03:00
/* Set the desktop width and height according to the bounding rectangle around the active
* monitors */
2019-02-07 16:40:36 +03:00
*pMaxWidth = MIN(*pMaxWidth, (UINT32)vscreen->area.right - vscreen->area.left + 1);
*pMaxHeight = MIN(*pMaxHeight, (UINT32)vscreen->area.bottom - vscreen->area.top + 1);
}
/* some 2008 server freeze at logon if we announce support for monitor layout PDU with
* #monitors < 2. So let's announce it only if we have more than 1 monitor.
*/
2023-10-13 10:48:44 +03:00
if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 1)
{
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
goto fail;
}
2021-09-13 09:58:26 +03:00
rc = TRUE;
fail:
#ifdef USABLE_XRANDR
2018-01-22 17:45:27 +03:00
if (rrmonitors)
XRRFreeMonitors(rrmonitors);
2018-01-22 17:45:27 +03:00
#endif
2021-09-13 09:58:26 +03:00
return rc;
}