Fullscreen without _NET_WM_FULLSCREEN_MONITORS

Some window managers do not support _NET_WM_FULLSCREEN_MONITORS.
In that case multimonitor fullscreen does not properly work, so
add a path resizing the window over all screens instead.
Based on @erbth pull request, adding proper X11 atom checks.
This commit is contained in:
Armin Novak 2017-12-20 12:02:23 +01:00
parent 80a49f46dc
commit 1628045f67
3 changed files with 177 additions and 36 deletions

View File

@ -30,6 +30,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef WITH_XRENDER
#include <X11/extensions/Xrender.h>
@ -1738,6 +1739,19 @@ static int xfreerdp_client_stop(rdpContext* context)
return 0;
}
static Atom get_supported_atom(xfContext* xfc, const char* atomName)
{
unsigned long i;
const Atom atom = XInternAtom(xfc->display, atomName, False);
for (i = 0; i < xfc->supportedAtomCount; i++)
{
if (xfc->supportedAtoms[i] == atom)
return atom;
}
return None;
}
static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
{
xfContext* xfc = (xfContext*) instance->context;
@ -1792,20 +1806,48 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
goto fail_create_mutex;
}
xfc->xfds = ConnectionNumber(xfc->display);
xfc->screen_number = DefaultScreen(xfc->display);
xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);
xfc->depth = DefaultDepthOfScreen(xfc->screen);
xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst);
xfc->invert = TRUE;
xfc->complex_regions = TRUE;
xfc->_NET_SUPPORTED = XInternAtom(xfc->display, "_NET_SUPPORTED", True);
xfc->_NET_SUPPORTING_WM_CHECK = XInternAtom(xfc->display, "_NET_SUPPORTING_WM_CHECK", True);
if ((xfc->_NET_SUPPORTED != None) && (xfc->_NET_SUPPORTING_WM_CHECK != None))
{
Atom actual_type;
int actual_format;
unsigned long nitems, after;
unsigned char* data = NULL;
int status = XGetWindowProperty(xfc->display, RootWindowOfScreen(xfc->screen),
xfc->_NET_SUPPORTED, 0, 1024, False, XA_ATOM,
&actual_type, &actual_format, &nitems, &after, &data);
if ((status == Success) && (actual_type == XA_ATOM) && (actual_format == 32))
{
xfc->supportedAtomCount = nitems;
xfc->supportedAtoms = calloc(nitems, sizeof(Atom));
memcpy(xfc->supportedAtoms, data, nitems * sizeof(Atom));
}
if (data)
XFree(data);
}
xfc->_NET_WM_ICON = XInternAtom(xfc->display, "_NET_WM_ICON", False);
xfc->_MOTIF_WM_HINTS = XInternAtom(xfc->display, "_MOTIF_WM_HINTS", False);
xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP",
False);
xfc->_NET_WORKAREA = XInternAtom(xfc->display, "_NET_WORKAREA", False);
xfc->_NET_WM_STATE = XInternAtom(xfc->display, "_NET_WM_STATE", False);
xfc->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfc->display,
"_NET_WM_STATE_FULLSCREEN", False);
xfc->_NET_WM_STATE = get_supported_atom(xfc, "_NET_WM_STATE");
xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN");
xfc->_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(xfc->display,
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
xfc->_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(xfc->display,
"_NET_WM_STATE_MAXIMIZED_VERT", False);
xfc->_NET_WM_FULLSCREEN_MONITORS = XInternAtom(xfc->display,
"_NET_WM_FULLSCREEN_MONITORS", False);
xfc->_NET_WM_FULLSCREEN_MONITORS = get_supported_atom(xfc, "_NET_WM_FULLSCREEN_MONITORS");
xfc->_NET_WM_NAME = XInternAtom(xfc->display, "_NET_WM_NAME", False);
xfc->_NET_WM_PID = XInternAtom(xfc->display, "_NET_WM_PID", False);
xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE",
@ -1832,13 +1874,6 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False);
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
xfc->xfds = ConnectionNumber(xfc->display);
xfc->screen_number = DefaultScreen(xfc->display);
xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);
xfc->depth = DefaultDepthOfScreen(xfc->screen);
xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst);
xfc->invert = TRUE;
xfc->complex_regions = TRUE;
xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds,
WINPR_FD_READ);
@ -1915,6 +1950,8 @@ static void xfreerdp_client_free(freerdp* instance, rdpContext* context)
free(xfc->vscreen.monitors);
xfc->vscreen.monitors = NULL;
}
free(xfc->supportedAtoms);
}
int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)

View File

