From ab0bc2a7f54637469e4891c392ede6719e3814c3 Mon Sep 17 00:00:00 2001 From: Andre Esteve Date: Sat, 28 Apr 2018 14:13:17 -0700 Subject: [PATCH] X11: Fix fullscreen toggle 1. Fix fullscreen toggle for window managers that do not have multimonitor fullscreen extension support 2. Fix current monitor detection 3. Fix calculation of vscreen boundaries when single monitor is being used 4. Fix start up position of window when starting (used to always go to the top left corener, now centered) Still a problem: 1. Window decorations do not show when going windowed 2. Smart resizing makes i3 really sad :( 3. Moving window across monitors and going fullscreen always maximizes on startup screen (when not using /multimon) --- client/X11/xf_client.c | 13 +++++- client/X11/xf_monitor.c | 95 ++++++++++++++++++++++++++--------------- client/X11/xf_window.c | 11 ++++- 3 files changed, 83 insertions(+), 36 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index fba5b4a1f..1d9ac164f 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -707,6 +707,16 @@ void xf_toggle_fullscreen(xfContext* xfc) WindowStateChangeEventArgs e; rdpContext* context = (rdpContext*) xfc; rdpSettings* settings = context->settings; + + /* + when debugging, ungrab keyboard when toggling fullscreen + to allow keyboard usage on the debugger + */ + if (xfc->debug) + { + XUngrabKeyboard(xfc->display, CurrentTime); + } + xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE; xfc->decorations = (xfc->fullscreen) ? FALSE : settings->Decorations; xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen); @@ -1794,7 +1804,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xf_PanningChangeEventHandler); #endif xfc->UseXThreads = TRUE; - //xfc->debug = TRUE; + /* uncomment below if debugging to prevent keyboard grap */ + /* xfc->debug = TRUE; */ if (xfc->UseXThreads) { diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index d2d3f073e..86a9208b1 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -146,6 +146,7 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) Window _dummy_w; int current_monitor = 0; Screen* screen; + MONITOR_INFO* monitor; #if defined WITH_XINERAMA || defined WITH_XRANDR int major, minor; #endif @@ -208,13 +209,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) vscreen->monitors[i].area.top = screenInfo[i].y_org; vscreen->monitors[i].area.right = screenInfo[i].x_org + screenInfo[i].width - 1; vscreen->monitors[i].area.bottom = screenInfo[i].y_org + screenInfo[i].height - 1; - - /* Determine which monitor that the mouse cursor is on */ - if ((mouse_x >= vscreen->monitors[i].area.left) && - (mouse_x <= vscreen->monitors[i].area.right) && - (mouse_y >= vscreen->monitors[i].area.top) && - (mouse_y <= vscreen->monitors[i].area.bottom)) - current_monitor = i; } } @@ -225,6 +219,46 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) 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 (i = 0; i < vscreen->nmonitors; i++) + { + if ((mouse_x >= vscreen->monitors[i].area.left) && + (mouse_x <= vscreen->monitors[i].area.right) && + (mouse_y >= vscreen->monitors[i].area.top) && + (mouse_y <= vscreen->monitors[i].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 ((!settings->UseMultimon && !settings->SpanMonitors) || + (settings->Workarea && !settings->RemoteApplicationMode)) + { + /* If no monitors were specified on the command-line then set the current monitor as active */ + if (!settings->NumMonitorIds) + { + settings->MonitorIds[0] = current_monitor; + } + + /* 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. + */ + settings->NumMonitorIds = 1; + } + /* 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 @@ -232,10 +266,26 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) */ if (settings->RemoteApplicationMode || !xf_GetWorkArea(xfc)) { - xfc->workArea.x = 0; - xfc->workArea.y = 0; - xfc->workArea.width = WidthOfScreen(xfc->screen); - xfc->workArea.height = HeightOfScreen(xfc->screen); + /* + 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 (settings->NumMonitorIds == 1) + { + monitor = vscreen->monitors + current_monitor; + 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); + } } if (settings->Fullscreen) @@ -288,26 +338,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) *pMaxHeight = settings->DesktopHeight; } - if (!settings->Fullscreen && !settings->Workarea && !settings->UseMultimon) - goto out; - - /* If single monitor fullscreen OR workarea without remote app */ - if ((settings->Fullscreen && !settings->UseMultimon && !settings->SpanMonitors) || - (settings->Workarea && !settings->RemoteApplicationMode)) - { - /* If no monitors were specified on the command-line then set the current monitor as active */ - if (!settings->NumMonitorIds) - { - settings->MonitorIds[0] = current_monitor; - } - - /* 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. - */ - settings->NumMonitorIds = 1; - } - /* Create array of all active monitors by taking into account monitors requested on the command-line */ for (i = 0; i < vscreen->nmonitors; i++) { @@ -406,8 +436,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) vB = destB; } - settings->DesktopPosX = vX; - settings->DesktopPosY = vY; vscreen->area.left = 0; vscreen->area.right = vR - vX - 1; vscreen->area.top = 0; @@ -489,7 +517,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->MonitorCount) settings->SupportMonitorLayoutPdu = TRUE; -out: #ifdef USABLE_XRANDR if (rrmonitors) diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index d28a34d93..fabc1d845 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -153,8 +153,11 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) int startX, startY; UINT32 width = window->width; UINT32 height = window->height; + /* xfc->decorations is set by caller depending on settings and whether it is fullscreen or not */ window->decorations = xfc->decorations; + /* show/hide decorations (e.g. title bar) as guided by xfc->decorations */ xf_SetWindowDecorations(xfc, window->handle, window->decorations); + DEBUG_X11(TAG, "X window decoration set to %d", (int)window->decorations); if (fullscreen) { @@ -194,7 +197,12 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) startY += xfc->context.settings->MonitorLocalShiftY; } - if (xfc->_NET_WM_FULLSCREEN_MONITORS != None) + /* + It is safe to proceed with simply toogling _NET_WM_STATE_FULLSCREEN window state on the following conditions: + - The window manager supports multiple monitor full screen + - The user requested to use a single monitor to render the remote desktop + */ + if (xfc->_NET_WM_FULLSCREEN_MONITORS != None || settings->MonitorCount == 1) { xf_ResizeDesktopWindow(xfc, window, width, height); @@ -286,6 +294,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) width = xfc->vscreen.area.right - xfc->vscreen.area.left + 1; height = xfc->vscreen.area.bottom - xfc->vscreen.area.top + 1; + DEBUG_X11("X window move and resize %dx%d@%dx%d", startX, startY, width, height); xf_ResizeDesktopWindow(xfc, window, width, height); XMoveWindow(xfc->display, window->handle, startX, startY); }