+
+
+#define _NET_WM_STATE_REMOVE        0
+#define _NET_WM_STATE_ADD           1
+
+static void wxWMspecSetState(Display *display, Window rootWnd,
+                             Window window, int operation, Atom state)
+{
+    wxMAKE_ATOM(_NET_WM_STATE, display);
+  
+    if ( IsMapped(display, window) )
+    {
+        XEvent xev;
+        xev.type = ClientMessage;
+        xev.xclient.type = ClientMessage;
+        xev.xclient.serial = 0;
+        xev.xclient.send_event = True;
+        xev.xclient.display = display;
+        xev.xclient.window = window;
+        xev.xclient.message_type = _NET_WM_STATE;
+        xev.xclient.format = 32;
+        xev.xclient.data.l[0] = operation;
+        xev.xclient.data.l[1] = state;
+        xev.xclient.data.l[2] = None;
+  
+        XSendEvent(display, rootWnd,
+                   False,
+                   SubstructureRedirectMask | SubstructureNotifyMask,
+                   &xev);
+    }
+    // FIXME - must modify _NET_WM_STATE property list if the window
+    //         wasn't mapped!
+}
+
+static void wxWMspecSetFullscreen(Display *display, Window rootWnd,
+                                  Window window, bool fullscreen)
+{
+    wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, display);
+    wxWMspecSetState(display, rootWnd,
+                     window,
+                     fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
+                      _NET_WM_STATE_FULLSCREEN);
+}
+
+
+// Is the user running KDE's kwin window manager? At least kwin from KDE 3
+// sets KWIN_RUNNING property on the root window.
+static bool wxKwinRunning(Display *display, Window rootWnd)
+{
+    wxMAKE_ATOM(KWIN_RUNNING, display);
+    
+    long *data;
+    Atom type;
+    int format;
+    unsigned long nitems, after;
+    if (XGetWindowProperty(display, rootWnd,
+                           KWIN_RUNNING, 0, 1, False, KWIN_RUNNING,
+                           &type, &format, &nitems, &after,
+                           (unsigned char**)&data) != Success)
+    {
+        return FALSE;
+    }
+
+    bool retval = (type == KWIN_RUNNING &&
+                   nitems == 1 && data && data[0] == 1);
+    XFree(data);
+    return retval;
+}
+
+// KDE's kwin is Qt-centric so much than no normal method of fullscreen 
+// mode will work with it. We have to carefully emulate the Qt way.
+static void wxSetKDEFullscreen(Display *display, Window rootWnd,
+                               Window w, bool fullscreen, wxRect *origRect)
+{
+    long data[2];
+    unsigned lng;
+
+    wxMAKE_ATOM(_NET_WM_WINDOW_TYPE, display);
+    wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL, display);
+    wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE, display);
+    wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP, display);
+
+    if (fullscreen)
+    {
+        data[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE;
+        data[1] = _NET_WM_WINDOW_TYPE_NORMAL;
+        lng = 2;
+    }
+    else
+    {
+        data[0] = _NET_WM_WINDOW_TYPE_NORMAL;
+        data[1] = None;
+        lng = 1;
+    }
+
+    // it is neccessary to unmap the window, otherwise kwin will ignore us:
+    XSync(display, False);
+    
+    bool wasMapped = IsMapped(display, w);
+    if (wasMapped)
+    {
+        XUnmapWindow(display, w);
+        XSync(display, False);
+    }
+
+    XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
+                       PropModeReplace, (unsigned char *) &data, lng);
+    XSync(display, False);
+
+    if (wasMapped)
+    {
+        XMapRaised(display, w);
+        XSync(display, False);
+    }
+    
+    wxWMspecSetState(display, rootWnd, w, 
+                     fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
+                     _NET_WM_STATE_STAYS_ON_TOP);
+    XSync(display, False);
+
+    if (!fullscreen)
+    {
+        // NB: like many other WMs, kwin ignores first request for window
+        //     position change after the window was mapped. This additional
+        //     move+resize event will ensure that the window is restored in
+        //     exactly same position as before it was made fullscreen (because
+        //     wxTopLevelWindow::ShowFullScreen will call SetSize, thus
+        //     setting the position for second time).
+        XMoveResizeWindow(display, w,
+                          origRect->x, origRect->y,
+                          origRect->width, origRect->height);
+        XSync(display, False);
+    }
+}
+
+
+wxX11FullScreenMethod wxGetFullScreenMethodX11(WXDisplay* display,
+                                               WXWindow rootWindow)
+{
+    Window root = (Window)rootWindow;
+    Display *disp = (Display*)display;
+
+    // if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it:
+    wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, disp);
+    if (wxQueryWMspecSupport(disp, root, _NET_WM_STATE_FULLSCREEN))
+    {
+        wxLogTrace(_T("fullscreen"),
+                   _T("detected _NET_WM_STATE_FULLSCREEN support"));
+        return wxX11_FS_WMSPEC;
+    }
+    
+    // if the user is running KDE's kwin WM, use a legacy hack because
+    // kwin doesn't understand any other method:
+    if (wxKwinRunning(disp, root))
+    {
+        wxLogTrace(_T("fullscreen"), _T("detected kwin"));
+        return wxX11_FS_KDE;
+    }
+    
+    // finally, fall back to ICCCM heuristic method:
+    wxLogTrace(_T("fullscreen"), _T("unknown WM, using _WIN_LAYER"));
+    return wxX11_FS_GENERIC;
+}
+
+
+void wxSetFullScreenStateX11(WXDisplay* display, WXWindow rootWindow,
+                             WXWindow window, bool show,
+                             wxRect *origRect,
+                             wxX11FullScreenMethod method)
+{
+    // NB: please see the comment under "Fullscreen mode:" title above
+    //     for implications of changing this code.
+
+    Window wnd = (Window)window;
+    Window root = (Window)rootWindow;
+    Display *disp = (Display*)display;
+
+    if (method == wxX11_FS_AUTODETECT)
+        method = wxGetFullScreenMethodX11(display, rootWindow);
+
+    switch (method)
+    {
+        case wxX11_FS_WMSPEC:
+            wxWMspecSetFullscreen(disp, root, wnd, show);
+            break;
+        case wxX11_FS_KDE:
+            wxSetKDEFullscreen(disp, root, wnd, show, origRect);
+            break;
+        default:
+            wxWinHintsSetLayer(disp, root, wnd,
+                               show ? WIN_LAYER_ABOVE_DOCK : WIN_LAYER_NORMAL);
+            break;
+    }
+}
+
+#endif
+