Lots of prep for the "real" way to support fullscreen mode on modern window managers.
authorSam Lantinga <slouken@libsdl.org>
Tue, 13 Jul 2010 23:11:10 -0700
changeset 4518 a956a315fe67
parent 4517 7b5e4396bcaa
child 4519 62d693e01a24
Lots of prep for the "real" way to support fullscreen mode on modern window managers. Unfortunately, this doesn't work. I also noticed that maximizing doesn't work as well. Also xprop hangs when trying to list properties of SDL windows.... ???
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11modes.c
src/video/x11/SDL_x11sym.h
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11video.h
src/video/x11/SDL_x11window.c
src/video/x11/SDL_x11window.h
--- a/src/video/x11/SDL_x11events.c	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11events.c	Tue Jul 13 23:11:10 2010 -0700
@@ -34,18 +34,19 @@
 #include "SDL_timer.h"
 #include "SDL_syswm.h"
 
-/*#define DEBUG_XEVENTS*/
+#define DEBUG_XEVENTS
 
 static void
 X11_DispatchEvent(_THIS)
 {
     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
+    Display *display = videodata->display;
     SDL_WindowData *data;
     XEvent xevent;
     int i;
 
     SDL_zero(xevent);           /* valgrind fix. --ryan. */
-    XNextEvent(videodata->display, &xevent);
+    XNextEvent(display, &xevent);
 
     /* filter events catchs XIM events and sends them to the correct
        handler */
@@ -80,6 +81,7 @@
     if (!data) {
         return;
     }
+
 #if 0
     printf("type = %d display = %d window = %d\n",
            xevent.type, xevent.xany.display, xevent.xany.window);
@@ -182,9 +184,8 @@
 #if 0
             if (videodata->key_layout[keycode] == SDLK_UNKNOWN) {
                 int min_keycode, max_keycode;
-                XDisplayKeycodes(videodata->display, &min_keycode,
-                                 &max_keycode);
-                keysym = XKeycodeToKeysym(videodata->display, keycode, 0);
+                XDisplayKeycodes(display, &min_keycode, &max_keycode);
+                keysym = XKeycodeToKeysym(display, keycode, 0);
                 fprintf(stderr,
                         "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> X11 KeyCode %d (%d), X11 KeySym 0x%X (%s).\n",
                         keycode, keycode - min_keycode, keysym,
@@ -289,9 +290,58 @@
         }
         break;
 
+    case PropertyNotify:{
+#ifdef DEBUG_XEVENTS
+            char *name = XGetAtomName(display, xevent.xproperty.atom);
+            printf("PropertyNotify (atom = %s)\n", name ? name : "NULL");
+            if (name) {
+                XFree(name);
+            }
+#endif
+            if (xevent.xproperty.atom == videodata->_NET_WM_STATE) {
+                unsigned char *propdata;
+                int status, real_format;
+                Atom real_type;
+                unsigned long items_read, items_left, i;
+
+#ifdef DEBUG_XEVENTS
+                printf("_NET_WM_STATE: {");
+#endif
+                status = XGetWindowProperty(display, data->xwindow, videodata->_NET_WM_STATE, 0L, 8192L, False, XA_ATOM, &real_type, &real_format, &items_read, &items_left, &propdata);
+                if (status == Success) {
+                    Atom *atoms = (Atom *)propdata;
+                    for (i = 0; i < items_read; i++) {
+                        if (atoms[i] == videodata->_NET_WM_STATE_HIDDEN) {
+#ifdef DEBUG_XEVENTS
+                            printf(" _NET_WM_STATE_HIDDEN");
+#endif
+                        }
+                        if (atoms[i] == videodata->_NET_WM_STATE_MAXIMIZED_HORZ) {
+#ifdef DEBUG_XEVENTS
+                            printf(" _NET_WM_STATE_MAXIMIZED_HORZ");
+#endif
+                        }
+                        if (atoms[i] == videodata->_NET_WM_STATE_MAXIMIZED_VERT) {
+#ifdef DEBUG_XEVENTS
+                            printf(" _NET_WM_STATE_MAXIMIZED_VERT");
+#endif
+                        }
+                        if (atoms[i] == videodata->_NET_WM_STATE_FULLSCREEN) {
+#ifdef DEBUG_XEVENTS
+                            printf(" _NET_WM_STATE_FULLSCREEN");
+#endif
+                        }
+                    }
+                }
+#ifdef DEBUG_XEVENTS
+                printf(" }\n");
+#endif
+            }
+        }
+        break;
+
     /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
     case SelectionRequest: {
-            Display *display = videodata->display;
             XSelectionRequestEvent *req;
             XEvent sevent;
             int seln_format;
--- a/src/video/x11/SDL_x11modes.c	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11modes.c	Tue Jul 13 23:11:10 2010 -0700
@@ -23,7 +23,7 @@
 
 #include "SDL_x11video.h"
 
-//#define X11MODES_DEBUG
+#define X11MODES_DEBUG
 #undef SDL_VIDEO_DRIVER_X11_XINERAMA
 #undef SDL_VIDEO_DRIVER_X11_XRANDR
 #undef SDL_VIDEO_DRIVER_X11_VIDMODE
@@ -253,6 +253,7 @@
     return SDL_TRUE;
 }
 
+static
 Bool SDL_NAME(XF86VidModeGetModeInfo) (Display * dpy, int scr,
                                        SDL_NAME(XF86VidModeModeInfo) * info)
 {
@@ -296,6 +297,7 @@
                                       &data->saved_view.y);
 }
 
+/*
 static void
 restore_mode(Display * display, SDL_DisplayData * data)
 {
@@ -313,6 +315,7 @@
                                           data->saved_view.y);
     }
 }
+*/
 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
 
 void
--- a/src/video/x11/SDL_x11sym.h	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11sym.h	Tue Jul 13 23:11:10 2010 -0700
@@ -67,12 +67,14 @@
 SDL_X11_SYM(int,XFreeGC,(Display* a,GC b),(a,b),return)
 SDL_X11_SYM(int,XFreeModifiermap,(XModifierKeymap* a),(a),return)
 SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b),(a,b),return)
+SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b),(a,b),return)
 SDL_X11_SYM(int,XGetErrorDatabaseText,(Display* a,_Xconst char* b,_Xconst char* c,_Xconst char* d,char* e,int f),(a,b,c,d,e,f),return)
 SDL_X11_SYM(XImage*,XGetImage,(Display* a,Drawable b,int c,int d,unsigned int e,unsigned int f,unsigned long g, int h),(a,b,c,d,e,f,g,h),return)
 SDL_X11_SYM(XModifierKeymap*,XGetModifierMapping,(Display* a),(a),return)
 SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d),(a,b,c,d),return)
 SDL_X11_SYM(int,XGetRGBColormaps,(Display* a,Window b,XStandardColormap **c,int *d,Atom e),(a,b,c,d,e),return)
 SDL_X11_SYM(Window,XGetSelectionOwner,(Display* a,Atom b),(a,b),return)
+SDL_X11_SYM(Status,XGetTextProperty,(Display *a,Window b,XTextProperty *c,Atom d),(a,b,c,d),return)
 SDL_X11_SYM(XVisualInfo*,XGetVisualInfo,(Display* a,long b,XVisualInfo* c,int* d),(a,b,c,d),return)
 SDL_X11_SYM(Status,XGetWindowAttributes,(Display* a,Window b,XWindowAttributes* c),(a,b,c),return)
 SDL_X11_SYM(int,XGetWindowProperty,(Display* a,Window b,Atom c,long d,long e,Bool f,Atom g,Atom* h,int* i,unsigned long* j,unsigned long *k,unsigned char **l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
--- a/src/video/x11/SDL_x11video.c	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11video.c	Tue Jul 13 23:11:10 2010 -0700
@@ -242,6 +242,43 @@
 };
 
 
+static void
+X11_CheckWindowManager(_THIS)
+{
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    Display *display = data->display;
+    Atom _NET_SUPPORTING_WM_CHECK;
+    int status, real_format;
+    Atom real_type;
+    unsigned long items_read, items_left;
+    unsigned char *propdata;
+    Window wm_window = 0;
+#ifdef DEBUG_WINDOW_MANAGER
+    char *wm_name;
+#endif
+
+    _NET_SUPPORTING_WM_CHECK = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
+    status = XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
+    if (status == Success && items_read) {
+        wm_window = ((Window*)propdata)[0];
+    }
+    XFree(propdata);
+
+    if (!wm_window) {
+#ifdef DEBUG_WINDOW_MANAGER
+        printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
+#endif
+        return;
+    }
+    data->net_wm = SDL_TRUE;
+
+#ifdef DEBUG_WINDOW_MANAGER
+    wm_name = X11_GetWindowTitle(_this, wm_window);
+    printf("Window manager: %s\n", wm_name);
+    SDL_free(wm_name);
+#endif
+}
+
 int
 X11_VideoInit(_THIS)
 {
@@ -259,8 +296,20 @@
 #endif
 
     /* Look up some useful Atoms */
-    data->WM_DELETE_WINDOW =
-        XInternAtom(data->display, "WM_DELETE_WINDOW", False);
+#define GET_ATOM(X) data->X = XInternAtom(data->display, #X, False)
+    GET_ATOM(WM_DELETE_WINDOW);
+    GET_ATOM(_NET_WM_STATE);
+    GET_ATOM(_NET_WM_STATE_HIDDEN);
+    GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
+    GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
+    GET_ATOM(_NET_WM_STATE_FULLSCREEN);
+    GET_ATOM(_NET_WM_NAME);
+    GET_ATOM(_NET_WM_ICON_NAME);
+    GET_ATOM(_NET_WM_ICON);
+    GET_ATOM(UTF8_STRING);
+
+    /* Detect the window manager */
+    X11_CheckWindowManager(_this);
 
     if (X11_InitModes(_this) < 0) {
         return -1;
--- a/src/video/x11/SDL_x11video.h	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11video.h	Tue Jul 13 23:11:10 2010 -0700
@@ -68,7 +68,22 @@
     int numwindows;
     SDL_WindowData **windowlist;
     int windowlistlength;
+
+    /* This is true for ICCCM2.0-compliant window managers */
+    SDL_bool net_wm;
+
+    /* Useful atoms */
     Atom WM_DELETE_WINDOW;
+    Atom _NET_WM_STATE;
+    Atom _NET_WM_STATE_HIDDEN;
+    Atom _NET_WM_STATE_MAXIMIZED_VERT;
+    Atom _NET_WM_STATE_MAXIMIZED_HORZ;
+    Atom _NET_WM_STATE_FULLSCREEN;
+    Atom _NET_WM_NAME;
+    Atom _NET_WM_ICON_NAME;
+    Atom _NET_WM_ICON;
+    Atom UTF8_STRING;
+
     SDL_scancode key_layout[256];
     SDL_bool selection_waiting;
 } SDL_VideoData;
--- a/src/video/x11/SDL_x11window.c	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11window.c	Tue Jul 13 23:11:10 2010 -0700
@@ -42,6 +42,20 @@
 #define _NET_WM_STATE_ADD       1l
 #define _NET_WM_STATE_TOGGLE    2l
 
+static SDL_bool
+X11_WindowIsOldstyleFullscreen(SDL_Window * window)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
+
+    /* 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 void
 X11_GetDisplaySize(_THIS, SDL_Window * window, int *w, int *h)
 {
@@ -128,14 +142,10 @@
     }
 
     {
-        Atom _NET_WM_STATE =
-            XInternAtom(data->videodata->display, "_NET_WM_STATE", False);
-        Atom _NET_WM_STATE_MAXIMIZED_VERT =
-            XInternAtom(data->videodata->display,
-                        "_NET_WM_STATE_MAXIMIZED_VERT", False);
-        Atom _NET_WM_STATE_MAXIMIZED_HORZ =
-            XInternAtom(data->videodata->display,
-                        "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+        Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
+        Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
+        Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
+        Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
         Atom actualType;
         int actualFormat;
         unsigned long i, numItems, bytesAfter;
@@ -148,19 +158,21 @@
                                &propertyValue) == Success) {
             Atom *atoms = (Atom *) propertyValue;
             int maximized = 0;
+            int fullscreen = 0;
 
             for (i = 0; i < numItems; ++i) {
                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
                     maximized |= 1;
                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
                     maximized |= 2;
+                } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
+                    fullscreen = 1;
                 }
-                /* Might also want to check the following properties:
-                   _NET_WM_STATE_ABOVE, _NET_WM_STATE_FULLSCREEN
-                 */
             }
             if (maximized == 3) {
                 window->flags |= SDL_WINDOW_MAXIMIZED;
+            }  else if (fullscreen == 1) {
+                window->flags |= SDL_WINDOW_FULLSCREEN;
             }
             XFree(propertyValue);
         }
