2017-11-29 12:26:04 +03:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* X11 Display Control channel
|
|
|
|
*
|
|
|
|
* Copyright 2017 David Fort <contact@hardening-consulting.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-01-19 11:27:39 +03:00
|
|
|
#include <winpr/assert.h>
|
2017-12-19 17:16:14 +03:00
|
|
|
#include <winpr/sysinfo.h>
|
2017-11-29 12:26:04 +03:00
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
|
|
|
#ifdef WITH_XRANDR
|
|
|
|
#include <X11/extensions/Xrandr.h>
|
|
|
|
#include <X11/extensions/randr.h>
|
2017-12-19 17:16:14 +03:00
|
|
|
|
2017-12-23 12:27:38 +03:00
|
|
|
#if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
|
2019-11-06 17:24:51 +03:00
|
|
|
#define USABLE_XRANDR
|
2017-12-19 17:16:14 +03:00
|
|
|
#endif
|
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "xf_disp.h"
|
|
|
|
#include "xf_monitor.h"
|
|
|
|
|
2022-04-28 06:43:31 +03:00
|
|
|
#include <freerdp/log.h>
|
2017-11-29 12:26:04 +03:00
|
|
|
#define TAG CLIENT_TAG("x11disp")
|
2017-12-19 17:16:14 +03:00
|
|
|
#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
|
2017-11-29 12:26:04 +03:00
|
|
|
|
2022-02-14 16:59:22 +03:00
|
|
|
struct s_xfDispContext
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2018-07-18 10:31:04 +03:00
|
|
|
xfContext* xfc;
|
2018-09-24 17:44:25 +03:00
|
|
|
DispClientContext* disp;
|
2017-11-29 12:26:04 +03:00
|
|
|
BOOL haveXRandr;
|
2022-01-31 17:06:23 +03:00
|
|
|
int eventBase;
|
|
|
|
int errorBase;
|
|
|
|
UINT32 lastSentWidth;
|
|
|
|
UINT32 lastSentHeight;
|
|
|
|
BYTE reserved[4];
|
2017-12-19 17:16:14 +03:00
|
|
|
UINT64 lastSentDate;
|
2022-01-31 17:06:23 +03:00
|
|
|
UINT32 targetWidth;
|
|
|
|
UINT32 targetHeight;
|
2017-11-29 12:26:04 +03:00
|
|
|
BOOL activated;
|
2018-08-08 14:04:26 +03:00
|
|
|
BOOL fullscreen;
|
2018-07-18 10:31:04 +03:00
|
|
|
UINT16 lastSentDesktopOrientation;
|
2022-01-31 17:06:23 +03:00
|
|
|
BYTE reserved2[2];
|
2018-07-18 10:31:04 +03:00
|
|
|
UINT32 lastSentDesktopScaleFactor;
|
|
|
|
UINT32 lastSentDeviceScaleFactor;
|
2022-01-31 17:06:23 +03:00
|
|
|
BYTE reserved3[4];
|
2017-11-29 12:26:04 +03:00
|
|
|
};
|
|
|
|
|
2022-01-31 17:06:23 +03:00
|
|
|
static UINT xf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
|
|
|
|
UINT32 nmonitors);
|
2018-08-08 14:04:26 +03:00
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
static BOOL xf_disp_settings_changed(xfDispContext* xfDisp)
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpSettings* settings = NULL;
|
2022-01-19 11:27:39 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(xfDisp);
|
|
|
|
WINPR_ASSERT(xfDisp->xfc);
|
|
|
|
|
|
|
|
settings = xfDisp->xfc->common.context.settings;
|
|
|
|
WINPR_ASSERT(settings);
|
2018-07-18 10:31:04 +03:00
|
|
|
|
|
|
|
if (xfDisp->lastSentWidth != xfDisp->targetWidth)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (xfDisp->lastSentHeight != xfDisp->targetHeight)
|
|
|
|
return TRUE;
|
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (xfDisp->lastSentDesktopOrientation !=
|
|
|
|
freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation))
|
2018-07-18 10:31:04 +03:00
|
|
|
return TRUE;
|
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (xfDisp->lastSentDesktopScaleFactor !=
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor))
|
2018-07-18 10:31:04 +03:00
|
|
|
return TRUE;
|
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (xfDisp->lastSentDeviceScaleFactor !=
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor))
|
2018-07-18 10:31:04 +03:00
|
|
|
return TRUE;
|
|
|
|
|
2018-08-08 14:04:26 +03:00
|
|
|
if (xfDisp->fullscreen != xfDisp->xfc->fullscreen)
|
|
|
|
return TRUE;
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL xf_update_last_sent(xfDispContext* xfDisp)
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpSettings* settings = NULL;
|
2022-01-19 11:27:39 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(xfDisp);
|
|
|
|
WINPR_ASSERT(xfDisp->xfc);
|
|
|
|
|
|
|
|
settings = xfDisp->xfc->common.context.settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
xfDisp->lastSentWidth = xfDisp->targetWidth;
|
|
|
|
xfDisp->lastSentHeight = xfDisp->targetHeight;
|
2023-10-13 10:48:44 +03:00
|
|
|
xfDisp->lastSentDesktopOrientation =
|
|
|
|
freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
|
|
|
|
xfDisp->lastSentDesktopScaleFactor =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
|
|
|
xfDisp->lastSentDeviceScaleFactor =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
2018-08-08 14:04:26 +03:00
|
|
|
xfDisp->fullscreen = xfDisp->xfc->fullscreen;
|
2018-07-18 10:31:04 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
2017-12-19 17:16:14 +03:00
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
static BOOL xf_disp_sendResize(xfDispContext* xfDisp)
|
2017-12-19 17:16:14 +03:00
|
|
|
{
|
2022-09-12 12:55:26 +03:00
|
|
|
DISPLAY_CONTROL_MONITOR_LAYOUT layout = { 0 };
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2018-09-24 17:24:32 +03:00
|
|
|
|
|
|
|
if (!xfDisp || !xfDisp->xfc)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
xfc = xfDisp->xfc;
|
2022-01-19 11:27:39 +03:00
|
|
|
settings = xfc->common.context.settings;
|
2018-09-24 17:24:32 +03:00
|
|
|
|
|
|
|
if (!settings)
|
|
|
|
return FALSE;
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
if (!xfDisp->activated || !xfDisp->disp)
|
2018-07-18 10:31:04 +03:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY)
|
|
|
|
return TRUE;
|
2017-12-19 17:16:14 +03:00
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
if (!xf_disp_settings_changed(xfDisp))
|
|
|
|
return TRUE;
|
|
|
|
|
2020-11-13 20:07:35 +03:00
|
|
|
xfDisp->lastSentDate = GetTickCount64();
|
2023-10-13 10:48:44 +03:00
|
|
|
|
|
|
|
const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
|
|
|
if (xfc->fullscreen && (mcount > 0))
|
2018-08-08 14:04:26 +03:00
|
|
|
{
|
2023-10-13 10:48:44 +03:00
|
|
|
const rdpMonitor* monitors =
|
|
|
|
freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
|
|
|
|
if (xf_disp_sendLayout(xfDisp->disp, monitors, mcount) != CHANNEL_RC_OK)
|
2018-08-08 14:04:26 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
|
|
|
|
layout.Top = layout.Left = 0;
|
|
|
|
layout.Width = xfDisp->targetWidth;
|
|
|
|
layout.Height = xfDisp->targetHeight;
|
2023-10-13 10:48:44 +03:00
|
|
|
layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
|
|
|
|
layout.DesktopScaleFactor =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
|
|
|
layout.DeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
2022-01-31 17:06:23 +03:00
|
|
|
layout.PhysicalWidth = xfDisp->targetWidth / 75.0 * 25.4;
|
|
|
|
layout.PhysicalHeight = xfDisp->targetHeight / 75.0 * 25.4;
|
2018-08-08 14:04:26 +03:00
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
if (IFCALLRESULT(CHANNEL_RC_OK, xfDisp->disp->SendMonitorLayout, xfDisp->disp, 1,
|
2018-09-24 17:24:32 +03:00
|
|
|
&layout) != CHANNEL_RC_OK)
|
2018-08-08 14:04:26 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2018-07-18 10:31:04 +03:00
|
|
|
|
|
|
|
return xf_update_last_sent(xfDisp);
|
2017-12-19 17:16:14 +03:00
|
|
|
}
|
|
|
|
|
2021-02-10 17:32:07 +03:00
|
|
|
static BOOL xf_disp_queueResize(xfDispContext* xfDisp, UINT32 width, UINT32 height)
|
|
|
|
{
|
2021-02-16 18:10:23 +03:00
|
|
|
if ((xfDisp->targetWidth == (INT64)width) && (xfDisp->targetHeight == (INT64)height))
|
2021-02-10 17:32:07 +03:00
|
|
|
return TRUE;
|
|
|
|
xfDisp->targetWidth = width;
|
|
|
|
xfDisp->targetHeight = height;
|
|
|
|
xfDisp->lastSentDate = GetTickCount64();
|
|
|
|
return xf_disp_sendResize(xfDisp);
|
|
|
|
}
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp)
|
2017-12-19 17:16:14 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
XSizeHints* size_hints = NULL;
|
2017-12-19 17:16:14 +03:00
|
|
|
|
|
|
|
if (!(size_hints = XAllocSizeHints()))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
size_hints->flags = PMinSize | PMaxSize | PWinGravity;
|
|
|
|
size_hints->win_gravity = NorthWestGravity;
|
|
|
|
size_hints->min_width = size_hints->min_height = 320;
|
|
|
|
size_hints->max_width = size_hints->max_height = 8192;
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-12-20 18:16:33 +03:00
|
|
|
if (xfDisp->xfc->window)
|
|
|
|
XSetWMNormalHints(xfDisp->xfc->display, xfDisp->xfc->window->handle, size_hints);
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-12-19 17:16:14 +03:00
|
|
|
XFree(size_hints);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-10-02 13:33:52 +03:00
|
|
|
static BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp,
|
|
|
|
rdpSettings** ppSettings)
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
xfc = (xfContext*)context;
|
|
|
|
|
|
|
|
if (!(xfc->xfDisp))
|
|
|
|
return FALSE;
|
|
|
|
|
2022-01-19 11:27:39 +03:00
|
|
|
if (!xfc->common.context.settings)
|
2018-10-02 13:33:52 +03:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*ppXfc = xfc;
|
|
|
|
*ppXfDisp = xfc->xfDisp;
|
2022-01-19 11:27:39 +03:00
|
|
|
*ppSettings = xfc->common.context.settings;
|
2018-10-02 13:33:52 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
2017-12-19 17:16:14 +03:00
|
|
|
|
2022-01-31 17:06:23 +03:00
|
|
|
static void xf_disp_OnActivated(void* context, const ActivatedEventArgs* e)
|
2017-12-19 17:16:14 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
|
|
|
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
|
|
|
return;
|
|
|
|
|
2020-11-13 20:07:35 +03:00
|
|
|
if (xfDisp->activated && !xfc->fullscreen)
|
2017-12-19 17:16:14 +03:00
|
|
|
{
|
|
|
|
xf_disp_set_window_resizable(xfDisp);
|
|
|
|
|
|
|
|
if (e->firstActivation)
|
|
|
|
return;
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
xf_disp_sendResize(xfDisp);
|
2017-12-19 17:16:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-19 11:08:02 +03:00
|
|
|
static void xf_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
2019-02-07 19:53:21 +03:00
|
|
|
WINPR_UNUSED(e);
|
|
|
|
|
2018-10-02 13:33:52 +03:00
|
|
|
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
|
|
|
return;
|
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (xfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
{
|
|
|
|
xf_disp_set_window_resizable(xfDisp);
|
2018-07-18 10:31:04 +03:00
|
|
|
xf_disp_sendResize(xfDisp);
|
Fix for #4330
Since ec027bf dynamic resolution is broken when used with egfx. Before that commit
we were tracking a server sent resize by setting a DesktopResize callback. This callback
is called when the desktop is resized by the server. Anyway the problem was that when this
callback is called, the activation sequence is not always completed, which were leading to
some freeze with 2012r2 servers (sending packets before the sequence is finished).
So with the faulty commit, we are tracking server resizes by subscribing to the Actived
event, that is called at the end of a reactivation sequence, so we're sure to not send packets
when not fully activated.
Anyway the issue that shows on (#4330) is that when you use egfx, no reactivation sequence happens,
the server only sends a ResetGraphics message with the new size, and so we miss the resized event.
This fix introduces a new GraphicsReset event, makes the display channel subscribe to that event,
and react accordingly.
2017-12-23 15:50:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-19 11:08:02 +03:00
|
|
|
static void xf_disp_OnTimer(void* context, const TimerEventArgs* e)
|
2017-12-19 17:16:14 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
2019-02-07 19:53:21 +03:00
|
|
|
WINPR_UNUSED(e);
|
|
|
|
|
2018-10-02 13:33:52 +03:00
|
|
|
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
|
|
|
return;
|
2017-12-19 17:16:14 +03:00
|
|
|
|
2022-09-12 12:55:26 +03:00
|
|
|
if (!xfDisp->activated || xfc->fullscreen)
|
2017-12-19 17:16:14 +03:00
|
|
|
return;
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
xf_disp_sendResize(xfDisp);
|
2017-12-19 17:16:14 +03:00
|
|
|
}
|
|
|
|
|
2022-09-21 13:01:58 +03:00
|
|
|
static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEventArgs* e)
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfContext* xfc = NULL;
|
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2022-09-21 13:01:58 +03:00
|
|
|
|
|
|
|
WINPR_UNUSED(e);
|
|
|
|
|
|
|
|
if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!xfDisp->activated || !xfc->fullscreen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xf_disp_sendResize(xfDisp);
|
|
|
|
}
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
xfDispContext* xf_disp_new(xfContext* xfc)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfDispContext* ret = NULL;
|
|
|
|
const rdpSettings* settings = NULL;
|
|
|
|
wPubSub* pubSub = NULL;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
2022-01-19 11:27:39 +03:00
|
|
|
WINPR_ASSERT(xfc);
|
|
|
|
|
|
|
|
pubSub = xfc->common.context.pubSub;
|
|
|
|
WINPR_ASSERT(pubSub);
|
|
|
|
|
|
|
|
settings = xfc->common.context.settings;
|
|
|
|
WINPR_ASSERT(settings);
|
2018-10-02 13:33:52 +03:00
|
|
|
|
|
|
|
ret = calloc(1, sizeof(xfDispContext));
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
if (!ret)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret->xfc = xfc;
|
2017-12-19 17:16:14 +03:00
|
|
|
#ifdef USABLE_XRANDR
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
if (XRRQueryExtension(xfc->display, &ret->eventBase, &ret->errorBase))
|
|
|
|
{
|
|
|
|
ret->haveXRandr = TRUE;
|
|
|
|
}
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
#endif
|
2023-10-13 10:48:44 +03:00
|
|
|
ret->lastSentWidth = ret->targetWidth =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
|
|
|
ret->lastSentHeight = ret->targetHeight =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
2022-01-19 11:27:39 +03:00
|
|
|
PubSub_SubscribeActivated(pubSub, xf_disp_OnActivated);
|
|
|
|
PubSub_SubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset);
|
|
|
|
PubSub_SubscribeTimer(pubSub, xf_disp_OnTimer);
|
2022-09-21 13:01:58 +03:00
|
|
|
PubSub_SubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange);
|
2017-11-29 12:26:04 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
void xf_disp_free(xfDispContext* disp)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2018-10-02 13:33:52 +03:00
|
|
|
if (!disp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (disp->xfc)
|
|
|
|
{
|
2022-01-19 11:27:39 +03:00
|
|
|
wPubSub* pubSub = disp->xfc->common.context.pubSub;
|
|
|
|
PubSub_UnsubscribeActivated(pubSub, xf_disp_OnActivated);
|
|
|
|
PubSub_UnsubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset);
|
|
|
|
PubSub_UnsubscribeTimer(pubSub, xf_disp_OnTimer);
|
2022-09-21 13:01:58 +03:00
|
|
|
PubSub_UnsubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange);
|
2018-10-02 13:33:52 +03:00
|
|
|
}
|
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
free(disp);
|
|
|
|
}
|
|
|
|
|
2022-01-31 17:06:23 +03:00
|
|
|
UINT xf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors, UINT32 nmonitors)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
|
|
|
UINT ret = CHANNEL_RC_OK;
|
2024-01-23 18:49:54 +03:00
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
|
|
|
DISPLAY_CONTROL_MONITOR_LAYOUT* layouts = NULL;
|
2022-01-31 17:06:23 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(disp);
|
|
|
|
WINPR_ASSERT(monitors);
|
|
|
|
WINPR_ASSERT(nmonitors > 0);
|
|
|
|
|
|
|
|
xfDisp = (xfDispContext*)disp->custom;
|
|
|
|
WINPR_ASSERT(xfDisp);
|
|
|
|
WINPR_ASSERT(xfDisp->xfc);
|
|
|
|
|
2022-01-19 11:27:39 +03:00
|
|
|
settings = xfDisp->xfc->common.context.settings;
|
2022-01-31 17:06:23 +03:00
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
if (!layouts)
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
|
2024-01-30 12:25:38 +03:00
|
|
|
for (UINT32 i = 0; i < nmonitors; i++)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2022-01-31 17:06:23 +03:00
|
|
|
const rdpMonitor* monitor = &monitors[i];
|
|
|
|
DISPLAY_CONTROL_MONITOR_LAYOUT* layout = &layouts[i];
|
|
|
|
|
|
|
|
layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
|
|
|
|
layout->Left = monitor->x;
|
|
|
|
layout->Top = monitor->y;
|
|
|
|
layout->Width = monitor->width;
|
|
|
|
layout->Height = monitor->height;
|
|
|
|
layout->Orientation = ORIENTATION_LANDSCAPE;
|
|
|
|
layout->PhysicalWidth = monitor->attributes.physicalWidth;
|
|
|
|
layout->PhysicalHeight = monitor->attributes.physicalHeight;
|
|
|
|
|
|
|
|
switch (monitor->attributes.orientation)
|
2017-12-23 12:27:38 +03:00
|
|
|
{
|
2018-07-18 10:31:04 +03:00
|
|
|
case 90:
|
2022-01-31 17:06:23 +03:00
|
|
|
layout->Orientation = ORIENTATION_PORTRAIT;
|
2018-07-18 10:31:04 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 180:
|
2022-01-31 17:06:23 +03:00
|
|
|
layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
2018-07-18 10:31:04 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 270:
|
2022-01-31 17:06:23 +03:00
|
|
|
layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
2018-07-18 10:31:04 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
/* MS-RDPEDISP - 2.2.2.2.1:
|
|
|
|
* Orientation (4 bytes): A 32-bit unsigned integer that specifies the
|
|
|
|
* orientation of the monitor in degrees. Valid values are 0, 90, 180
|
|
|
|
* or 270
|
|
|
|
*
|
|
|
|
* So we default to ORIENTATION_LANDSCAPE
|
|
|
|
*/
|
2022-01-31 17:06:23 +03:00
|
|
|
layout->Orientation = ORIENTATION_LANDSCAPE;
|
2018-07-18 10:31:04 +03:00
|
|
|
break;
|
2017-12-23 12:27:38 +03:00
|
|
|
}
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
layout->DesktopScaleFactor =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
|
|
|
layout->DeviceScaleFactor =
|
|
|
|
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
2017-11-29 12:26:04 +03:00
|
|
|
}
|
|
|
|
|
2018-09-24 17:24:32 +03:00
|
|
|
ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
|
2017-11-29 12:26:04 +03:00
|
|
|
free(layouts);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-27 10:51:14 +03:00
|
|
|
BOOL xf_disp_handle_xevent(xfContext* xfc, const XEvent* event)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
|
|
|
UINT32 maxWidth = 0;
|
|
|
|
UINT32 maxHeight = 0;
|
2017-11-29 12:26:04 +03:00
|
|
|
|
2018-09-24 17:24:32 +03:00
|
|
|
if (!xfc || !event)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
xfDisp = xfc->xfDisp;
|
|
|
|
|
|
|
|
if (!xfDisp)
|
|
|
|
return FALSE;
|
|
|
|
|
2022-01-19 11:27:39 +03:00
|
|
|
settings = xfc->common.context.settings;
|
2018-09-24 17:24:32 +03:00
|
|
|
|
|
|
|
if (!settings)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
if (!xfDisp->haveXRandr || !xfDisp->disp)
|
2017-11-29 12:26:04 +03:00
|
|
|
return TRUE;
|
|
|
|
|
2017-12-19 17:16:14 +03:00
|
|
|
#ifdef USABLE_XRANDR
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
if (event->type != xfDisp->eventBase + RRScreenChangeNotify)
|
|
|
|
return TRUE;
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
#endif
|
2017-11-29 12:26:04 +03:00
|
|
|
xf_detect_monitors(xfc, &maxWidth, &maxHeight);
|
2023-10-13 10:48:44 +03:00
|
|
|
const rdpMonitor* monitors = freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray);
|
|
|
|
const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
|
|
|
return xf_disp_sendLayout(xfDisp->disp, monitors, mcount) == CHANNEL_RC_OK;
|
2017-11-29 12:26:04 +03:00
|
|
|
}
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
xfDispContext* xfDisp = NULL;
|
2018-09-24 17:24:32 +03:00
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
if (!xfc)
|
2018-09-24 17:24:32 +03:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
xfDisp = xfc->xfDisp;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
|
|
|
if (!xfDisp)
|
|
|
|
return FALSE;
|
|
|
|
|
2021-02-10 17:32:07 +03:00
|
|
|
return xf_disp_queueResize(xfDisp, width, height);
|
2017-11-29 12:26:04 +03:00
|
|
|
}
|
|
|
|
|
2018-10-02 13:33:52 +03:00
|
|
|
static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
|
|
|
|
UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
|
|
|
/* we're called only if dynamic resolution update is activated */
|
2024-01-23 18:49:54 +03:00
|
|
|
xfDispContext* xfDisp = NULL;
|
|
|
|
rdpSettings* settings = NULL;
|
2022-01-19 11:27:39 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(disp);
|
|
|
|
|
|
|
|
xfDisp = (xfDispContext*)disp->custom;
|
|
|
|
WINPR_ASSERT(xfDisp);
|
|
|
|
WINPR_ASSERT(xfDisp->xfc);
|
|
|
|
|
|
|
|
settings = xfDisp->xfc->common.context.settings;
|
|
|
|
WINPR_ASSERT(settings);
|
|
|
|
|
2018-07-18 10:31:04 +03:00
|
|
|
WLog_DBG(TAG,
|
2019-11-06 17:24:51 +03:00
|
|
|
"DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
|
|
|
|
" MaxMonitorAreaFactorB: %" PRIu32 "",
|
2018-07-18 10:31:04 +03:00
|
|
|
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
|
2017-11-29 12:26:04 +03:00
|
|
|
xfDisp->activated = TRUE;
|
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
2017-11-29 12:26:04 +03:00
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
|
2018-11-22 14:06:30 +03:00
|
|
|
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
|
2017-11-29 12:26:04 +03:00
|
|
|
return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp)
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpSettings* settings = NULL;
|
2018-09-24 17:44:25 +03:00
|
|
|
|
|
|
|
if (!xfDisp || !xfDisp->xfc || !disp)
|
|
|
|
return FALSE;
|
|
|
|
|
2022-01-19 11:27:39 +03:00
|
|
|
settings = xfDisp->xfc->common.context.settings;
|
2018-10-02 13:33:52 +03:00
|
|
|
|
|
|
|
if (!settings)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
xfDisp->disp = disp;
|
2019-11-06 17:24:51 +03:00
|
|
|
disp->custom = (void*)xfDisp;
|
2017-11-29 12:26:04 +03:00
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
|
|
|
disp->DisplayControlCaps = xf_DisplayControlCaps;
|
2017-12-19 17:16:14 +03:00
|
|
|
#ifdef USABLE_XRANDR
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2023-10-13 10:48:44 +03:00
|
|
|
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
2017-11-29 12:26:04 +03:00
|
|
|
{
|
|
|
|
/* ask X11 to notify us of screen changes */
|
2018-09-24 17:44:25 +03:00
|
|
|
XRRSelectInput(xfDisp->xfc->display, DefaultRootWindow(xfDisp->xfc->display),
|
|
|
|
RRScreenChangeNotifyMask);
|
2017-11-29 12:26:04 +03:00
|
|
|
}
|
2018-07-18 10:31:04 +03:00
|
|
|
|
2017-11-29 12:26:04 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-09-24 17:44:25 +03:00
|
|
|
BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp)
|
|
|
|
{
|
|
|
|
if (!xfDisp || !disp)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
xfDisp->disp = NULL;
|
2018-10-03 16:16:59 +03:00
|
|
|
return TRUE;
|
2018-09-24 17:44:25 +03:00
|
|
|
}
|