diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index cbeed28e5..734a17f46 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -20,6 +20,9 @@ #include #include #include + +#include + #include #ifdef WITH_XRANDR @@ -37,7 +40,7 @@ #include #define TAG CLIENT_TAG("x11disp") -#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */ +#define RESIZE_MIN_DELAY_NS 200000UL /* minimum delay in ms between two resizes */ struct s_xfDispContext { @@ -59,8 +62,12 @@ struct s_xfDispContext UINT32 lastSentDesktopScaleFactor; UINT32 lastSentDeviceScaleFactor; BYTE reserved3[4]; + FreeRDP_TimerID timerID; }; +static BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp, + rdpSettings** ppSettings); +static BOOL xf_disp_sendResize(xfDispContext* xfDisp, BOOL fromTimer); static UINT xf_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors, UINT32 nmonitors); @@ -120,31 +127,71 @@ static BOOL xf_update_last_sent(xfDispContext* xfDisp) return TRUE; } -static BOOL xf_disp_sendResize(xfDispContext* xfDisp) +static uint64_t xf_disp_OnTimer(rdpContext* context, WINPR_ATTR_UNUSED void* userdata, + WINPR_ATTR_UNUSED FreeRDP_TimerID timerID, + WINPR_ATTR_UNUSED uint64_t timestamp, + WINPR_ATTR_UNUSED uint64_t interval) + +{ + xfContext* xfc = NULL; + xfDispContext* xfDisp = NULL; + rdpSettings* settings = NULL; + + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) + return interval; + + if (!xfDisp->activated) + return interval; + + xf_disp_sendResize(xfDisp, TRUE); + xfDisp->timerID = 0; + return 0; +} + +static BOOL update_timer(xfDispContext* xfDisp, uint64_t intervalNS) +{ + WINPR_ASSERT(xfDisp); + + if (xfDisp->timerID == 0) + { + rdpContext* context = &xfDisp->xfc->common.context; + + xfDisp->timerID = freerdp_timer_add(context, intervalNS, xf_disp_OnTimer, NULL, true); + } + return TRUE; +} + +BOOL xf_disp_sendResize(xfDispContext* xfDisp, BOOL fromTimer) { DISPLAY_CONTROL_MONITOR_LAYOUT layout = { 0 }; - xfContext* xfc = NULL; - rdpSettings* settings = NULL; if (!xfDisp || !xfDisp->xfc) return FALSE; - xfc = xfDisp->xfc; - settings = xfc->common.context.settings; + /* If there is already a timer running skip the update and wait for the timer to expire. */ + if ((xfDisp->timerID != 0) && !fromTimer) + return TRUE; + + xfContext* xfc = xfDisp->xfc; + rdpSettings* settings = xfc->common.context.settings; if (!settings) return FALSE; if (!xfDisp->activated || !xfDisp->disp) - return TRUE; + return update_timer(xfDisp, RESIZE_MIN_DELAY_NS); - if (GetTickCount64() - xfDisp->lastSentDate < RESIZE_MIN_DELAY) - return TRUE; + const uint64_t diff = winpr_GetTickCount64NS() - xfDisp->lastSentDate; + if (diff < RESIZE_MIN_DELAY_NS) + { + const uint64_t interval = RESIZE_MIN_DELAY_NS - diff; + return update_timer(xfDisp, interval); + } if (!xf_disp_settings_changed(xfDisp)) return TRUE; - xfDisp->lastSentDate = GetTickCount64(); + xfDisp->lastSentDate = winpr_GetTickCount64NS(); const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); if (mcount > 1) @@ -184,8 +231,7 @@ static BOOL xf_disp_queueResize(xfDispContext* xfDisp, UINT32 width, UINT32 heig return TRUE; xfDisp->targetWidth = width; xfDisp->targetHeight = height; - xfDisp->lastSentDate = GetTickCount64(); - return xf_disp_sendResize(xfDisp); + return xf_disp_sendResize(xfDisp, FALSE); } static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp) @@ -207,8 +253,8 @@ static BOOL xf_disp_set_window_resizable(xfDispContext* xfDisp) return TRUE; } -static BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp, - rdpSettings** ppSettings) +BOOL xf_disp_check_context(void* context, xfContext** ppXfc, xfDispContext** ppXfDisp, + rdpSettings** ppSettings) { xfContext* xfc = NULL; @@ -245,7 +291,7 @@ static void xf_disp_OnActivated(void* context, const ActivatedEventArgs* e) if (e->firstActivation) return; - xf_disp_sendResize(xfDisp); + xf_disp_sendResize(xfDisp, FALSE); } } @@ -263,27 +309,10 @@ static void xf_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* if (xfDisp->activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen)) { xf_disp_set_window_resizable(xfDisp); - xf_disp_sendResize(xfDisp); + xf_disp_sendResize(xfDisp, FALSE); } } -static void xf_disp_OnTimer(void* context, const TimerEventArgs* e) -{ - xfContext* xfc = NULL; - xfDispContext* xfDisp = NULL; - rdpSettings* settings = NULL; - - WINPR_UNUSED(e); - - if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) - return; - - if (!xfDisp->activated) - return; - - xf_disp_sendResize(xfDisp); -} - static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEventArgs* e) { xfContext* xfc = NULL; @@ -298,7 +327,7 @@ static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEv if (!xfDisp->activated || !xfc->fullscreen) return; - xf_disp_sendResize(xfDisp); + xf_disp_sendResize(xfDisp, FALSE); } xfDispContext* xf_disp_new(xfContext* xfc) @@ -335,7 +364,6 @@ xfDispContext* xf_disp_new(xfContext* xfc) freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight); PubSub_SubscribeActivated(pubSub, xf_disp_OnActivated); PubSub_SubscribeGraphicsReset(pubSub, xf_disp_OnGraphicsReset); - PubSub_SubscribeTimer(pubSub, xf_disp_OnTimer); PubSub_SubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange); return ret; } @@ -350,7 +378,6 @@ void xf_disp_free(xfDispContext* disp) 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); PubSub_UnsubscribeWindowStateChange(pubSub, xf_disp_OnWindowStateChange); }