src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 22 Jun 2012 23:31:22 -0400
changeset 6343 e94f912d20b9
parent 6336 6e6163b6ba69
child 6369 a92fbd27127b
permissions -rwxr-xr-x
Fix SDL_SetWindowSize with X11 non-RESIZABLE windows, patch by Pierre-Loup.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "../SDL_sysvideo.h"
    26 #include "../SDL_pixels_c.h"
    27 #include "../../events/SDL_keyboard_c.h"
    28 #include "../../events/SDL_mouse_c.h"
    29 
    30 #include "SDL_x11video.h"
    31 #include "SDL_x11mouse.h"
    32 #include "SDL_x11shape.h"
    33 #include "SDL_x11xinput2.h"
    34 
    35 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
    36 #include "SDL_x11opengles.h"
    37 #endif
    38 
    39 #include "SDL_timer.h"
    40 #include "SDL_syswm.h"
    41 
    42 #define _NET_WM_STATE_REMOVE    0l
    43 #define _NET_WM_STATE_ADD       1l
    44 #define _NET_WM_STATE_TOGGLE    2l
    45 
    46 static SDL_bool
    47 X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
    48 {
    49     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    50 
    51     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
    52     if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
    53         return SDL_TRUE;
    54     } else {
    55         return SDL_FALSE;
    56     }
    57 }
    58 
    59 static SDL_bool
    60 X11_IsWindowMapped(_THIS, SDL_Window * window)
    61 {
    62     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    63     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    64     XWindowAttributes attr;
    65 
    66     XGetWindowAttributes(videodata->display, data->xwindow, &attr);
    67     if (attr.map_state != IsUnmapped) {
    68         return SDL_TRUE;
    69     } else {
    70         return SDL_FALSE;
    71     }
    72 }
    73 
    74 static int
    75 X11_GetWMStateProperty(_THIS, SDL_Window * window, Atom atoms[3])
    76 {
    77     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    78     int count = 0;
    79 
    80     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    81         atoms[count++] = data->_NET_WM_STATE_FULLSCREEN;
    82     }
    83     if (window->flags & SDL_WINDOW_MAXIMIZED) {
    84         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_VERT;
    85         atoms[count++] = data->_NET_WM_STATE_MAXIMIZED_HORZ;
    86     }
    87     return count;
    88 }
    89 
    90 static int
    91 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
    92 {
    93     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    94     SDL_WindowData *data;
    95     int numwindows = videodata->numwindows;
    96     int windowlistlength = videodata->windowlistlength;
    97     SDL_WindowData **windowlist = videodata->windowlist;
    98 
    99     /* Allocate the window data */
   100     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   101     if (!data) {
   102         SDL_OutOfMemory();
   103         return -1;
   104     }
   105     data->window = window;
   106     data->xwindow = w;
   107 #ifdef X_HAVE_UTF8_STRING
   108     if (SDL_X11_HAVE_UTF8) {
   109         data->ic =
   110             pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
   111                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
   112                        XNResourceName, videodata->classname, XNResourceClass,
   113                        videodata->classname, NULL);
   114     }
   115 #endif
   116     data->created = created;
   117     data->videodata = videodata;
   118 
   119     /* Associate the data with the window */
   120 
   121     if (numwindows < windowlistlength) {
   122         windowlist[numwindows] = data;
   123         videodata->numwindows++;
   124     } else {
   125         windowlist =
   126             (SDL_WindowData **) SDL_realloc(windowlist,
   127                                             (numwindows +
   128                                              1) * sizeof(*windowlist));
   129         if (!windowlist) {
   130             SDL_OutOfMemory();
   131             SDL_free(data);
   132             return -1;
   133         }
   134         windowlist[numwindows] = data;
   135         videodata->numwindows++;
   136         videodata->windowlistlength++;
   137         videodata->windowlist = windowlist;
   138     }
   139 
   140     /* Fill in the SDL window with the window data */
   141     {
   142         XWindowAttributes attrib;
   143 
   144         XGetWindowAttributes(data->videodata->display, w, &attrib);
   145         window->x = attrib.x;
   146         window->y = attrib.y;
   147         window->w = attrib.width;
   148         window->h = attrib.height;
   149         if (attrib.map_state != IsUnmapped) {
   150             window->flags |= SDL_WINDOW_SHOWN;
   151         } else {
   152             window->flags &= ~SDL_WINDOW_SHOWN;
   153         }
   154         data->visual = attrib.visual;
   155         data->colormap = attrib.colormap;
   156     }
   157 
   158     {
   159         Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   160         Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   161         Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   162         Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   163         Atom actualType;
   164         int actualFormat;
   165         unsigned long i, numItems, bytesAfter;
   166         unsigned char *propertyValue = NULL;
   167         long maxLength = 1024;
   168 
   169         if (XGetWindowProperty(data->videodata->display, w, _NET_WM_STATE,
   170                                0l, maxLength, False, XA_ATOM, &actualType,
   171                                &actualFormat, &numItems, &bytesAfter,
   172                                &propertyValue) == Success) {
   173             Atom *atoms = (Atom *) propertyValue;
   174             int maximized = 0;
   175             int fullscreen = 0;
   176 
   177             for (i = 0; i < numItems; ++i) {
   178                 if (atoms[i] == _NET_WM_STATE_MAXIMIZED_VERT) {
   179                     maximized |= 1;
   180                 } else if (atoms[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
   181                     maximized |= 2;
   182                 } else if ( atoms[i] == _NET_WM_STATE_FULLSCREEN) {
   183                     fullscreen = 1;
   184                 }
   185             }
   186             if (maximized == 3) {
   187                 window->flags |= SDL_WINDOW_MAXIMIZED;
   188             }  else if (fullscreen == 1) {
   189                 window->flags |= SDL_WINDOW_FULLSCREEN;
   190             }
   191             XFree(propertyValue);
   192         }
   193     }
   194 
   195     {
   196         Window FocalWindow;
   197         int RevertTo=0;
   198         XGetInputFocus(data->videodata->display, &FocalWindow, &RevertTo);
   199         if (FocalWindow==w)
   200         {
   201             window->flags |= SDL_WINDOW_INPUT_FOCUS;
   202             SDL_SetKeyboardFocus(data->window);
   203         }
   204 
   205         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   206             /* Tell x11 to clip mouse */
   207         }
   208     }
   209 
   210     /* FIXME: How can I tell?
   211        {
   212        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   213        if (style & WS_VISIBLE) {
   214        if (style & (WS_BORDER | WS_THICKFRAME)) {
   215        window->flags &= ~SDL_WINDOW_BORDERLESS;
   216        } else {
   217        window->flags |= SDL_WINDOW_BORDERLESS;
   218        }
   219        if (style & WS_THICKFRAME) {
   220        window->flags |= SDL_WINDOW_RESIZABLE;
   221        } else {
   222        window->flags &= ~SDL_WINDOW_RESIZABLE;
   223        }
   224        if (style & WS_MINIMIZE) {
   225        window->flags |= SDL_WINDOW_MINIMIZED;
   226        } else {
   227        window->flags &= ~SDL_WINDOW_MINIMIZED;
   228        }
   229        }
   230        if (GetFocus() == hwnd) {
   231        int index = data->videodata->keyboard;
   232        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   233        SDL_SetKeyboardFocus(index, data->window);
   234 
   235        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   236        RECT rect;
   237        GetClientRect(hwnd, &rect);
   238        ClientToScreen(hwnd, (LPPOINT) & rect);
   239        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   240        ClipCursor(&rect);
   241        }
   242        }
   243      */
   244 
   245     /* All done! */
   246     window->driverdata = data;
   247     return 0;
   248 }
   249 
   250 int
   251 X11_CreateWindow(_THIS, SDL_Window * window)
   252 {
   253     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   254     SDL_DisplayData *displaydata =
   255         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   256     Display *display = data->display;
   257     int screen = displaydata->screen;
   258     Visual *visual;
   259     int depth;
   260     XSetWindowAttributes xattr;
   261     Window w;
   262     XSizeHints sizehints;
   263     XWMHints wmhints;
   264     XClassHint classhints;
   265     Atom _NET_WM_WINDOW_TYPE;
   266     Atom _NET_WM_WINDOW_TYPE_NORMAL;
   267     Atom _NET_WM_PID;
   268     int wmstate_count;
   269     Atom wmstate_atoms[3];
   270     Uint32 fevent = 0;
   271 
   272 #if SDL_VIDEO_OPENGL_GLX
   273     if (window->flags & SDL_WINDOW_OPENGL) {
   274         XVisualInfo *vinfo;
   275 
   276         vinfo = X11_GL_GetVisual(_this, display, screen);
   277         if (!vinfo) {
   278             return -1;
   279         }
   280         visual = vinfo->visual;
   281         depth = vinfo->depth;
   282         XFree(vinfo);
   283     } else
   284 #endif
   285 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   286     if (window->flags & SDL_WINDOW_OPENGL) {
   287         XVisualInfo *vinfo;
   288 
   289         vinfo = X11_GLES_GetVisual(_this, display, screen);
   290         if (!vinfo) {
   291             return -1;
   292         }
   293         visual = vinfo->visual;
   294         depth = vinfo->depth;
   295         XFree(vinfo);
   296     } else
   297 #endif
   298     {
   299         visual = displaydata->visual;
   300         depth = displaydata->depth;
   301     }
   302 
   303     xattr.override_redirect = False;
   304     xattr.background_pixel = 0;
   305     xattr.border_pixel = 0;
   306 
   307     if (visual->class == DirectColor) {
   308         XColor *colorcells;
   309         int i;
   310         int ncolors;
   311         int rmax, gmax, bmax;
   312         int rmask, gmask, bmask;
   313         int rshift, gshift, bshift;
   314 
   315         xattr.colormap =
   316             XCreateColormap(display, RootWindow(display, screen),
   317                             visual, AllocAll);
   318 
   319         /* If we can't create a colormap, then we must die */
   320         if (!xattr.colormap) {
   321             SDL_SetError("Could not create writable colormap");
   322             return -1;
   323         }
   324 
   325         /* OK, we got a colormap, now fill it in as best as we can */
   326         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   327         if (!colorcells) {
   328             SDL_OutOfMemory();
   329             return -1;
   330         }
   331         ncolors = visual->map_entries;
   332         rmax = 0xffff;
   333         gmax = 0xffff;
   334         bmax = 0xffff;
   335 
   336         rshift = 0;
   337         rmask = visual->red_mask;
   338         while (0 == (rmask & 1)) {
   339             rshift++;
   340             rmask >>= 1;
   341         }
   342 
   343         gshift = 0;
   344         gmask = visual->green_mask;
   345         while (0 == (gmask & 1)) {
   346             gshift++;
   347             gmask >>= 1;
   348         }
   349 
   350         bshift = 0;
   351         bmask = visual->blue_mask;
   352         while (0 == (bmask & 1)) {
   353             bshift++;
   354             bmask >>= 1;
   355         }
   356 
   357         /* build the color table pixel values */
   358         for (i = 0; i < ncolors; i++) {
   359             Uint32 red = (rmax * i) / (ncolors - 1);
   360             Uint32 green = (gmax * i) / (ncolors - 1);
   361             Uint32 blue = (bmax * i) / (ncolors - 1);
   362 
   363             Uint32 rbits = (rmask * i) / (ncolors - 1);
   364             Uint32 gbits = (gmask * i) / (ncolors - 1);
   365             Uint32 bbits = (bmask * i) / (ncolors - 1);
   366 
   367             Uint32 pix =
   368                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   369 
   370             colorcells[i].pixel = pix;
   371 
   372             colorcells[i].red = red;
   373             colorcells[i].green = green;
   374             colorcells[i].blue = blue;
   375 
   376             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   377         }
   378 
   379         XStoreColors(display, xattr.colormap, colorcells, ncolors);
   380 
   381         SDL_free(colorcells);
   382     } else {
   383         xattr.colormap =
   384             XCreateColormap(display, RootWindow(display, screen),
   385                             visual, AllocNone);
   386     }
   387 
   388     w = XCreateWindow(display, RootWindow(display, screen),
   389                       window->x, window->y, window->w, window->h,
   390                       0, depth, InputOutput, visual,
   391                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   392                        CWColormap), &xattr);
   393     if (!w) {
   394         SDL_SetError("Couldn't create window");
   395         return -1;
   396     }
   397 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   398     if (window->flags & SDL_WINDOW_OPENGL) {
   399         /* Create the GLES window surface */
   400         _this->gles_data->egl_surface =
   401             _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   402                                                  egl_display,
   403                                                  _this->gles_data->egl_config,
   404                                                  (NativeWindowType) w, NULL);
   405 
   406         if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   407             SDL_SetError("Could not create GLES window surface");
   408             return -1;
   409         }
   410     }
   411 #endif
   412 
   413     if (window->flags & SDL_WINDOW_BORDERLESS) {
   414         SDL_bool set;
   415         Atom WM_HINTS;
   416 
   417         /* We haven't modified the window manager hints yet */
   418         set = SDL_FALSE;
   419 
   420         /* First try to set MWM hints */
   421         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   422         if (WM_HINTS != None) {
   423             /* Hints used by Motif compliant window managers */
   424             struct
   425             {
   426                 unsigned long flags;
   427                 unsigned long functions;
   428                 unsigned long decorations;
   429                 long input_mode;
   430                 unsigned long status;
   431             } MWMHints = {
   432             (1L << 1), 0, 0, 0, 0};
   433 
   434             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   435                             PropModeReplace, (unsigned char *) &MWMHints,
   436                             sizeof(MWMHints) / 4);
   437             set = SDL_TRUE;
   438         }
   439         /* Now try to set KWM hints */
   440         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   441         if (WM_HINTS != None) {
   442             long KWMHints = 0;
   443 
   444             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   445                             PropModeReplace,
   446                             (unsigned char *) &KWMHints,
   447                             sizeof(KWMHints) / 4);
   448             set = SDL_TRUE;
   449         }
   450         /* Now try to set GNOME hints */
   451         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   452         if (WM_HINTS != None) {
   453             long GNOMEHints = 0;
   454 
   455             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   456                             PropModeReplace,
   457                             (unsigned char *) &GNOMEHints,
   458                             sizeof(GNOMEHints) / 4);
   459             set = SDL_TRUE;
   460         }
   461         /* Finally set the transient hints if necessary */
   462         if (!set) {
   463             XSetTransientForHint(display, w, RootWindow(display, screen));
   464         }
   465     } else {
   466         SDL_bool set;
   467         Atom WM_HINTS;
   468 
   469         /* We haven't modified the window manager hints yet */
   470         set = SDL_FALSE;
   471 
   472         /* First try to unset MWM hints */
   473         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   474         if (WM_HINTS != None) {
   475             XDeleteProperty(display, w, WM_HINTS);
   476             set = SDL_TRUE;
   477         }
   478         /* Now try to unset KWM hints */
   479         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   480         if (WM_HINTS != None) {
   481             XDeleteProperty(display, w, WM_HINTS);
   482             set = SDL_TRUE;
   483         }
   484         /* Now try to unset GNOME hints */
   485         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   486         if (WM_HINTS != None) {
   487             XDeleteProperty(display, w, WM_HINTS);
   488             set = SDL_TRUE;
   489         }
   490         /* Finally unset the transient hints if necessary */
   491         if (!set) {
   492             XDeleteProperty(display, w, XA_WM_TRANSIENT_FOR);
   493         }
   494     }
   495 
   496     /* Setup the normal size hints */
   497     sizehints.flags = 0;
   498     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   499         sizehints.min_width = sizehints.max_width = window->w;
   500         sizehints.min_height = sizehints.max_height = window->h;
   501         sizehints.flags |= (PMaxSize | PMinSize);
   502     }
   503     sizehints.x = window->x;
   504     sizehints.y = window->y;
   505     sizehints.flags |= USPosition;
   506 
   507     /* Setup the input hints so we get keyboard input */
   508     wmhints.input = True;
   509     wmhints.flags = InputHint;
   510 
   511     /* Setup the class hints so we can get an icon (AfterStep) */
   512     classhints.res_name = data->classname;
   513     classhints.res_class = data->classname;
   514 
   515     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   516     XSetWMProperties(display, w, NULL, NULL, NULL, 0, &sizehints, &wmhints, &classhints);
   517 
   518     /* Set the PID related to the window for the given hostname, if possible */
   519     if (data->pid > 0) {
   520         _NET_WM_PID = XInternAtom(display, "_NET_WM_PID", False);
   521         XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   522                         (unsigned char *)&data->pid, 1);
   523     }
   524 
   525     /* Set the window manager state */
   526     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   527     if (wmstate_count > 0) {
   528         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   529                         PropModeReplace,
   530                         (unsigned char *)wmstate_atoms, wmstate_count);
   531     } else {
   532         XDeleteProperty(display, w, data->_NET_WM_STATE);
   533     }
   534 
   535     /* Let the window manager know we're a "normal" window */
   536     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   537     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   538     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   539                     PropModeReplace,
   540                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   541 
   542     /* Allow the window to be deleted by the window manager */
   543     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   544 
   545     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   546         XDestroyWindow(display, w);
   547         return -1;
   548     }
   549 
   550 #ifdef X_HAVE_UTF8_STRING
   551     if (SDL_X11_HAVE_UTF8) {
   552         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   553                       XNFilterEvents, &fevent, NULL);
   554     }
   555 #endif
   556 
   557     X11_Xinput2SelectTouch(_this, window);
   558 
   559     XSelectInput(display, w,
   560                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   561                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   562                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   563                  PropertyChangeMask | StructureNotifyMask |
   564                  KeymapStateMask | fevent));
   565 
   566     XFlush(display);
   567 
   568     return 0;
   569 }
   570 
   571 int
   572 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   573 {
   574     Window w = (Window) data;
   575 
   576     window->title = X11_GetWindowTitle(_this, w);
   577 
   578     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   579         return -1;
   580     }
   581     return 0;
   582 }
   583 
   584 char *
   585 X11_GetWindowTitle(_THIS, Window xwindow)
   586 {
   587     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   588     Display *display = data->display;
   589     int status, real_format;
   590     Atom real_type;
   591     unsigned long items_read, items_left;
   592     unsigned char *propdata;
   593     char *title = NULL;
   594 
   595     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   596                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   597                 &items_read, &items_left, &propdata);
   598     if (status == Success && propdata) {
   599         title = SDL_strdup(SDL_static_cast(char*, propdata));
   600         XFree(propdata);
   601     } else {
   602         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   603                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   604                     &items_read, &items_left, &propdata);
   605         if (status == Success && propdata) {
   606             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   607         } else {
   608             title = SDL_strdup("");
   609         }
   610     }
   611     return title;
   612 }
   613 
   614 void
   615 X11_SetWindowTitle(_THIS, SDL_Window * window)
   616 {
   617     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   618     Display *display = data->videodata->display;
   619     XTextProperty titleprop, iconprop;
   620     Status status;
   621     const char *title = window->title;
   622     const char *icon = NULL;
   623 
   624 #ifdef X_HAVE_UTF8_STRING
   625     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   626     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   627 #endif
   628 
   629     if (title != NULL) {
   630         char *title_locale = SDL_iconv_utf8_locale(title);
   631         if (!title_locale) {
   632             SDL_OutOfMemory();
   633             return;
   634         }
   635         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   636         SDL_free(title_locale);
   637         if (status) {
   638             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   639             XFree(titleprop.value);
   640         }
   641 #ifdef X_HAVE_UTF8_STRING
   642         if (SDL_X11_HAVE_UTF8) {
   643             status =
   644                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   645                                             XUTF8StringStyle, &titleprop);
   646             if (status == Success) {
   647                 XSetTextProperty(display, data->xwindow, &titleprop,
   648                                  _NET_WM_NAME);
   649                 XFree(titleprop.value);
   650             }
   651         }
   652 #endif
   653     }
   654     if (icon != NULL) {
   655         char *icon_locale = SDL_iconv_utf8_locale(icon);
   656         if (!icon_locale) {
   657             SDL_OutOfMemory();
   658             return;
   659         }
   660         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   661         SDL_free(icon_locale);
   662         if (status) {
   663             XSetTextProperty(display, data->xwindow, &iconprop,
   664                              XA_WM_ICON_NAME);
   665             XFree(iconprop.value);
   666         }
   667 #ifdef X_HAVE_UTF8_STRING
   668         if (SDL_X11_HAVE_UTF8) {
   669             status =
   670                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   671                                             XUTF8StringStyle, &iconprop);
   672             if (status == Success) {
   673                 XSetTextProperty(display, data->xwindow, &iconprop,
   674                                  _NET_WM_ICON_NAME);
   675                 XFree(iconprop.value);
   676             }
   677         }
   678 #endif
   679     }
   680     XFlush(display);
   681 }
   682 
   683 void
   684 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   685 {
   686     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   687     Display *display = data->videodata->display;
   688     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   689 
   690     if (icon) {
   691         SDL_PixelFormat format;
   692         SDL_Surface *surface;
   693         int propsize;
   694         long *propdata;
   695 
   696         /* Convert the icon to ARGB for modern window managers */
   697         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
   698         surface = SDL_ConvertSurface(icon, &format, 0);
   699         if (!surface) {
   700             return;
   701         }
   702 
   703         /* Set the _NET_WM_ICON property */
   704         propsize = 2 + (icon->w * icon->h);
   705         propdata = SDL_malloc(propsize * sizeof(long));
   706         if (propdata) {
   707             int x, y;
   708             Uint32 *src;
   709             long *dst;
   710 
   711             propdata[0] = icon->w;
   712             propdata[1] = icon->h;
   713             dst = &propdata[2];
   714             for (y = 0; y < icon->h; ++y) {
   715                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   716                 for (x = 0; x < icon->w; ++x) {
   717                     *dst++ = *src++;
   718                 }
   719             }
   720             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   721                             32, PropModeReplace, (unsigned char *) propdata,
   722                             propsize);
   723         }
   724         SDL_FreeSurface(surface);
   725     } else {
   726         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   727     }
   728     XFlush(display);
   729 }
   730 
   731 void
   732 X11_SetWindowPosition(_THIS, SDL_Window * window)
   733 {
   734     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   735     Display *display = data->videodata->display;
   736 
   737     XMoveWindow(display, data->xwindow, window->x, window->y);
   738     XFlush(display);
   739 }
   740 
   741 void
   742 X11_SetWindowSize(_THIS, SDL_Window * window)
   743 {
   744     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   745     Display *display = data->videodata->display;
   746 
   747     if (SDL_IsShapedWindow(window))
   748         X11_ResizeWindowShape(window);
   749     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   750          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   751             we must set the size hints to adjust the window size.*/
   752          XSizeHints *sizehints = XAllocSizeHints();
   753          long userhints;
   754 
   755          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   756 
   757          sizehints->min_width = sizehints->max_width = window->w;
   758          sizehints->min_height = sizehints->max_height = window->h;
   759 
   760          XSetWMNormalHints(display, data->xwindow, sizehints);
   761 
   762          XFree(sizehints);
   763     } else
   764         XResizeWindow(display, data->xwindow, window->w, window->h);
   765     XFlush(display);
   766 }
   767 
   768 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
   769 {
   770     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
   771 }
   772 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
   773 {
   774     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
   775 }
   776 
   777 void
   778 X11_ShowWindow(_THIS, SDL_Window * window)
   779 {
   780     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   781     Display *display = data->videodata->display;
   782     XEvent event;
   783 
   784     XMapRaised(display, data->xwindow);
   785     /* Blocking wait for "MapNotify" event.
   786      * We use XIfEvent because XWindowEvent takes a mask rather than a type, 
   787      * and XCheckTypedWindowEvent doesn't block */
   788     XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   789     XFlush(display);
   790 }
   791 
   792 void
   793 X11_HideWindow(_THIS, SDL_Window * window)
   794 {
   795     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   796     Display *display = data->videodata->display;
   797     XEvent event;
   798 
   799     XUnmapWindow(display, data->xwindow);
   800     /* Blocking wait for "UnmapNotify" event */
   801     XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);    
   802     XFlush(display);
   803 }
   804 
   805 void
   806 X11_RaiseWindow(_THIS, SDL_Window * window)
   807 {
   808     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   809     Display *display = data->videodata->display;
   810 
   811     XRaiseWindow(display, data->xwindow);
   812     XFlush(display);
   813 }
   814 
   815 static void
   816 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   817 {
   818     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   819     SDL_DisplayData *displaydata =
   820         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   821     Display *display = data->videodata->display;
   822     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   823     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   824     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   825     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   826 
   827     if (X11_IsWindowMapped(_this, window)) {
   828         XEvent e;
   829 
   830         SDL_zero(e);
   831         e.xany.type = ClientMessage;
   832         e.xclient.message_type = _NET_WM_STATE;
   833         e.xclient.format = 32;
   834         e.xclient.window = data->xwindow;
   835         e.xclient.data.l[0] =
   836             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   837         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   838         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   839         e.xclient.data.l[3] = 0l;
   840 
   841         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   842                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   843     } else {
   844         int count = 0;
   845         Atom atoms[3];
   846 
   847         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   848             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   849         }
   850         if (maximized) {
   851             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   852             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   853         }
   854         if (count > 0) {
   855             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   856                             PropModeReplace, (unsigned char *)atoms, count);
   857         } else {
   858             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   859         }
   860     }
   861     XFlush(display);
   862 }
   863 
   864 void
   865 X11_MaximizeWindow(_THIS, SDL_Window * window)
   866 {
   867     SetWindowMaximized(_this, window, SDL_TRUE);
   868 }
   869 
   870 void
   871 X11_MinimizeWindow(_THIS, SDL_Window * window)
   872 {
   873     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   874     SDL_DisplayData *displaydata =
   875         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   876     Display *display = data->videodata->display;
   877  
   878     XIconifyWindow(display, data->xwindow, displaydata->screen);
   879     XFlush(display);
   880 }
   881 
   882 void
   883 X11_RestoreWindow(_THIS, SDL_Window * window)
   884 {
   885     SetWindowMaximized(_this, window, SDL_FALSE);
   886     X11_ShowWindow(_this, window);
   887 }
   888 
   889 void
   890 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   891 {
   892     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   893     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   894     Display *display = data->videodata->display;
   895     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   896     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   897     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   898     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   899 
   900     if (X11_IsWindowMapped(_this, window)) {
   901         XEvent e;
   902 
   903         SDL_zero(e);
   904         e.xany.type = ClientMessage;
   905         e.xclient.message_type = _NET_WM_STATE;
   906         e.xclient.format = 32;
   907         e.xclient.window = data->xwindow;
   908         e.xclient.data.l[0] =
   909             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   910         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   911         e.xclient.data.l[3] = 0l;
   912 
   913         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   914                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   915     } else {
   916         int count = 0;
   917         Atom atoms[3];
   918 
   919         if (fullscreen) {
   920             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   921         }
   922         if (window->flags & SDL_WINDOW_MAXIMIZED) {
   923             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   924             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   925         }
   926         if (count > 0) {
   927             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   928                             PropModeReplace, (unsigned char *)atoms, count);
   929         } else {
   930             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   931         }
   932     }
   933     XFlush(display);
   934 }
   935 
   936 int
   937 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   938 {
   939     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   940     Display *display = data->videodata->display;
   941     Visual *visual = data->visual;
   942     Colormap colormap = data->colormap;
   943     XColor *colorcells;
   944     int ncolors;
   945     int rmask, gmask, bmask;
   946     int rshift, gshift, bshift;
   947     int i;
   948 
   949     if (visual->class != DirectColor) {
   950         SDL_SetError("Window doesn't have DirectColor visual");
   951         return -1;
   952     }
   953 
   954     ncolors = visual->map_entries;
   955     colorcells = SDL_malloc(ncolors * sizeof(XColor));
   956     if (!colorcells) {
   957         SDL_OutOfMemory();
   958         return -1;
   959     }
   960 
   961     rshift = 0;
   962     rmask = visual->red_mask;
   963     while (0 == (rmask & 1)) {
   964         rshift++;
   965         rmask >>= 1;
   966     }
   967 
   968     gshift = 0;
   969     gmask = visual->green_mask;
   970     while (0 == (gmask & 1)) {
   971         gshift++;
   972         gmask >>= 1;
   973     }
   974 
   975     bshift = 0;
   976     bmask = visual->blue_mask;
   977     while (0 == (bmask & 1)) {
   978         bshift++;
   979         bmask >>= 1;
   980     }
   981 
   982     /* build the color table pixel values */
   983     for (i = 0; i < ncolors; i++) {
   984         Uint32 rbits = (rmask * i) / (ncolors - 1);
   985         Uint32 gbits = (gmask * i) / (ncolors - 1);
   986         Uint32 bbits = (bmask * i) / (ncolors - 1);
   987         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   988 
   989         colorcells[i].pixel = pix;
   990 
   991         colorcells[i].red = ramp[(0 * 256) + i];
   992         colorcells[i].green = ramp[(1 * 256) + i];
   993         colorcells[i].blue = ramp[(2 * 256) + i];
   994 
   995         colorcells[i].flags = DoRed | DoGreen | DoBlue;
   996     }
   997 
   998     XStoreColors(display, colormap, colorcells, ncolors);
   999     XFlush(display);
  1000     SDL_free(colorcells);
  1001 
  1002     return 0;
  1003 }
  1004 
  1005 void
  1006 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1007 {
  1008     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1009     Display *display = data->videodata->display;
  1010     SDL_bool oldstyle_fullscreen;
  1011 
  1012     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1013     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1014 
  1015     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1016         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1017         /* Try to grab the mouse */
  1018         for (;;) {
  1019             int result =
  1020                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1021                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1022             if (result == GrabSuccess) {
  1023                 break;
  1024             }
  1025             SDL_Delay(100);
  1026         }
  1027 
  1028         /* Raise the window if we grab the mouse */
  1029         XRaiseWindow(display, data->xwindow);
  1030 
  1031         /* Now grab the keyboard */
  1032         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1033                       GrabModeAsync, CurrentTime);
  1034     } else {
  1035         XUngrabPointer(display, CurrentTime);
  1036         XUngrabKeyboard(display, CurrentTime);
  1037     }
  1038 }
  1039 
  1040 void
  1041 X11_DestroyWindow(_THIS, SDL_Window * window)
  1042 {
  1043     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1044     window->driverdata = NULL;
  1045 
  1046     if (data) {
  1047         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1048         Display *display = videodata->display;
  1049         int numwindows = videodata->numwindows;
  1050         SDL_WindowData **windowlist = videodata->windowlist;
  1051         int i;
  1052 
  1053         if (windowlist) {
  1054             for (i = 0; i < numwindows; ++i) {
  1055                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1056                     windowlist[i] = windowlist[numwindows - 1];
  1057                     windowlist[numwindows - 1] = NULL;
  1058                     videodata->numwindows--;
  1059                     break;
  1060                 }
  1061             }
  1062         }
  1063 #ifdef X_HAVE_UTF8_STRING
  1064         if (data->ic) {
  1065             XDestroyIC(data->ic);
  1066         }
  1067 #endif
  1068         if (data->created) {
  1069             XDestroyWindow(display, data->xwindow);
  1070             XFlush(display);
  1071         }
  1072         SDL_free(data);
  1073     }
  1074 }
  1075 
  1076 SDL_bool
  1077 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1078 {
  1079     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1080     Display *display = data->videodata->display;
  1081 
  1082     if (info->version.major == SDL_MAJOR_VERSION &&
  1083         info->version.minor == SDL_MINOR_VERSION) {
  1084         info->subsystem = SDL_SYSWM_X11;
  1085         info->info.x11.display = display;
  1086         info->info.x11.window = data->xwindow;
  1087         return SDL_TRUE;
  1088     } else {
  1089         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1090                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1091         return SDL_FALSE;
  1092     }
  1093 }
  1094 
  1095 #endif /* SDL_VIDEO_DRIVER_X11 */
  1096 
  1097 /* vi: set ts=4 sw=4 expandtab: */