@@ -180,11 +192,6 @@
        } else {
        window->flags &= ~SDL_WINDOW_RESIZABLE;
        }
-       if (style & WS_MAXIMIZE) {
-       window->flags |= SDL_WINDOW_MAXIMIZED;
-       } else {
-       window->flags &= ~SDL_WINDOW_MAXIMIZED;
-       }
        if (style & WS_MINIMIZE) {
        window->flags |= SDL_WINDOW_MINIMIZED;
        } else {
@@ -225,6 +232,14 @@
     XSizeHints *sizehints;
     XWMHints *wmhints;
     XClassHint *classhints;
+    SDL_bool oldstyle_fullscreen;
+
+    /* ICCCM2.0-compliant window managers can handle fullscreen windows */
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) && !data->net_wm) {
+        oldstyle_fullscreen = SDL_TRUE;
+    } else {
+        oldstyle_fullscreen = SDL_FALSE;
+    }
 
 #if SDL_VIDEO_DRIVER_X11_XINERAMA
 /* FIXME
@@ -265,7 +280,7 @@
         depth = displaydata->depth;
     }
 
-    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+    if (oldstyle_fullscreen) {
         xattr.override_redirect = True;
     } else {
         xattr.override_redirect = False;
@@ -417,7 +432,6 @@
             }
 
             /* OK, we got a colormap, now fill it in as best as we can */