@ -174,7 +174,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen)
}
/* Determine the x,y starting location for the fullscreen window */
if (fullscreen && xfc->context.settings->MonitorCount)
if (fullscreen)
{
/* Initialize startX and startY with reasonable values */
startX = xfc->context.settings->MonitorDefArray[0].x;
@ -190,9 +190,12 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen)
/* Lastly apply any monitor shift(translation from remote to local coordinate system)
* to startX and startY values
*/
startX = startX + xfc->context.settings->MonitorLocalShiftX;
startY = startY + xfc->context.settings->MonitorLocalShiftY;
startX += xfc->context.settings->MonitorLocalShiftX;
startY += xfc->context.settings->MonitorLocalShiftY;
}
if (xfc->_NET_WM_FULLSCREEN_MONITORS != None)
{
/* Set monitor bounds */
if (settings->MonitorCount > 1)
{
@ -203,25 +206,119 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen)
xfc->fullscreenMonitors.right,
1);
}
xf_ResizeDesktopWindow(xfc, window, width, height);
if (fullscreen)
{
/* enter full screen: move the window before adding NET_WM_STATE_FULLSCREEN */
XMoveWindow(xfc->display, window->handle, startX, startY);
}
/* Set the fullscreen state */
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
xfc->_NET_WM_STATE_FULLSCREEN, 0, 0);
if (!fullscreen)
{
/* leave full screen: move the window after removing NET_WM_STATE_FULLSCREEN */
XMoveWindow(xfc->display, window->handle, startX, startY);
}
}
xf_ResizeDesktopWindow(xfc, window, width, height);
if (fullscreen)
else
{
/* enter full screen: move the window before adding NET_WM_STATE_FULLSCREEN */
XMoveWindow(xfc->display, window->handle, startX, startY);
}
if (fullscreen)
{
xf_SetWindowDecorations(xfc, window->handle, FALSE);
/* Set the fullscreen state */
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
xfc->_NET_WM_STATE_FULLSCREEN, 0, 0);
if (xfc->fullscreenMonitors.top)
{
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_ADD,
xfc->fullscreenMonitors.top, 0, 0);
}
else
{
XSetWindowAttributes xswa;
xswa.override_redirect = True;
XChangeWindowAttributes(xfc->display, window->handle, CWOverrideRedirect, &xswa);
XRaiseWindow(xfc->display, window->handle);
xswa.override_redirect = False;
XChangeWindowAttributes(xfc->display, window->handle, CWOverrideRedirect, &xswa);
}
if (!fullscreen)
{
/* leave full screen: move the window after removing NET_WM_STATE_FULLSCREEN */
XMoveWindow(xfc->display, window->handle, startX, startY);
/* if window is in maximized state, save and remove */
if (xfc->_NET_WM_STATE_MAXIMIZED_VERT != None)
{
BYTE state;
unsigned long nitems;
unsigned long bytes;
BYTE* prop;
if (xf_GetWindowProperty(xfc, window->handle, xfc->_NET_WM_STATE, 255, &nitems, &bytes, &prop))
{
state = 0;
while (nitems-- > 0)
{
if (((Atom*) prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_VERT)
state |= 0x01;
if (((Atom*) prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_HORZ)
state |= 0x02;
}
if (state)
{
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_REMOVE, xfc->_NET_WM_STATE_MAXIMIZED_VERT,
0, 0);
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_REMOVE, xfc->_NET_WM_STATE_MAXIMIZED_HORZ,
0, 0);
xfc->savedMaximizedState = state;
}
XFree(prop);
}
}
width = xfc->vscreen.area.right - xfc->vscreen.area.left + 1;
height = xfc->vscreen.area.bottom - xfc->vscreen.area.top + 1;
xf_ResizeDesktopWindow(xfc, window, width, height);
XMoveWindow(xfc->display, window->handle, startX, startY);
}
else
{
xf_SetWindowDecorations(xfc, window->handle, window->decorations);
xf_ResizeDesktopWindow(xfc, window, width, height);
XMoveWindow(xfc->display, window->handle, startX, startY);
if (xfc->fullscreenMonitors.top)
{
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_REMOVE,
xfc->fullscreenMonitors.top, 0, 0);
}
/* restore maximized state, if the window was maximized before setting fullscreen */
if (xfc->savedMaximizedState & 0x01)
{
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_ADD, xfc->_NET_WM_STATE_MAXIMIZED_VERT,
0, 0);
}
if (xfc->savedMaximizedState & 0x02)
{
xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4,
_NET_WM_STATE_ADD, xfc->_NET_WM_STATE_MAXIMIZED_HORZ,
0, 0);
}
xfc->savedMaximizedState = 0;
}
}
}
@ -239,7 +336,7 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property,
return FALSE;
status = XGetWindowProperty(xfc->display, window,
property, 0, length, FALSE, AnyPropertyType,
property, 0, length, False, AnyPropertyType,
&actual_type, &actual_format, nitems, bytes, prop);
if (status != Success)
@ -480,7 +577,7 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width,
int height)
{
XSizeHints* size_hints;
rdpSettings *settings = xfc->context.settings;
rdpSettings* settings = xfc->context.settings;
if (!xfc || !window)
return;
@ -494,8 +591,8 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width,
size_hints->max_width = size_hints->max_height = 16384;
XSetWMNormalHints(xfc->display, window->handle, size_hints);
XResizeWindow(xfc->display, window->handle, width, height);
#ifdef WITH_XRENDER
if (!settings->SmartSizing)
#endif
{
@ -595,7 +692,7 @@ void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name)
}
static void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width,
int* height)
int* height)
{
int vscreen_width;
int vscreen_height;

View File

@ -173,6 +173,9 @@ struct xf_context
VIRTUAL_SCREEN vscreen;
void* xv_context;
Atom* supportedAtoms;
unsigned long supportedAtomCount;
Atom UTF8_STRING;
Atom _NET_WM_ICON;
@ -180,6 +183,9 @@ struct xf_context
Atom _NET_CURRENT_DESKTOP;
Atom _NET_WORKAREA;
Atom _NET_SUPPORTED;
ATOM _NET_SUPPORTING_WM_CHECK;
Atom _NET_WM_STATE;
Atom _NET_WM_STATE_FULLSCREEN;
Atom _NET_WM_STATE_MAXIMIZED_HORZ;
@ -213,8 +219,8 @@ struct xf_context
RdpeiClientContext* rdpei;
RdpgfxClientContext* gfx;
EncomspClientContext* encomsp;
xfDispContext *xfDisp;
DispClientContext *disp;
xfDispContext* xfDisp;
DispClientContext* disp;
RailClientContext* rail;
wHashTable* railWindows;
@ -224,6 +230,7 @@ struct xf_context
/* value to be sent over wire for each logical client mouse button */
int button_map[NUM_BUTTONS_MAPPED];
BYTE savedMaximizedState;
};
BOOL xf_create_window(xfContext* xfc);