diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp index b467bf1e90..2c27a21372 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.cpp @@ -274,7 +274,7 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight int dpyWidth, dpyHeight; int glxMajorVersion, glxMinorVersion; int vidModeMajorVersion, vidModeMinorVersion; - Atom wmDelete; + Atom wmProtocols[3]; // attributes for a single buffered visual in RGBA format with at least // 8 bits per color and a 24 bit depth buffer @@ -393,9 +393,11 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), 0, 0, _twidth, _theight, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr); - // only set window title and handle wm_delete_events if in windowed mode - wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); - XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1); + // only set window title and handle WM_PROTOCOLS if in windowed mode + wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); + wmProtocols[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False); + wmProtocols[2] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False); + XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 3); XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL); XMapRaised(GLWin.dpy, GLWin.win); @@ -416,6 +418,37 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight return true; } +#if defined(HAVE_X11) && HAVE_X11 +void X11_EWMH_Fullscreen(int action) +{ + assert(action == _NET_WM_STATE_REMOVE || + action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE); + + XEvent xev; + + // Init X event structure for _NET_WM_STATE_FULLSCREEN client message + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.message_type = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False); + xev.xclient.window = GLWin.win; + xev.xclient.format = 32; + xev.xclient.data.l[0] = action; + xev.xclient.data.l[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False); + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + // Send the event + if (!XSendEvent(GLWin.dpy, DefaultRootWindow(GLWin.dpy), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev)) + { + ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode.\n"); + } +} +#endif + bool OpenGL_MakeCurrent() { #if defined(USE_WX) && USE_WX @@ -521,9 +554,23 @@ void OpenGL_Update() case KeyPress: key = XLookupKeysym((XKeyEvent*)&event, 0); if(key >= XK_F1 && key <= XK_F9) - FKeyPressed = key - 0xff4e; - else if (key == XK_Escape) + { + if(key == XK_F4 && ((event.xkey.state & Mod1Mask) == Mod1Mask)) FKeyPressed = 0x1b; + else + FKeyPressed = key - 0xff4e; + } + else if (key == XK_Escape) + { + if (!GLWin.fs) + { + X11_EWMH_Fullscreen(_NET_WM_STATE_TOGGLE); + XWithdrawWindow(GLWin.dpy,GLWin.win,GLWin.screen); + XMapRaised(GLWin.dpy,GLWin.win); + XRaiseWindow(GLWin.dpy,GLWin.win); + XFlush(GLWin.dpy); + } + } else { if(key == XK_Shift_L || key == XK_Shift_R) ShiftPressed = true; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h index 98a769606e..0b14e16b39 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h @@ -69,6 +69,13 @@ #include #include #include + +// EWMH state actions, see +// http://freedesktop.org/wiki/Specifications/wm-spec?action=show&redirect=Standards%2Fwm-spec +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + #if defined(HAVE_XXF86VM) && HAVE_XXF86VM #include #endif // XXF86VM