21 #include <winpr/assert.h>
22 #include <winpr/sysinfo.h>
23 #include <X11/Xutil.h>
26 #include <X11/extensions/Xrandr.h>
27 #include <X11/extensions/randr.h>
29 #if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105
36 #include "xf_monitor.h"
38 #include <freerdp/log.h>
39 #define TAG CLIENT_TAG("x11disp")
40 #define RESIZE_MIN_DELAY 200
42 struct s_xfDispContext
45 DispClientContext* disp;
50 UINT32 lastSentHeight;
57 UINT16 lastSentDesktopOrientation;
59 UINT32 lastSentDesktopScaleFactor;
60 UINT32 lastSentDeviceScaleFactor;
64 static UINT xf_disp_sendLayout(DispClientContext* disp,
const rdpMonitor* monitors,
67 static BOOL xf_disp_settings_changed(xfDispContext* xfDisp)
69 rdpSettings* settings = NULL;
72 WINPR_ASSERT(xfDisp->xfc);
74 settings = xfDisp->xfc->common.context.settings;
75 WINPR_ASSERT(settings);
77 if (xfDisp->lastSentWidth != xfDisp->targetWidth)
80 if (xfDisp->lastSentHeight != xfDisp->targetHeight)
83 if (xfDisp->lastSentDesktopOrientation !=
87 if (xfDisp->lastSentDesktopScaleFactor !=
91 if (xfDisp->lastSentDeviceScaleFactor !=
95 if (xfDisp->fullscreen != xfDisp->xfc->fullscreen)
101 static BOOL xf_update_last_sent(xfDispContext* xfDisp)
103 rdpSettings* settings = NULL;
105 WINPR_ASSERT(xfDisp);
106 WINPR_ASSERT(xfDisp->xfc);
108 settings = xfDisp->xfc->common.context.settings;
109 WINPR_ASSERT(settings);
111 xfDisp->lastSentWidth = xfDisp->targetWidth;
112 xfDisp->lastSentHeight = xfDisp->targetHeight;
113 xfDisp->lastSentDesktopOrientation =
115 xfDisp->lastSentDesktopScaleFactor =
117 xfDisp->lastSentDeviceScaleFactor =
119 xfDisp->fullscreen = xfDisp->xfc->fullscreen;
123 static BOOL xf_disp_sendResize(xfDispContext* xfDisp)
126 xfContext* xfc = NULL;
127 rdpSettings* settings = NULL;
129 if (!xfDisp || !xfDisp->xfc)
133 settings = xfc->common.context.settings;
138 if (!xfDisp->activated || !xfDisp->disp)
141 if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY)
144 if (!xf_disp_settings_changed(xfDisp))
147 xfDisp->lastSentDate = GetTickCount64();
150 if (xfc->fullscreen && (mcount > 0))
154 if (xf_disp_sendLayout(xfDisp->disp, monitors, mcount) != CHANNEL_RC_OK)
159 layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
160 layout.Top = layout.Left = 0;
161 layout.Width = xfDisp->targetWidth;
162 layout.Height = xfDisp->targetHeight;
164 layout.DesktopScaleFactor =
168 const double dw = xfDisp->targetWidth / 75.0 * 25.4;
169 const double dh = xfDisp->targetHeight / 75.0 * 25.4;
170 layout.PhysicalWidth = (UINT32)lround(dw);
171 layout.PhysicalHeight = (UINT32)lround(dh);
173 if (IFCALLRESULT(CHANNEL_RC_OK, xfDisp->disp->SendMonitorLayout, xfDisp->disp, 1,
174 &layout) != CHANNEL_RC_OK)
178 return xf_update_last_sent(xfDisp);
181 static BOOL xf_disp_queueResize(xfDispContext* xfDisp, UINT32 width, UINT32 height)
183 if ((xfDisp->targetWidth == (INT64)width) && (xfDisp->targetHeight == (INT64)height))
185 xfDisp->targetWidth = width;
186 xfDisp->targetHeight = height;
187 xfDisp->lastSentDate = GetTickCount64();
188 return xf_disp_sendResize(xfDisp);
191 static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp)
193 XSizeHints* size_hints = NULL;
195 if (!(size_hints = XAllocSizeHints()))
198 size_hints->flags = PMinSize | PMaxSize | PWinGravity;
199 size_hints->win_gravity = NorthWestGravity;
200 size_hints->min_width = size_hints->min_height = 320;
201 size_hints->max_width = size_hints->max_height = 8192;
203 if (xfDisp->xfc->window)
204 XSetWMNormalHints(xfDisp->xfc->display, xfDisp->xfc->window->handle, size_hints);
210 static BOOL xf_disp_check_context(
void* context, xfContext** ppXfc, xfDispContext** ppXfDisp,
211 rdpSettings** ppSettings)
213 xfContext* xfc = NULL;
218 xfc = (xfContext*)context;
223 if (!xfc->common.context.settings)
227 *ppXfDisp = xfc->xfDisp;
228 *ppSettings = xfc->common.context.settings;
232 static void xf_disp_OnActivated(
void* context,
const ActivatedEventArgs* e)
234 xfContext* xfc = NULL;
235 xfDispContext* xfDisp = NULL;
236 rdpSettings* settings = NULL;
238 if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
241 if (xfDisp->activated && !xfc->fullscreen)
243 xf_disp_set_window_resizable(xfDisp);
245 if (e->firstActivation)
248 xf_disp_sendResize(xfDisp);
252 static void xf_disp_OnGraphicsReset(
void* context,
const GraphicsResetEventArgs* e)
254 xfContext* xfc = NULL;
255 xfDispContext* xfDisp = NULL;
256 rdpSettings* settings = NULL;
260 if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
265 xf_disp_set_window_resizable(xfDisp);
266 xf_disp_sendResize(xfDisp);
270 static void xf_disp_OnTimer(
void* context,
const TimerEventArgs* e)
272 xfContext* xfc = NULL;
273 xfDispContext* xfDisp = NULL;
274 rdpSettings* settings = NULL;
278 if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
281 if (!xfDisp->activated || xfc->fullscreen)
284 xf_disp_sendResize(xfDisp);
287 static void xf_disp_OnWindowStateChange(
void* context,
const WindowStateChangeEventArgs* e)
289 xfContext* xfc = NULL;
290 xfDispContext* xfDisp = NULL;
291 rdpSettings* settings = NULL;
295 if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings))
298 if (!xfDisp->activated || !xfc->fullscreen)
301 xf_disp_sendResize(xfDisp);
304 xfDispContext* xf_disp_new(xfContext* xfc)
306 xfDispContext* ret = NULL;
307 const rdpSettings* settings = NULL;
308 wPubSub* pubSub = NULL;
312 pubSub = xfc->common.context.pubSub;
313 WINPR_ASSERT(pubSub);
315 settings = xfc->common.context.settings;
316 WINPR_ASSERT(settings);
318 ret = calloc(1,
sizeof(xfDispContext));
326 if (XRRQueryExtension(xfc->display, &ret->eventBase, &ret->errorBase))
328 ret->haveXRandr = TRUE;
332 ret->lastSentWidth = ret->targetWidth =
334 ret->lastSentHeight = ret->targetHeight =
336 PubSub_SubscribeActivated(pubSub, xf_disp_OnActivated);
337 PubSub_SubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset);
338 PubSub_SubscribeTimer(pubSub, xf_disp_OnTimer);
339 PubSub_SubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange);
343 void xf_disp_free(xfDispContext* disp)
350 wPubSub* pubSub = disp->xfc->common.context.pubSub;
351 PubSub_UnsubscribeActivated(pubSub, xf_disp_OnActivated);
352 PubSub_UnsubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset);
353 PubSub_UnsubscribeTimer(pubSub, xf_disp_OnTimer);
354 PubSub_UnsubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange);
360 UINT xf_disp_sendLayout(DispClientContext* disp,
const rdpMonitor* monitors, UINT32 nmonitors)
362 UINT ret = CHANNEL_RC_OK;
363 xfDispContext* xfDisp = NULL;
364 rdpSettings* settings = NULL;
368 WINPR_ASSERT(monitors);
369 WINPR_ASSERT(nmonitors > 0);
371 xfDisp = (xfDispContext*)disp->custom;
372 WINPR_ASSERT(xfDisp);
373 WINPR_ASSERT(xfDisp->xfc);
375 settings = xfDisp->xfc->common.context.settings;
376 WINPR_ASSERT(settings);
381 return CHANNEL_RC_NO_MEMORY;
383 for (UINT32 i = 0; i < nmonitors; i++)
388 layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
389 layout->Left = monitor->x;
390 layout->Top = monitor->y;
391 layout->Width = monitor->width;
392 layout->Height = monitor->height;
393 layout->Orientation = ORIENTATION_LANDSCAPE;
394 layout->PhysicalWidth = monitor->attributes.physicalWidth;
395 layout->PhysicalHeight = monitor->attributes.physicalHeight;
397 switch (monitor->attributes.orientation)
400 layout->Orientation = ORIENTATION_PORTRAIT;
404 layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
408 layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
420 layout->Orientation = ORIENTATION_LANDSCAPE;
424 layout->DesktopScaleFactor =
426 layout->DeviceScaleFactor =
430 ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
435 BOOL xf_disp_handle_xevent(xfContext* xfc,
const XEvent* event)
437 xfDispContext* xfDisp = NULL;
438 rdpSettings* settings = NULL;
440 UINT32 maxHeight = 0;
445 xfDisp = xfc->xfDisp;
450 settings = xfc->common.context.settings;
455 if (!xfDisp->haveXRandr || !xfDisp->disp)
460 if (event->type != xfDisp->eventBase + RRScreenChangeNotify)
464 xf_detect_monitors(xfc, &maxWidth, &maxHeight);
467 return xf_disp_sendLayout(xfDisp->disp, monitors, mcount) == CHANNEL_RC_OK;
470 BOOL xf_disp_handle_configureNotify(xfContext* xfc,
int width,
int height)
472 xfDispContext* xfDisp = NULL;
477 xfDisp = xfc->xfDisp;
482 return xf_disp_queueResize(xfDisp, width, height);
485 static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
486 UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
489 xfDispContext* xfDisp = NULL;
490 rdpSettings* settings = NULL;
494 xfDisp = (xfDispContext*)disp->custom;
495 WINPR_ASSERT(xfDisp);
496 WINPR_ASSERT(xfDisp->xfc);
498 settings = xfDisp->xfc->common.context.settings;
499 WINPR_ASSERT(settings);
502 "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32
" MaxMonitorAreaFactorA: %" PRIu32
503 " MaxMonitorAreaFactorB: %" PRIu32
"",
504 maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
505 xfDisp->activated = TRUE;
508 return CHANNEL_RC_OK;
510 WLog_DBG(TAG,
"DisplayControlCapsPdu: setting the window as resizable");
511 return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
514 BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp)
516 rdpSettings* settings = NULL;
518 if (!xfDisp || !xfDisp->xfc || !disp)
521 settings = xfDisp->xfc->common.context.settings;
527 disp->custom = (
void*)xfDisp;
531 disp->DisplayControlCaps = xf_DisplayControlCaps;
537 XRRSelectInput(xfDisp->xfc->display, DefaultRootWindow(xfDisp->xfc->display),
538 RRScreenChangeNotifyMask);
547 BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp)
549 if (!xfDisp || !disp)
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 UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.