--- a/src/video/x11/SDL_x11sym.h Thu Sep 27 00:53:37 2012 -0400
+++ b/src/video/x11/SDL_x11sym.h Thu Sep 27 03:36:13 2012 -0400
@@ -30,6 +30,7 @@
SDL_X11_SYM(int,XChangePointerControl,(Display* a,Bool b,Bool c,int d,int e,int f),(a,b,c,d,e,f),return)
SDL_X11_SYM(int,XChangeProperty,(Display* a,Window b,Atom c,Atom d,int e,int f,_Xconst unsigned char* g,int h),(a,b,c,d,e,f,g,h),return)
SDL_X11_SYM(Bool,XCheckIfEvent,(Display* a,XEvent *b,Bool (*c)(Display*,XEvent*,XPointer),XPointer d),(a,b,c,d),return)
+SDL_X11_SYM(int,XClearWindow,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XCloseDisplay,(Display* a),(a),return)
SDL_X11_SYM(int,XConvertSelection,(Display* a,Atom b,Atom c,Atom d,Window e,Time f),(a,b,c,d,e,f),return)
SDL_X11_SYM(Pixmap,XCreateBitmapFromData,(Display *dpy,Drawable d,_Xconst char *data,unsigned int width,unsigned int height),(dpy,d,data,width,height),return)
@@ -69,6 +70,7 @@
SDL_X11_SYM(Status,XIconifyWindow,(Display* a,Window b,int c),(a,b,c),return)
SDL_X11_SYM(KeyCode,XKeysymToKeycode,(Display* a,KeySym b),(a,b),return)
SDL_X11_SYM(char*,XKeysymToString,(KeySym a),(a),return)
+SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return)
SDL_X11_SYM(Atom,XInternAtom,(Display* a,_Xconst char* b,Bool c),(a,b,c),return)
SDL_X11_SYM(XPixmapFormatValues*,XListPixmapFormats,(Display* a,int* b),(a,b),return)
SDL_X11_SYM(KeySym,XLookupKeysym,(XKeyEvent* a,int b),(a,b),return)
@@ -85,6 +87,7 @@
SDL_X11_SYM(int,XQueryKeymap,(Display* a,char *b),(a,b),return)
SDL_X11_SYM(Bool,XQueryPointer,(Display* a,Window b,Window* c,Window* d,int* e,int* f,int* g,int* h,unsigned int* i),(a,b,c,d,e,f,g,h,i),return)
SDL_X11_SYM(int,XRaiseWindow,(Display* a,Window b),(a,b),return)
+SDL_X11_SYM(int,XReparentWindow,(Display* a,Window b,Window c,int d,int e),(a,b,c,d,e),return)
SDL_X11_SYM(int,XResetScreenSaver,(Display* a),(a),return)
SDL_X11_SYM(int,XResizeWindow,(Display* a,Window b,unsigned int c,unsigned int d),(a,b,c,d),return)
SDL_X11_SYM(int,XSelectInput,(Display* a,Window b,long c),(a,b,c),return)
@@ -95,6 +98,7 @@
SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return)
SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),)
+SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return)
SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),)
SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
@@ -256,6 +260,7 @@
SDL_X11_SYM(Bool,XF86VidModeQueryExtension,(Display *a,int *b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XF86VidModeQueryVersion,(Display *a,int *b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XF86VidModeSwitchToMode,(Display *a,int b,XF86VidModeModeInfo *c),(a,b,c),return)
+SDL_X11_SYM(Bool,XF86VidModeLockModeSwitch,(Display *a,int b,int c),(a,b,c),return)
#endif
/* *INDENT-ON* */
--- a/src/video/x11/SDL_x11window.c Thu Sep 27 00:53:37 2012 -0400
+++ b/src/video/x11/SDL_x11window.c Thu Sep 27 03:36:13 2012 -0400
@@ -38,22 +38,38 @@
#include "SDL_timer.h"
#include "SDL_syswm.h"
+#include "SDL_assert.h"
#define _NET_WM_STATE_REMOVE 0l
#define _NET_WM_STATE_ADD 1l
#define _NET_WM_STATE_TOGGLE 2l
-static SDL_bool
-X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
+static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
+{
+ return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
+}
+static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
+{
+ return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
+}
+static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
{
- SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
+ return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
+}
+static Bool isFocusOut(Display *dpy, XEvent *ev, XPointer win)
+{
+ return ev->type == FocusOut && ev->xunmap.window == *((Window*)win);
+}
+static Bool isFocusIn(Display *dpy, XEvent *ev, XPointer win)
+{
+ return ev->type == FocusIn && ev->xunmap.window == *((Window*)win);
+}
- /* ICCCM2.0-compliant window managers can handle fullscreen windows */
- if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
- return SDL_TRUE;
- } else {
- return SDL_FALSE;
- }
+static SDL_bool
+X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ return (data->fswindow != 0);
}
static SDL_bool
@@ -724,19 +740,6 @@
XFlush(display);
}
-static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
-{
- return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
-}
-static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
-{
- return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
-}
-static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
-{
- return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
-}
-
void
X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
{
@@ -907,8 +910,9 @@
return ret;
}
-void
-X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
+/* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
+static void
+X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
@@ -977,6 +981,189 @@
XFlush(display);
}
+static __inline__ int
+maxint(const int a, const int b)
+{
+ return (a > b ? a : b);
+}
+
+
+/* This handles fullscreen itself, outside the Window Manager. */
+static void
+X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
+ Visual *visual = data->visual;
+ Display *display = data->videodata->display;
+ const int screen = displaydata->screen;
+ Window root = RootWindow(display, screen);
+ const int def_vis = (visual == DefaultVisual(display, screen));
+ const int w = maxint(window->w, _display->current_mode.w);
+ const int h = maxint(window->h, _display->current_mode.h);
+ unsigned long xattrmask = 0;
+ XSetWindowAttributes xattr;
+ XEvent ev;
+ int x = 0;
+ int y = 0;
+
+ if ( data->fswindow ) {
+ return; /* already fullscreen, I hope. */
+ }
+
+ /* Ungrab the input so that we can move the mouse around */
+ XUngrabPointer(display, CurrentTime);
+
+ #if SDL_VIDEO_DRIVER_X11_XINERAMA
+ /* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
+ #endif
+
+ SDL_zero(xattr);
+ xattr.override_redirect = True;
+ xattrmask |= CWOverrideRedirect;
+ xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
+ xattrmask |= CWBackPixel;
+ xattr.border_pixel = 0;
+ xattrmask |= CWBorderPixel;
+ xattr.colormap = data->colormap;
+ xattrmask |= CWColormap;
+
+ data->fswindow = XCreateWindow(display, root, x, y, w, h, 0,
+ displaydata->depth, InputOutput,
+ visual, xattrmask, &xattr);
+
+ XSelectInput(display, data->fswindow, StructureNotifyMask);
+
+ XSetWindowBackground(display, data->fswindow, 0);
+ XClearWindow(display, data->fswindow);
+
+ XMapRaised(display, data->fswindow);
+
+ /* Wait to be mapped, filter Unmap event out if it arrives. */
+ XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
+ XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
+
+#if SDL_VIDEO_DRIVER_X11_XVIDMODE
+ if ( displaydata->use_vidmode ) {
+ XF86VidModeLockModeSwitch(display, screen, True);
+ }
+#endif
+
+ XInstallColormap(display, data->colormap);
+
+ SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
+ XFlush(display);
+ //XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);
+
+ /* Center actual window within our cover-the-screen window. */
+ x += (w - window->w) / 2;
+ y += (h - window->h) / 2;
+ XReparentWindow(display, data->xwindow, data->fswindow, x, y);
+ XRaiseWindow(display, data->xwindow);
+
+ /* Make sure the fswindow is in view by warping mouse to the corner */
+ XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
+ XFlush(display);
+
+ /* Center mouse in the window. */
+ x += (window->w / 2);
+ y += (window->h / 2);
+ XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
+
+ /* Wait to be mapped, filter Unmap event out if it arrives. */
+ XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
+
+ /* Wait to be visible, or XSetInputFocus() triggers an X error. */
+ while (SDL_TRUE) {
+ XWindowAttributes attr;
+ XSync(display, False);
+ XGetWindowAttributes(display, data->xwindow, &attr);
+ if (attr.map_state == IsViewable)
+ break;
+ }
+
+ XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
+ window->flags |= SDL_WINDOW_INPUT_FOCUS;
+ SDL_SetKeyboardFocus(data->window);
+
+ X11_SetWindowGrab(_this, window);
+
+ XSync(display, False);
+}
+
+static void
+X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
+ Display *display = data->videodata->display;
+ const int screen = displaydata->screen;
+ Window root = RootWindow(display, screen);
+ XEvent ev;
+
+ if (!data->fswindow)
+ return; /* already not fullscreen, I hope. */
+
+ XReparentWindow(display, data->xwindow, root, window->x, window->y);
+
+#if SDL_VIDEO_DRIVER_X11_VIDMODE
+ if ( displaydata->use_vidmode ) {
+ XF86VidModeLockModeSwitch(display, screen, False);
+ }
+#endif
+
+ XUnmapWindow(display, data->fswindow);
+ /* Wait to be unmapped. */
+ XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
+ XDestroyWindow(display, data->fswindow);
+ data->fswindow = 0;
+
+ /* catch these events so we know the window is back in business. */
+ XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
+ XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);
+
+ XSync(display, True); /* Flush spurious mode change events */
+
+ X11_SetWindowGrab(_this, window);
+
+ SetWindowBordered(display, screen, data->xwindow,
+ (window->flags & SDL_WINDOW_BORDERLESS) == 0);
+
+ XFlush(display);
+}
+
+
+void
+X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
+{
+ /* !!! FIXME: SDL_Hint? */
+ SDL_bool legacy = SDL_FALSE;
+ const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
+ if (env) {
+ legacy = SDL_atoi(env);
+ } else {
+ SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
+ if ( displaydata->use_vidmode ) {
+ legacy = SDL_TRUE; /* the new stuff only works with XRandR. */
+ } else {
+ /* !!! FIXME: look at the window manager name, and blacklist certain ones? */
+ /* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
+ legacy = SDL_FALSE; /* try the new way. */
+ }
+ }
+
+ if (legacy) {
+ if (fullscreen) {
+ X11_BeginWindowFullscreenLegacy(_this, window, _display);
+ } else {
+ X11_EndWindowFullscreenLegacy(_this, window, _display);
+ }
+ } else {
+ X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
+ }
+}
+
+
int
X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
{
@@ -1054,7 +1241,7 @@
SDL_bool oldstyle_fullscreen;
/* ICCCM2.0-compliant window managers can handle fullscreen windows */
- oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
+ oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);
if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
&& (window->flags & SDL_WINDOW_INPUT_FOCUS)) {