Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
672
third_party/FreeRDP/client/X11/xf_monitor.c
vendored
Normal file
672
third_party/FreeRDP/client/X11/xf_monitor.c
vendored
Normal file
@@ -0,0 +1,672 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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/cast.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#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
|
||||
#define USABLE_XRANDR
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "xf_monitor.h"
|
||||
#include "xf_utils.h"
|
||||
|
||||
/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
|
||||
*/
|
||||
|
||||
int xf_list_monitors(xfContext* xfc)
|
||||
{
|
||||
WINPR_UNUSED(xfc);
|
||||
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int nmonitors = 0;
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
|
||||
if (!display)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to open X display");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(USABLE_XRANDR)
|
||||
|
||||
if (XRRQueryExtension(display, &major, &minor) &&
|
||||
(XRRQueryVersion(display, &major, &minor) == True) && (major * 100 + minor >= 105))
|
||||
{
|
||||
XRRMonitorInfo* monitors =
|
||||
XRRGetMonitors(display, DefaultRootWindow(display), 1, &nmonitors);
|
||||
|
||||
for (int i = 0; i < nmonitors; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
XRRFreeMonitors(monitors);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef WITH_XINERAMA
|
||||
if (XineramaQueryExtension(display, &major, &minor))
|
||||
{
|
||||
if (XineramaIsActive(display))
|
||||
{
|
||||
XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors);
|
||||
|
||||
for (int i = 0; i < nmonitors; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
XFree(screen);
|
||||
}
|
||||
}
|
||||
else
|
||||
#else
|
||||
{
|
||||
Screen* screen = ScreenOfDisplay(display, DefaultScreen(display));
|
||||
printf(" * [0] %dx%d\t+0+0\n", WidthOfScreen(screen), HeightOfScreen(screen));
|
||||
}
|
||||
|
||||
#endif
|
||||
LogDynAndXCloseDisplay(xfc->log, display);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id)
|
||||
{
|
||||
const rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
settings = xfc->common.context.settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const UINT32 NumMonitorIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
|
||||
if (NumMonitorIds == 0)
|
||||
return TRUE;
|
||||
|
||||
for (UINT32 index = 0; index < NumMonitorIds; index++)
|
||||
{
|
||||
const UINT32* cur = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index);
|
||||
if (cur && (*cur == id))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
UINT32 monitor_index = 0;
|
||||
BOOL primaryMonitorFound = FALSE;
|
||||
int mouse_x = 0;
|
||||
int mouse_y = 0;
|
||||
int _dummy_i = 0;
|
||||
Window _dummy_w = 0;
|
||||
UINT32 current_monitor = 0;
|
||||
Screen* screen = nullptr;
|
||||
#if defined WITH_XINERAMA || defined WITH_XRANDR
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
#endif
|
||||
#if defined(USABLE_XRANDR)
|
||||
XRRMonitorInfo* rrmonitors = nullptr;
|
||||
BOOL useXRandr = FALSE;
|
||||
#endif
|
||||
|
||||
if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->common.context.settings)
|
||||
return FALSE;
|
||||
|
||||
rdpSettings* settings = xfc->common.context.settings;
|
||||
VIRTUAL_SCREEN* vscreen = &xfc->vscreen;
|
||||
|
||||
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
|
||||
if (freerdp_settings_get_uint64(settings, FreeRDP_ParentWindowId) > 0)
|
||||
{
|
||||
xfc->workArea.x = 0;
|
||||
xfc->workArea.y = 0;
|
||||
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 */
|
||||
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)
|
||||
|
||||
if (XRRQueryExtension(xfc->display, &major, &minor) &&
|
||||
(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++)
|
||||
{
|
||||
MONITOR_INFO* cur_vscreen = &vscreen->monitors[i];
|
||||
const XRRMonitorInfo* cur_monitor = &rrmonitors[i];
|
||||
|
||||
cur_vscreen->area.left = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x);
|
||||
cur_vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y);
|
||||
cur_vscreen->area.right =
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->x + cur_monitor->width - 1);
|
||||
cur_vscreen->area.bottom =
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cur_monitor->y + cur_monitor->height - 1);
|
||||
cur_vscreen->primary = cur_monitor->primary > 0;
|
||||
}
|
||||
}
|
||||
|
||||
useXRandr = TRUE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef WITH_XINERAMA
|
||||
if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display))
|
||||
{
|
||||
int nmonitors = 0;
|
||||
XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &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++)
|
||||
{
|
||||
MONITOR_INFO* monitor = &vscreen->monitors[i];
|
||||
monitor->area.left = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].x_org);
|
||||
monitor->area.top = WINPR_ASSERTING_INT_CAST(uint16_t, screenInfo[i].y_org);
|
||||
monitor->area.right = WINPR_ASSERTING_INT_CAST(
|
||||
uint16_t, screenInfo[i].x_org + screenInfo[i].width - 1);
|
||||
monitor->area.bottom = WINPR_ASSERTING_INT_CAST(
|
||||
uint16_t, screenInfo[i].y_org + screenInfo[i].height - 1);
|
||||
}
|
||||
}
|
||||
|
||||
XFree(screenInfo);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Both XRandR and Xinerama are either not compiled in or are not working, do nothing.
|
||||
*/
|
||||
}
|
||||
|
||||
rdpMonitor* rdpmonitors = calloc(vscreen->nmonitors + 1, sizeof(rdpMonitor));
|
||||
if (!rdpmonitors)
|
||||
goto fail;
|
||||
|
||||
xfc->fullscreenMonitors.top = 0;
|
||||
xfc->fullscreenMonitors.bottom = 0;
|
||||
xfc->fullscreenMonitors.left = 0;
|
||||
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.
|
||||
*/
|
||||
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)))
|
||||
{
|
||||
/* If no monitors were specified on the command-line then set the current monitor as active
|
||||
*/
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0)
|
||||
{
|
||||
UINT32 id = current_monitor;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1))
|
||||
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.
|
||||
*/
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* WORKAROUND: With Remote Application Mode - using NET_WM_WORKAREA
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
if ((freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 1) &&
|
||||
(vscreen->nmonitors > current_monitor))
|
||||
{
|
||||
MONITOR_INFO* monitor = vscreen->monitors + current_monitor;
|
||||
|
||||
if (!monitor)
|
||||
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 = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
|
||||
xfc->workArea.height = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
|
||||
}
|
||||
}
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, WidthOfScreen(xfc->screen));
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, HeightOfScreen(xfc->screen));
|
||||
}
|
||||
else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
*pMaxWidth = xfc->workArea.width;
|
||||
*pMaxHeight = xfc->workArea.height;
|
||||
}
|
||||
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)
|
||||
goto fail;
|
||||
|
||||
const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
|
||||
const RECTANGLE_16* area = &vmonitor->area;
|
||||
|
||||
*pMaxWidth = area->right - area->left + 1;
|
||||
*pMaxHeight = area->bottom - area->top + 1;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
|
||||
*pMaxWidth = ((area->right - area->left + 1) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
|
||||
*pMaxHeight = ((area->bottom - area->top + 1) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pMaxWidth = xfc->workArea.width;
|
||||
*pMaxHeight = xfc->workArea.height;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
|
||||
*pMaxWidth = (xfc->workArea.width *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
|
||||
*pMaxHeight = (xfc->workArea.height *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
}
|
||||
}
|
||||
else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) &&
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight))
|
||||
{
|
||||
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
}
|
||||
|
||||
/* Create array of all active monitors by taking into account monitors requested on the
|
||||
* command-line */
|
||||
{
|
||||
size_t nmonitors = 0;
|
||||
{
|
||||
UINT32 nr = 0;
|
||||
|
||||
{
|
||||
const UINT32* ids = freerdp_settings_get_pointer(settings, FreeRDP_MonitorIds);
|
||||
if (ids)
|
||||
nr = *ids;
|
||||
}
|
||||
for (UINT32 i = 0; i < vscreen->nmonitors; i++)
|
||||
{
|
||||
MONITOR_ATTRIBUTES* attrs = nullptr;
|
||||
|
||||
if (!xf_is_monitor_id_active(xfc, i))
|
||||
continue;
|
||||
|
||||
if (!vscreen->monitors)
|
||||
goto fail;
|
||||
|
||||
rdpMonitor* monitor = &rdpmonitors[nmonitors];
|
||||
const RECTANGLE_16* area = &vscreen->monitors[i].area;
|
||||
monitor->x =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
area->left*(
|
||||
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->y =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
area->top*(
|
||||
freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->width =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
(area->right - area->left + 1) *
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->height =
|
||||
WINPR_ASSERTING_INT_CAST(
|
||||
int32_t,
|
||||
(area->bottom - area->top + 1) *
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)
|
||||
? freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)
|
||||
: 100)) /
|
||||
100;
|
||||
monitor->orig_screen = i;
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (useXRandr && rrmonitors)
|
||||
{
|
||||
Rotation rot = 0;
|
||||
Rotation ret = 0;
|
||||
attrs = &monitor->attributes;
|
||||
attrs->physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mwidth);
|
||||
attrs->physicalHeight =
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, rrmonitors[i].mheight);
|
||||
ret = XRRRotations(xfc->display, WINPR_ASSERTING_INT_CAST(int, i), &rot);
|
||||
switch (rot & ret)
|
||||
{
|
||||
|
||||
case RR_Rotate_90:
|
||||
attrs->orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
case RR_Rotate_180:
|
||||
attrs->orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
case RR_Rotate_270:
|
||||
attrs->orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
case RR_Rotate_0:
|
||||
default:
|
||||
attrs->orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (i == nr)
|
||||
{
|
||||
monitor->is_primary = TRUE;
|
||||
primaryMonitorFound = TRUE;
|
||||
}
|
||||
|
||||
nmonitors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
if (!vscreen->monitors)
|
||||
goto fail;
|
||||
|
||||
const MONITOR_INFO* vmonitor = &vscreen->monitors[current_monitor];
|
||||
const RECTANGLE_16* area = &vmonitor->area;
|
||||
|
||||
const INT32 width = area->right - area->left + 1;
|
||||
const INT32 height = area->bottom - area->top + 1;
|
||||
const INT32 maxw =
|
||||
((width < 0) || ((UINT32)width < *pMaxWidth)) ? width : (INT32)*pMaxWidth;
|
||||
const INT32 maxh =
|
||||
((height < 0) || ((UINT32)height < *pMaxHeight)) ? width : (INT32)*pMaxHeight;
|
||||
|
||||
rdpMonitor* monitor = &rdpmonitors[0];
|
||||
if (!monitor)
|
||||
goto fail;
|
||||
|
||||
monitor->x = area->left;
|
||||
monitor->y = area->top;
|
||||
monitor->width = maxw;
|
||||
monitor->height = maxh;
|
||||
monitor->orig_screen = current_monitor;
|
||||
nmonitors = 1;
|
||||
}
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount,
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, nmonitors)))
|
||||
goto fail;
|
||||
|
||||
/* If we have specific monitor information */
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0)
|
||||
{
|
||||
const rdpMonitor* cmonitor = &rdpmonitors[0];
|
||||
if (!cmonitor)
|
||||
goto fail;
|
||||
|
||||
/* Initialize bounding rectangle for all monitors */
|
||||
int vX = cmonitor->x;
|
||||
int vY = cmonitor->y;
|
||||
int vR = vX + cmonitor->width;
|
||||
int vB = vY + cmonitor->height;
|
||||
const int32_t corig = WINPR_ASSERTING_INT_CAST(int32_t, cmonitor->orig_screen);
|
||||
xfc->fullscreenMonitors.top = corig;
|
||||
xfc->fullscreenMonitors.bottom = corig;
|
||||
xfc->fullscreenMonitors.left = corig;
|
||||
xfc->fullscreenMonitors.right = corig;
|
||||
|
||||
/* Calculate bounding rectangle around all monitors to be used AND
|
||||
* also set the Xinerama indices which define left/top/right/bottom monitors.
|
||||
*/
|
||||
for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
|
||||
{
|
||||
rdpMonitor* monitor = &rdpmonitors[i];
|
||||
|
||||
/* does the same as gdk_rectangle_union */
|
||||
const int destX = MIN(vX, monitor->x);
|
||||
const int destY = MIN(vY, monitor->y);
|
||||
const int destR = MAX(vR, monitor->x + monitor->width);
|
||||
const int destB = MAX(vB, monitor->y + monitor->height);
|
||||
const int32_t orig = WINPR_ASSERTING_INT_CAST(int32_t, monitor->orig_screen);
|
||||
|
||||
if (vX != destX)
|
||||
xfc->fullscreenMonitors.left = orig;
|
||||
|
||||
if (vY != destY)
|
||||
xfc->fullscreenMonitors.top = orig;
|
||||
|
||||
if (vR != destR)
|
||||
xfc->fullscreenMonitors.right = orig;
|
||||
|
||||
if (vB != destB)
|
||||
xfc->fullscreenMonitors.bottom = orig;
|
||||
|
||||
vX = destX;
|
||||
vY = destY;
|
||||
vR = destR;
|
||||
vB = destB;
|
||||
}
|
||||
|
||||
vscreen->area.left = 0;
|
||||
const int r = vR - vX - 1;
|
||||
vscreen->area.right = WINPR_ASSERTING_INT_CAST(UINT16, r);
|
||||
vscreen->area.top = 0;
|
||||
const int b = vB - vY - 1;
|
||||
vscreen->area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, b);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
INT64 bottom = 1LL * xfc->workArea.height + xfc->workArea.y - 1LL;
|
||||
vscreen->area.top = WINPR_ASSERTING_INT_CAST(UINT16, xfc->workArea.y);
|
||||
vscreen->area.bottom = WINPR_ASSERTING_INT_CAST(UINT16, bottom);
|
||||
}
|
||||
|
||||
if (!primaryMonitorFound)
|
||||
{
|
||||
/* If we have a command line setting we should use it */
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) > 0)
|
||||
{
|
||||
/* The first monitor is the first in the setting which should be used */
|
||||
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 =
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, XScreenNumberOfScreen(screen));
|
||||
}
|
||||
|
||||
UINT32 j = monitor_index;
|
||||
rdpMonitor* pmonitor = &rdpmonitors[j];
|
||||
|
||||
/* If the "default" monitor is not 0,0 use it */
|
||||
if ((pmonitor->x != 0) || (pmonitor->y != 0))
|
||||
{
|
||||
pmonitor->is_primary = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a
|
||||
* fallback*/
|
||||
for (UINT32 i = 0;
|
||||
i < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); i++)
|
||||
{
|
||||
rdpMonitor* monitor = &rdpmonitors[i];
|
||||
if (!primaryMonitorFound && monitor->x == 0 && monitor->y == 0)
|
||||
{
|
||||
monitor->is_primary = TRUE;
|
||||
primaryMonitorFound = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the desktop width and height according to the bounding rectangle around the
|
||||
* active monitors */
|
||||
*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.
|
||||
*/
|
||||
nmonitors = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
||||
if (nmonitors > 1)
|
||||
{
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = freerdp_settings_set_monitor_def_array_sorted(settings, rdpmonitors, nmonitors);
|
||||
}
|
||||
|
||||
fail:
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
if (rrmonitors)
|
||||
XRRFreeMonitors(rrmonitors);
|
||||
|
||||
#endif
|
||||
free(rdpmonitors);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user