-
             colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
             if (NULL == colorcells) {
                 SDL_SetError("out of memory in X11_CreateWindow");
@@ -494,7 +508,7 @@
                             visual, AllocNone);
     }
 
-    if ((window->flags & SDL_WINDOW_FULLSCREEN)
+    if (oldstyle_fullscreen
         || window->x == SDL_WINDOWPOS_CENTERED) {
         X11_GetDisplaySize(_this, window, &x, NULL);
         x = (x - window->w) / 2;
@@ -503,7 +517,7 @@
     } else {
         x = window->x;
     }
-    if ((window->flags & SDL_WINDOW_FULLSCREEN)
+    if (oldstyle_fullscreen
         || window->y == SDL_WINDOWPOS_CENTERED) {
         X11_GetDisplaySize(_this, window, NULL, &y);
         y = (y - window->h) / 2;
@@ -539,12 +553,12 @@
     sizehints = XAllocSizeHints();
     if (sizehints) {
         if (!(window->flags & SDL_WINDOW_RESIZABLE)
-            || (window->flags & SDL_WINDOW_FULLSCREEN)) {
+            || oldstyle_fullscreen) {
             sizehints->min_width = sizehints->max_width = window->w;
             sizehints->min_height = sizehints->max_height = window->h;
             sizehints->flags = PMaxSize | PMinSize;
         }
-        if (!(window->flags & SDL_WINDOW_FULLSCREEN)
+        if (!oldstyle_fullscreen
             && window->x != SDL_WINDOWPOS_UNDEFINED
             && window->y != SDL_WINDOWPOS_UNDEFINED) {
             sizehints->x = x;
@@ -555,7 +569,7 @@
         XFree(sizehints);
     }
 
-    if (window->flags & (SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN)) {
+    if ((window->flags & SDL_WINDOW_BORDERLESS) || oldstyle_fullscreen) {
         SDL_bool set;
         Atom WM_HINTS;
 
@@ -643,23 +657,6 @@
         }
     }
 
-    /* Tell KDE to keep fullscreen windows on top */
-    if (window->flags & SDL_WINDOW_FULLSCREEN) {
-        XEvent ev;
-
-        SDL_zero(ev);
-        ev.xclient.type = ClientMessage;
-        ev.xclient.window = RootWindow(data->display, displaydata->screen);
-        ev.xclient.message_type =
-            XInternAtom(data->display, "KWM_KEEP_ON_TOP", False);
-        ev.xclient.format = 32;
-        ev.xclient.data.l[0] = w;
-        ev.xclient.data.l[1] = CurrentTime;
-        XSendEvent(data->display,
-                   RootWindow(data->display, displaydata->screen), False,
-                   SubstructureRedirectMask, &ev);
-    }
-
     /* Set the input hints so we get keyboard input */
     wmhints = XAllocWMHints();
     if (wmhints) {
@@ -678,6 +675,26 @@
         XFree(classhints);
     }
 
+    /* FIXME: Why doesn't this work? */
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        Atom _NET_WM_STATE = data->_NET_WM_STATE;
+        Atom _NET_WM_STATE_FULLSCREEN = data->_NET_WM_STATE_FULLSCREEN;
+        XEvent e;
+
+        e.xany.type = ClientMessage;
+        e.xclient.display = data->display;
+        e.xclient.window = w;
+        e.xclient.message_type = _NET_WM_STATE;
+        e.xclient.format = 32;
+        e.xclient.data.l[0] = _NET_WM_STATE_ADD;
+        e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
+        e.xclient.data.l[2] = 0l;
+
+        XSendEvent(data->display,
+                   RootWindow(data->display, displaydata->screen), 0,
+                   SubstructureNotifyMask | SubstructureRedirectMask, &e);
+    }
+
     /* Allow the window to be deleted by the window manager */
     XSetWMProtocols(data->display, w, &data->WM_DELETE_WINDOW, 1);
 
@@ -716,7 +733,7 @@
 {
     Window w = (Window) data;
 
-    /* FIXME: Query the title from the existing window */
+    window->title = X11_GetWindowTitle(_this, w);
 
     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
         return -1;
@@ -724,6 +741,36 @@
     return 0;
 }
 
+char *
+X11_GetWindowTitle(_THIS, Window xwindow)
+{
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    Display *display = data->display;
+    int status, real_format;
+    Atom real_type;
+    unsigned long items_read, items_left;
+    unsigned char *propdata;
+    char *title = NULL;
+
+    status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
+                0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
+                &items_read, &items_left, &propdata);
+    if (status == Success) {
+        title = SDL_strdup(SDL_static_cast(char*, propdata));
+        XFree(propdata);
+    } else {
+        status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
+                    0L, 8192L, False, XA_STRING, &real_type, &real_format,
+                    &items_read, &items_left, &propdata);
+        if (status == Success) {
+            title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
+        } else {
+            title = SDL_strdup("");
+        }
+    }
+    return title;
+}
+
 void
 X11_SetWindowTitle(_THIS, SDL_Window * window)
 {
@@ -735,14 +782,8 @@
     const char *icon = NULL;
 
 #ifdef X_HAVE_UTF8_STRING
-    Atom _NET_WM_NAME = 0;
-    Atom _NET_WM_ICON_NAME = 0;
-
-    /* Look up some useful Atoms */
-    if (SDL_X11_HAVE_UTF8) {
-        _NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", False);
-        _NET_WM_ICON_NAME = XInternAtom(display, "_NET_WM_ICON_NAME", False);
-    }
+    Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
+    Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
 #endif
 
     if (title != NULL) {
@@ -803,7 +844,7 @@
 {
     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
     Display *display = data->videodata->display;
-    Atom _NET_WM_ICON = XInternAtom(display, "_NET_WM_ICON", False);
+    Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
 
     if (icon) {
         SDL_PixelFormat format;
@@ -842,16 +883,20 @@
 {
     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
     Display *display = data->videodata->display;
+    SDL_bool oldstyle_fullscreen;
     int x, y;
 
-    if ((window->flags & SDL_WINDOW_FULLSCREEN)
+    /* ICCCM2.0-compliant window managers can handle fullscreen windows */
+    oldstyle_fullscreen = X11_WindowIsOldstyleFullscreen(window);
+
+    if (oldstyle_fullscreen
         || window->x == SDL_WINDOWPOS_CENTERED) {
         X11_GetDisplaySize(_this, window, &x, NULL);
         x = (x - window->w) / 2;
     } else {
         x = window->x;
     }
-    if ((window->flags & SDL_WINDOW_FULLSCREEN)
+    if (oldstyle_fullscreen
         || window->y == SDL_WINDOWPOS_CENTERED) {
         X11_GetDisplaySize(_this, window, NULL, &y);
         y = (y - window->h) / 2;
@@ -904,15 +949,14 @@
     SDL_DisplayData *displaydata =
         (SDL_DisplayData *) window->display->driverdata;
     Display *display = data->videodata->display;
-    Atom _NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", False);
-    Atom _NET_WM_STATE_MAXIMIZED_VERT =
-        XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
-    Atom _NET_WM_STATE_MAXIMIZED_HORZ =
-        XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+    Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
+    Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
+    Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
     XEvent e;
 
     e.xany.type = ClientMessage;
-    e.xany.window = data->xwindow;
+    e.xclient.display = display;
+    e.xclient.window = data->xwindow;
     e.xclient.message_type = _NET_WM_STATE;
     e.xclient.format = 32;
     e.xclient.data.l[0] =
@@ -920,7 +964,6 @@
     e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
     e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
     e.xclient.data.l[3] = 0l;
-    e.xclient.data.l[4] = 0l;
 
     XSendEvent(display, RootWindow(display, displaydata->screen), 0,
                SubstructureNotifyMask | SubstructureRedirectMask, &e);
@@ -935,7 +978,12 @@
 void
 X11_MinimizeWindow(_THIS, SDL_Window * window)
 {
-    X11_HideWindow(_this, window);
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    SDL_DisplayData *displaydata =
+        (SDL_DisplayData *) window->display->driverdata;
+    Display *display = data->videodata->display;
+ 
+    XIconifyWindow(display, data->xwindow, displaydata->screen);
 }
 
 void
@@ -950,8 +998,12 @@
 {
     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
     Display *display = data->videodata->display;
+    SDL_bool oldstyle_fullscreen;
 
-    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
+    /* ICCCM2.0-compliant window managers can handle fullscreen windows */
+    oldstyle_fullscreen = X11_WindowIsOldstyleFullscreen(window);
+
+    if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
         /* Try to grab the mouse */
         for (;;) {
--- a/src/video/x11/SDL_x11window.h	Tue Jul 13 23:05:14 2010 -0700
+++ b/src/video/x11/SDL_x11window.h	Tue Jul 13 23:11:10 2010 -0700
@@ -35,6 +35,7 @@
 
 extern int X11_CreateWindow(_THIS, SDL_Window * window);
 extern int X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data);
+extern char *X11_GetWindowTitle(_THIS, Window xwindow);
 extern void X11_SetWindowTitle(_THIS, SDL_Window * window);
 extern void X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
 extern void X11_SetWindowPosition(_THIS, SDL_Window * window);