Permalink
Browse files

X11: use override_redirect if window manager doesn't support full scr…

…een or standalone
  • Loading branch information...
1 parent 5dee1c7 commit daa9d27d44c1942fe9241b14b7c492315b1604af @elupus committed Jul 19, 2012
@@ -408,6 +408,17 @@ bool CWinEventsX11::ProcessMotion(XMotionEvent& xmotion)
return g_application.OnEvent(newEvent);
}
+bool CWinEventsX11::ProcessEnter(XCrossingEvent& xcrossing)
+{
+ return true;
+}
+
+bool CWinEventsX11::ProcessLeave(XCrossingEvent& xcrossing)
+{
+ g_Mouse.SetActive(false);
+ return true;
+}
+
bool CWinEventsX11::ProcessButtonPress(XButtonEvent& xbutton)
{
XBMC_Event newEvent = {0};
@@ -491,6 +502,25 @@ bool CWinEventsX11::Process()
if (XFilterEvent(&xevent, None))
continue;
+
+ if(!g_Windowing.IsWindowManagerControlled())
+ {
+ switch (xevent.type)
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ XSetInputFocus(m_display, m_window, RevertToParent, xevent.xbutton.time);
+ break;
+ case KeyPress:
+ case KeyRelease:
+ XSetInputFocus(m_display, m_window, RevertToParent, xevent.xkey.time);
+ break;
+ case MapNotify:
+ XSetInputFocus(m_display, m_window, RevertToParent, CurrentTime);
+ break;
+ }
+ }
+
switch (xevent.type)
{
case MapNotify:
@@ -529,8 +559,12 @@ bool CWinEventsX11::Process()
ret |= ProcessKeyRelease(xevent.xkey);
break;
+ case EnterNotify:
+ ret |= ProcessEnter(xevent.xcrossing);
+ break;
+
case LeaveNotify:
- g_Mouse.SetActive(false);
+ ret |= ProcessLeave(xevent.xcrossing);
break;
case MotionNotify:
@@ -47,6 +47,8 @@ class CWinEventsX11 : public CWinEventsBase
bool ProcessClientMessage(XClientMessageEvent& xclient);
bool ProcessFocusIn (XFocusInEvent& xfocus);
bool ProcessFocusOut (XFocusOutEvent& xfocus);
+ bool ProcessEnter (XCrossingEvent& xcrossing);
+ bool ProcessLeave (XCrossingEvent& xcrossing);
bool ProcessKey(XBMC_Event &event, int repeatDelay);
bool ProcessKeyRepeat();
bool ProcessShortcuts(XBMC_Event& event);
@@ -34,6 +34,7 @@
#include <X11/Xatom.h>
#include "cores/VideoRenderers/RenderManager.h"
#include "utils/TimeUtils.h"
+#include "Application.h"
#if defined(HAS_XRANDR)
#include <X11/extensions/Xrandr.h>
@@ -79,6 +80,8 @@ CWinSystemX11::CWinSystemX11() : CWinSystemBase()
m_invisibleCursor = 0;
m_outputName = "";
m_outputIndex = 0;
+ m_wm_fullscreen = false;
+ m_wm_controlled = false;
XSetErrorHandler(XErrorHandler);
}
@@ -274,6 +277,72 @@ static Pixmap AllocateIconPixmap(Display* dpy, Window w)
return icon;
}
+void CWinSystemX11::ProbeWindowManager()
+{
+ int res, format;
+ Atom *items, type;
+ unsigned long bytes_after, nitems;
+ unsigned char *prop_return;
+ int wm_window_id;
+
+ m_wm = false;
+ m_wm_name = "";
+ m_wm_fullscreen = false;
+
+ res = XGetWindowProperty(m_dpy, XRootWindow(m_dpy, m_visual->screen), m_NET_SUPPORTING_WM_CHECK,
+ 0, 16384, False, AnyPropertyType, &type, &format,
+ &nitems, &bytes_after, &prop_return);
+ if(res != Success || nitems == 0 || prop_return == NULL)
+ {
+ CLog::Log(LOGDEBUG, "CWinSystemX11::ProbeWindowManager - No window manager found (NET_SUPPORTING_WM_CHECK not set)");
+ return;
+ }
+
+ wm_window_id = *(int *)prop_return;
+ XFree(prop_return);
+ prop_return = NULL;
+
+ res = XGetWindowProperty(m_dpy, wm_window_id, m_NET_WM_NAME,
+ 0, 16384, False, AnyPropertyType, &type, &format,
+ &nitems, &bytes_after, &prop_return);
+ if(res != Success || nitems == 0 || prop_return == NULL)
+ {
+ CLog::Log(LOGDEBUG, "CWinSystemX11::ProbeWindowManager - No window manager found (NET_WM_NAME not set on wm window)");
+ return;
+ }
+ m_wm_name = (char *)prop_return;
+ XFree(prop_return);
+ prop_return = NULL;
+
+ res = XGetWindowProperty(m_dpy, XRootWindow(m_dpy, m_visual->screen), m_NET_SUPPORTED,
+ 0, 16384, False, AnyPropertyType, &type, &format,
+ &nitems, &bytes_after, &prop_return);
+ if(res != Success || nitems == 0 || prop_return == NULL)
+ {
+ CLog::Log(LOGDEBUG, "CWinSystemX11::ProbeWindowManager - No window manager found (NET_SUPPORTING_WM_CHECK not set)");
+ return;
+ }
+ items = (Atom *)prop_return;
+ m_wm = true;
+ for(unsigned long i = 0; i < nitems; i++)
+ {
+ if(items[i] == m_NET_WM_STATE_FULLSCREEN)
+ m_wm_fullscreen = true;
+ }
+ XFree(prop_return);
+ prop_return = NULL;
+
+ CLog::Log(LOGDEBUG, "CWinSystemX11::ProbeWindowManager - Window manager (%s) detected%s",
+ m_wm_name.c_str(),
+ m_wm_fullscreen ? ", can fullscreen" : "");
+
+ if(m_wm_fullscreen && g_application.IsStandAlone())
+ {
+ CLog::Log(LOGDEBUG, "CWinSystemX11::ProbeWindowManager - Disable window manager fullscreen due to standalone");
+ m_wm_fullscreen = false;
+ }
+}
+
bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
{
@@ -285,13 +354,28 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
DestroyWindow();
}
+ /* update available atoms */
+ m_NET_SUPPORTING_WM_CHECK = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ m_NET_WM_STATE = XInternAtom(m_dpy, "_NET_WM_STATE", False);
+ m_NET_WM_STATE_FULLSCREEN = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ m_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ m_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ m_NET_SUPPORTED = XInternAtom(m_dpy, "_NET_SUPPORTED", False);
+ m_NET_WM_STATE_FULLSCREEN = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ m_NET_SUPPORTING_WM_CHECK = XInternAtom(m_dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ m_NET_WM_NAME = XInternAtom(m_dpy, "_NET_WM_NAME", False);
+ m_WM_DELETE_WINDOW = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
+
/* higher layer should have set m_visual */
if(m_visual == NULL)
{
CLog::Log(LOGERROR, "CWinSystemX11::CreateNewWindow - no visual setup");
return false;
}
+ /* figure out what the window manager support */
+ ProbeWindowManager();
+
XSetWindowAttributes swa = {0};
#if defined(HAS_XRANDR)
@@ -303,7 +387,10 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
}
#endif
- swa.override_redirect = False;
+ if(m_wm_fullscreen)
+ swa.override_redirect = 0;
+ else
+ swa.override_redirect = fullScreen ? 1 : 0;
swa.border_pixel = fullScreen ? 0 : 5;
if(m_visual->visual == DefaultVisual(m_dpy, m_visual->screen))
@@ -323,13 +410,13 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask,
&swa);
- if (fullScreen)
+ if(m_wm_fullscreen)
{
- Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", False);
- XChangeProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1);
+ if (fullScreen)
+ XChangeProperty(m_dpy, m_wmWindow, m_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &m_NET_WM_STATE_FULLSCREEN, 1);
+ else
+ XDeleteProperty(m_dpy, m_wmWindow, m_NET_WM_STATE);
}
- else
- XDeleteProperty(m_dpy, m_wmWindow, XInternAtom(m_dpy, "_NET_WM_STATE", False));
m_invisibleCursor = AllocateInvisibleCursor(m_dpy, m_wmWindow);
XDefineCursor(m_dpy, m_wmWindow, m_invisibleCursor);
@@ -354,8 +441,7 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
XFree(wm_hints);
// register interest in the delete window message
- Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
- XSetWMProtocols(m_dpy, m_wmWindow, &wmDeleteMessage, 1);
+ XSetWMProtocols(m_dpy, m_wmWindow, &m_WM_DELETE_WINDOW, 1);
XMapRaised(m_dpy, m_wmWindow);
XSync(m_dpy, True);
@@ -451,13 +537,6 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
return true;
}
- XSetWindowAttributes attr = {0};
- if(fullScreen)
- attr.border_pixel = 0;
- else
- attr.border_pixel = 5;
- XChangeWindowAttributes(m_dpy, m_wmWindow, CWBorderPixel, &attr);
-
int x = 0, y = 0;
#if defined(HAS_XRANDR)
XOutput out = g_xrandr.GetOutput(res.iInternal, res.strOutput);
@@ -468,15 +547,17 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
}
#endif
+
+ if(!fullScreen)
+ {
+ x = m_nLeft;
+ y = m_nTop;
+ }
+
XWindowAttributes attr2;
XGetWindowAttributes(m_dpy, m_wmWindow, &attr2);
- Atom m_NET_WM_STATE = XInternAtom(m_dpy, "_NET_WM_STATE", False);
- Atom m_NET_WM_STATE_FULLSCREEN = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True);
- Atom m_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_VERT", True);
- Atom m_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", True);
-
- if(m_NET_WM_STATE_FULLSCREEN)
+ if(m_wm_fullscreen)
{
/* if on other screen, we must move it first, otherwise
* the window manager will fullscreen it on the wrong
@@ -508,8 +589,6 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
{
e.xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
e.xclient.data.l[1] = m_NET_WM_STATE_FULLSCREEN;
- e.xclient.data.l[2] = m_NET_WM_STATE_MAXIMIZED_VERT;
- e.xclient.data.l[3] = m_NET_WM_STATE_MAXIMIZED_HORZ;
}
XSendEvent(m_dpy, RootWindow(m_dpy, m_visual->screen), False,
@@ -519,15 +598,36 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
}
else
{
+ XSetWindowAttributes attr = {0};
+ if(fullScreen)
+ attr.override_redirect = 1;
+ else
+ attr.override_redirect = 0;
+ /* if override_redirect changes, we need to notify
+ * WM by reparenting the window to root */
+ if(attr.override_redirect != attr2.override_redirect)
+ {
+ XUnmapWindow (m_dpy, m_wmWindow);
+ XChangeWindowAttributes(m_dpy, m_wmWindow, CWOverrideRedirect, &attr);
+ XReparentWindow (m_dpy, m_wmWindow, RootWindow(m_dpy, res.iInternal), x, y);
+ XGetWindowAttributes (m_dpy, m_wmWindow, &attr2);
+ }
+
+ XWindowChanges cw;
+ cw.x = x;
+ cw.y = y;
if(fullScreen)
- XMoveResizeWindow(m_dpy, m_wmWindow, x, y, res.iWidth, res.iHeight);
+ cw.border_width = 0;
else
- XResizeWindow(m_dpy, m_wmWindow, res.iWidth, res.iHeight);
+ cw.border_width = 5;
+ cw.width = res.iWidth;
+ cw.height = res.iHeight;
+ XConfigureWindow(m_dpy, m_wmWindow, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &cw);
}
- XRaiseWindow(m_dpy, m_wmWindow);
+ XMapRaised(m_dpy, m_wmWindow);
XSync(m_dpy, False);
RefreshWindowState();
@@ -681,6 +781,8 @@ void CWinSystemX11::RefreshWindowState()
m_nHeight = attr.height;
m_nLeft = attr.x;
m_nTop = attr.y;
+
+ m_wm_controlled = attr.override_redirect == 0 && m_wm_name;
}
void CWinSystemX11::ShowOSMouse(bool show)
@@ -76,7 +76,10 @@ class CWinSystemX11 : public CWinSystemBase
XVisualInfo* GetVisual() { return m_visual; }
void NotifyXRREvent();
+ bool IsWindowManagerControlled() { return m_wm_controlled; }
+
protected:
+ void ProbeWindowManager();
void RefreshWindowState();
void CheckDisplayEvents();
void OnLostDevice();
@@ -98,6 +101,20 @@ class CWinSystemX11 : public CWinSystemBase
CStdString m_outputName;
int m_outputIndex;
+ bool m_wm;
+ CStdString m_wm_name;
+ bool m_wm_fullscreen;
+ bool m_wm_controlled;
+
+ Atom m_NET_SUPPORTING_WM_CHECK;
+ Atom m_NET_WM_STATE;
+ Atom m_NET_WM_STATE_FULLSCREEN;
+ Atom m_NET_WM_STATE_MAXIMIZED_VERT;
+ Atom m_NET_WM_STATE_MAXIMIZED_HORZ;
+ Atom m_NET_SUPPORTED;
+ Atom m_NET_WM_NAME;
+ Atom m_WM_DELETE_WINDOW;
+
private:
bool IsSuitableVisual(XVisualInfo *vInfo);
static int XErrorHandler(Display* dpy, XErrorEvent* error);

0 comments on commit daa9d27

Please sign in to comment.