src/video/x11/SDL_x11window.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 19 Jul 2012 09:36:58 -0700
changeset 6373 494e0436525f
parent 6370 93187f7f7d5d
child 6422 fd0ac1b56115
permissions -rwxr-xr-x
More OpenGL ES fixes from Scott Percival
     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 || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   273     if (window->flags & SDL_WINDOW_OPENGL) {
   274         XVisualInfo *vinfo;
   275 
   276 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2        
   277         if (_this->gl_config.use_egl == 1) {
   278             vinfo = X11_GLES_GetVisual(_this, display, screen);
   279         } else
   280 #endif
   281         {
   282 #if SDL_VIDEO_OPENGL_GLX
   283             vinfo = X11_GL_GetVisual(_this, display, screen);
   284 #endif
   285         }
   286         if (!vinfo) {
   287             return -1;
   288         }
   289         visual = vinfo->visual;
   290         depth = vinfo->depth;
   291         XFree(vinfo);
   292     } else
   293 #endif
   294     {
   295         visual = displaydata->visual;
   296         depth = displaydata->depth;
   297     }
   298 
   299     xattr.override_redirect = False;
   300     xattr.background_pixel = 0;
   301     xattr.border_pixel = 0;
   302 
   303     if (visual->class == DirectColor) {
   304         XColor *colorcells;
   305         int i;
   306         int ncolors;
   307         int rmax, gmax, bmax;
   308         int rmask, gmask, bmask;
   309         int rshift, gshift, bshift;
   310 
   311         xattr.colormap =
   312             XCreateColormap(display, RootWindow(display, screen),
   313                             visual, AllocAll);
   314 
   315         /* If we can't create a colormap, then we must die */
   316         if (!xattr.colormap) {
   317             SDL_SetError("Could not create writable colormap");
   318             return -1;
   319         }
   320 
   321         /* OK, we got a colormap, now fill it in as best as we can */
   322         colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   323         if (!colorcells) {
   324             SDL_OutOfMemory();
   325             return -1;
   326         }
   327         ncolors = visual->map_entries;
   328         rmax = 0xffff;
   329         gmax = 0xffff;
   330         bmax = 0xffff;
   331 
   332         rshift = 0;
   333         rmask = visual->red_mask;
   334         while (0 == (rmask & 1)) {
   335             rshift++;
   336             rmask >>= 1;
   337         }
   338 
   339         gshift = 0;
   340         gmask = visual->green_mask;
   341         while (0 == (gmask & 1)) {
   342             gshift++;
   343             gmask >>= 1;
   344         }
   345 
   346         bshift = 0;
   347         bmask = visual->blue_mask;
   348         while (0 == (bmask & 1)) {
   349             bshift++;
   350             bmask >>= 1;
   351         }
   352 
   353         /* build the color table pixel values */
   354         for (i = 0; i < ncolors; i++) {
   355             Uint32 red = (rmax * i) / (ncolors - 1);
   356             Uint32 green = (gmax * i) / (ncolors - 1);
   357             Uint32 blue = (bmax * i) / (ncolors - 1);
   358 
   359             Uint32 rbits = (rmask * i) / (ncolors - 1);
   360             Uint32 gbits = (gmask * i) / (ncolors - 1);
   361             Uint32 bbits = (bmask * i) / (ncolors - 1);
   362 
   363             Uint32 pix =
   364                 (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   365 
   366             colorcells[i].pixel = pix;
   367 
   368             colorcells[i].red = red;
   369             colorcells[i].green = green;
   370             colorcells[i].blue = blue;
   371 
   372             colorcells[i].flags = DoRed | DoGreen | DoBlue;
   373         }
   374 
   375         XStoreColors(display, xattr.colormap, colorcells, ncolors);
   376 
   377         SDL_free(colorcells);
   378     } else {
   379         xattr.colormap =
   380             XCreateColormap(display, RootWindow(display, screen),
   381                             visual, AllocNone);
   382     }
   383 
   384     w = XCreateWindow(display, RootWindow(display, screen),
   385                       window->x, window->y, window->w, window->h,
   386                       0, depth, InputOutput, visual,
   387                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   388                        CWColormap), &xattr);
   389     if (!w) {
   390         SDL_SetError("Couldn't create window");
   391         return -1;
   392     }
   393 #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   394     if ((window->flags & SDL_WINDOW_OPENGL) && (_this->gl_config.use_egl == 1)) {
   395         if (!_this->gles_data) {
   396             XDestroyWindow(display, w);
   397             return -1;
   398         }
   399 
   400         /* Create the GLES window surface */
   401         _this->gles_data->egl_surface =
   402             _this->gles_data->eglCreateWindowSurface(_this->gles_data->
   403                                                  egl_display,
   404                                                  _this->gles_data->egl_config,
   405                                                  (NativeWindowType) w, NULL);
   406 
   407         if (_this->gles_data->egl_surface == EGL_NO_SURFACE) {
   408             SDL_SetError("Could not create GLES window surface");
   409             XDestroyWindow(display, w);
   410             return -1;
   411         }
   412     }
   413 #endif
   414 
   415     if (window->flags & SDL_WINDOW_BORDERLESS) {
   416         SDL_bool set;
   417         Atom WM_HINTS;
   418 
   419         /* We haven't modified the window manager hints yet */
   420         set = SDL_FALSE;
   421 
   422         /* First try to set MWM hints */
   423         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   424         if (WM_HINTS != None) {
   425             /* Hints used by Motif compliant window managers */
   426             struct
   427             {
   428                 unsigned long flags;
   429                 unsigned long functions;
   430                 unsigned long decorations;
   431                 long input_mode;
   432                 unsigned long status;
   433             } MWMHints = {
   434             (1L << 1), 0, 0, 0, 0};
   435 
   436             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   437                             PropModeReplace, (unsigned char *) &MWMHints,
   438                             sizeof(MWMHints) / 4);
   439             set = SDL_TRUE;
   440         }
   441         /* Now try to set KWM hints */
   442         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   443         if (WM_HINTS != None) {
   444             long KWMHints = 0;
   445 
   446             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   447                             PropModeReplace,
   448                             (unsigned char *) &KWMHints,
   449                             sizeof(KWMHints) / 4);
   450             set = SDL_TRUE;
   451         }
   452         /* Now try to set GNOME hints */
   453         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   454         if (WM_HINTS != None) {
   455             long GNOMEHints = 0;
   456 
   457             XChangeProperty(display, w, WM_HINTS, WM_HINTS, 32,
   458                             PropModeReplace,
   459                             (unsigned char *) &GNOMEHints,
   460                             sizeof(GNOMEHints) / 4);
   461             set = SDL_TRUE;
   462         }
   463         /* Finally set the transient hints if necessary */
   464         if (!set) {
   465             XSetTransientForHint(display, w, RootWindow(display, screen));
   466         }
   467     } else {
   468         SDL_bool set;
   469         Atom WM_HINTS;
   470 
   471         /* We haven't modified the window manager hints yet */
   472         set = SDL_FALSE;
   473 
   474         /* First try to unset MWM hints */
   475         WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", True);
   476         if (WM_HINTS != None) {
   477             XDeleteProperty(display, w, WM_HINTS);
   478             set = SDL_TRUE;
   479         }
   480         /* Now try to unset KWM hints */
   481         WM_HINTS = XInternAtom(display, "KWM_WIN_DECORATION", True);
   482         if (WM_HINTS != None) {
   483             XDeleteProperty(display, w, WM_HINTS);
   484             set = SDL_TRUE;
   485         }
   486         /* Now try to unset GNOME hints */
   487         WM_HINTS = XInternAtom(display, "_WIN_HINTS", True);
   488         if (WM_HINTS != None) {
   489             XDeleteProperty(display, w, WM_HINTS);
   490             set = SDL_TRUE;
   491         }
   492         /* Finally unset the transient hints if necessary */
   493         if (!set) {
   494             XDeleteProperty(display, w, XA_WM_TRANSIENT_FOR);
   495         }
   496     }
   497 
   498     /* Setup the normal size hints */
   499     sizehints.flags = 0;
   500     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   501         sizehints.min_width = sizehints.max_width = window->w;
   502         sizehints.min_height = sizehints.max_height = window->h;
   503         sizehints.flags |= (PMaxSize | PMinSize);
   504     }
   505     sizehints.x = window->x;
   506     sizehints.y = window->y;
   507     sizehints.flags |= USPosition;
   508 
   509     /* Setup the input hints so we get keyboard input */
   510     wmhints.input = True;
   511     wmhints.flags = InputHint;
   512 
   513     /* Setup the class hints so we can get an icon (AfterStep) */
   514     classhints.res_name = data->classname;
   515     classhints.res_class = data->classname;
   516 
   517     /* Set the size, input and class hints, and define WM_CLIENT_MACHINE and WM_LOCALE_NAME */
   518     XSetWMProperties(display, w, NULL, NULL, NULL, 0, &sizehints, &wmhints, &classhints);
   519 
   520     /* Set the PID related to the window for the given hostname, if possible */
   521     if (data->pid > 0) {
   522         _NET_WM_PID = XInternAtom(display, "_NET_WM_PID", False);
   523         XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace,
   524                         (unsigned char *)&data->pid, 1);
   525     }
   526 
   527     /* Set the window manager state */
   528     wmstate_count = X11_GetWMStateProperty(_this, window, wmstate_atoms);
   529     if (wmstate_count > 0) {
   530         XChangeProperty(display, w, data->_NET_WM_STATE, XA_ATOM, 32,
   531                         PropModeReplace,
   532                         (unsigned char *)wmstate_atoms, wmstate_count);
   533     } else {
   534         XDeleteProperty(display, w, data->_NET_WM_STATE);
   535     }
   536 
   537     /* Let the window manager know we're a "normal" window */
   538     _NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
   539     _NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
   540     XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
   541                     PropModeReplace,
   542                     (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1);
   543 
   544     /* Allow the window to be deleted by the window manager */
   545     XSetWMProtocols(display, w, &data->WM_DELETE_WINDOW, 1);
   546 
   547     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   548         XDestroyWindow(display, w);
   549         return -1;
   550     }
   551 
   552 #ifdef X_HAVE_UTF8_STRING
   553     if (SDL_X11_HAVE_UTF8) {
   554         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   555                       XNFilterEvents, &fevent, NULL);
   556     }
   557 #endif
   558 
   559     X11_Xinput2SelectTouch(_this, window);
   560 
   561     XSelectInput(display, w,
   562                  (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   563                  ExposureMask | ButtonPressMask | ButtonReleaseMask |
   564                  PointerMotionMask | KeyPressMask | KeyReleaseMask |
   565                  PropertyChangeMask | StructureNotifyMask |
   566                  KeymapStateMask | fevent));
   567 
   568     XFlush(display);
   569 
   570     return 0;
   571 }
   572 
   573 int
   574 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   575 {
   576     Window w = (Window) data;
   577 
   578     window->title = X11_GetWindowTitle(_this, w);
   579 
   580     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   581         return -1;
   582     }
   583     return 0;
   584 }
   585 
   586 char *
   587 X11_GetWindowTitle(_THIS, Window xwindow)
   588 {
   589     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   590     Display *display = data->display;
   591     int status, real_format;
   592     Atom real_type;
   593     unsigned long items_read, items_left;
   594     unsigned char *propdata;
   595     char *title = NULL;
   596 
   597     status = XGetWindowProperty(display, xwindow, data->_NET_WM_NAME,
   598                 0L, 8192L, False, data->UTF8_STRING, &real_type, &real_format,
   599                 &items_read, &items_left, &propdata);
   600     if (status == Success && propdata) {
   601         title = SDL_strdup(SDL_static_cast(char*, propdata));
   602         XFree(propdata);
   603     } else {
   604         status = XGetWindowProperty(display, xwindow, XA_WM_NAME,
   605                     0L, 8192L, False, XA_STRING, &real_type, &real_format,
   606                     &items_read, &items_left, &propdata);
   607         if (status == Success && propdata) {
   608             title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1);
   609         } else {
   610             title = SDL_strdup("");
   611         }
   612     }
   613     return title;
   614 }
   615 
   616 void
   617 X11_SetWindowTitle(_THIS, SDL_Window * window)
   618 {
   619     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   620     Display *display = data->videodata->display;
   621     XTextProperty titleprop, iconprop;
   622     Status status;
   623     const char *title = window->title;
   624     const char *icon = NULL;
   625 
   626 #ifdef X_HAVE_UTF8_STRING
   627     Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME;
   628     Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME;
   629 #endif
   630 
   631     if (title != NULL) {
   632         char *title_locale = SDL_iconv_utf8_locale(title);
   633         if (!title_locale) {
   634             SDL_OutOfMemory();
   635             return;
   636         }
   637         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   638         SDL_free(title_locale);
   639         if (status) {
   640             XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME);
   641             XFree(titleprop.value);
   642         }
   643 #ifdef X_HAVE_UTF8_STRING
   644         if (SDL_X11_HAVE_UTF8) {
   645             status =
   646                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   647                                             XUTF8StringStyle, &titleprop);
   648             if (status == Success) {
   649                 XSetTextProperty(display, data->xwindow, &titleprop,
   650                                  _NET_WM_NAME);
   651                 XFree(titleprop.value);
   652             }
   653         }
   654 #endif
   655     }
   656     if (icon != NULL) {
   657         char *icon_locale = SDL_iconv_utf8_locale(icon);
   658         if (!icon_locale) {
   659             SDL_OutOfMemory();
   660             return;
   661         }
   662         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   663         SDL_free(icon_locale);
   664         if (status) {
   665             XSetTextProperty(display, data->xwindow, &iconprop,
   666                              XA_WM_ICON_NAME);
   667             XFree(iconprop.value);
   668         }
   669 #ifdef X_HAVE_UTF8_STRING
   670         if (SDL_X11_HAVE_UTF8) {
   671             status =
   672                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   673                                             XUTF8StringStyle, &iconprop);
   674             if (status == Success) {
   675                 XSetTextProperty(display, data->xwindow, &iconprop,
   676                                  _NET_WM_ICON_NAME);
   677                 XFree(iconprop.value);
   678             }
   679         }
   680 #endif
   681     }
   682     XFlush(display);
   683 }
   684 
   685 void
   686 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   687 {
   688     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   689     Display *display = data->videodata->display;
   690     Atom _NET_WM_ICON = data->videodata->_NET_WM_ICON;
   691 
   692     if (icon) {
   693         SDL_PixelFormat format;
   694         SDL_Surface *surface;
   695         int propsize;
   696         long *propdata;
   697 
   698         /* Convert the icon to ARGB for modern window managers */
   699         SDL_InitFormat(&format, SDL_PIXELFORMAT_ARGB8888);
   700         surface = SDL_ConvertSurface(icon, &format, 0);
   701         if (!surface) {
   702             return;
   703         }
   704 
   705         /* Set the _NET_WM_ICON property */
   706         propsize = 2 + (icon->w * icon->h);
   707         propdata = SDL_malloc(propsize * sizeof(long));
   708         if (propdata) {
   709             int x, y;
   710             Uint32 *src;
   711             long *dst;
   712 
   713             propdata[0] = icon->w;
   714             propdata[1] = icon->h;
   715             dst = &propdata[2];
   716             for (y = 0; y < icon->h; ++y) {
   717                 src = (Uint32*)((Uint8*)surface->pixels + y * surface->pitch);
   718                 for (x = 0; x < icon->w; ++x) {
   719                     *dst++ = *src++;
   720                 }
   721             }
   722             XChangeProperty(display, data->xwindow, _NET_WM_ICON, XA_CARDINAL,
   723                             32, PropModeReplace, (unsigned char *) propdata,
   724                             propsize);
   725         }
   726         SDL_FreeSurface(surface);
   727     } else {
   728         XDeleteProperty(display, data->xwindow, _NET_WM_ICON);
   729     }
   730     XFlush(display);
   731 }
   732 
   733 void
   734 X11_SetWindowPosition(_THIS, SDL_Window * window)
   735 {
   736     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   737     Display *display = data->videodata->display;
   738 
   739     XMoveWindow(display, data->xwindow, window->x, window->y);
   740     XFlush(display);
   741 }
   742 
   743 void
   744 X11_SetWindowSize(_THIS, SDL_Window * window)
   745 {
   746     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   747     Display *display = data->videodata->display;
   748 
   749     if (SDL_IsShapedWindow(window))
   750         X11_ResizeWindowShape(window);
   751     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   752          /* Apparently, if the X11 Window is set to a 'non-resizable' window, you cannot resize it using the XResizeWindow, thus
   753             we must set the size hints to adjust the window size.*/
   754          XSizeHints *sizehints = XAllocSizeHints();
   755          long userhints;
   756 
   757          XGetWMNormalHints(display, data->xwindow, sizehints, &userhints);
   758 
   759          sizehints->min_width = sizehints->max_width = window->w;
   760          sizehints->min_height = sizehints->max_height = window->h;
   761 
   762          XSetWMNormalHints(display, data->xwindow, sizehints);
   763 
   764          XFree(sizehints);
   765     } else
   766         XResizeWindow(display, data->xwindow, window->w, window->h);
   767     XFlush(display);
   768 }
   769 
   770 static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
   771 {
   772     return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
   773 }
   774 static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
   775 {
   776     return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
   777 }
   778 
   779 void
   780 X11_ShowWindow(_THIS, SDL_Window * window)
   781 {
   782     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   783     Display *display = data->videodata->display;
   784     XEvent event;
   785 
   786     XMapRaised(display, data->xwindow);
   787     /* Blocking wait for "MapNotify" event.
   788      * We use XIfEvent because XWindowEvent takes a mask rather than a type, 
   789      * and XCheckTypedWindowEvent doesn't block */
   790     XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow);
   791     XFlush(display);
   792 }
   793 
   794 void
   795 X11_HideWindow(_THIS, SDL_Window * window)
   796 {
   797     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   798     Display *display = data->videodata->display;
   799     XEvent event;
   800 
   801     XUnmapWindow(display, data->xwindow);
   802     /* Blocking wait for "UnmapNotify" event */
   803     XIfEvent(display, &event, &isUnmapNotify, (XPointer)&data->xwindow);    
   804     XFlush(display);
   805 }
   806 
   807 void
   808 X11_RaiseWindow(_THIS, SDL_Window * window)
   809 {
   810     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   811     Display *display = data->videodata->display;
   812 
   813     XRaiseWindow(display, data->xwindow);
   814     XFlush(display);
   815 }
   816 
   817 static void
   818 SetWindowMaximized(_THIS, SDL_Window * window, SDL_bool maximized)
   819 {
   820     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   821     SDL_DisplayData *displaydata =
   822         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   823     Display *display = data->videodata->display;
   824     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   825     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   826     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   827     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   828 
   829     if (X11_IsWindowMapped(_this, window)) {
   830         XEvent e;
   831 
   832         SDL_zero(e);
   833         e.xany.type = ClientMessage;
   834         e.xclient.message_type = _NET_WM_STATE;
   835         e.xclient.format = 32;
   836         e.xclient.window = data->xwindow;
   837         e.xclient.data.l[0] =
   838             maximized ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   839         e.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
   840         e.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
   841         e.xclient.data.l[3] = 0l;
   842 
   843         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   844                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   845     } else {
   846         int count = 0;
   847         Atom atoms[3];
   848 
   849         if (window->flags & SDL_WINDOW_FULLSCREEN) {
   850             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   851         }
   852         if (maximized) {
   853             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   854             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   855         }
   856         if (count > 0) {
   857             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   858                             PropModeReplace, (unsigned char *)atoms, count);
   859         } else {
   860             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   861         }
   862     }
   863     XFlush(display);
   864 }
   865 
   866 void
   867 X11_MaximizeWindow(_THIS, SDL_Window * window)
   868 {
   869     SetWindowMaximized(_this, window, SDL_TRUE);
   870 }
   871 
   872 void
   873 X11_MinimizeWindow(_THIS, SDL_Window * window)
   874 {
   875     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   876     SDL_DisplayData *displaydata =
   877         (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
   878     Display *display = data->videodata->display;
   879  
   880     XIconifyWindow(display, data->xwindow, displaydata->screen);
   881     XFlush(display);
   882 }
   883 
   884 void
   885 X11_RestoreWindow(_THIS, SDL_Window * window)
   886 {
   887     SetWindowMaximized(_this, window, SDL_FALSE);
   888     X11_ShowWindow(_this, window);
   889 }
   890 
   891 void
   892 X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
   893 {
   894     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   895     SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
   896     Display *display = data->videodata->display;
   897     Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
   898     Atom _NET_WM_STATE_MAXIMIZED_VERT = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT;
   899     Atom _NET_WM_STATE_MAXIMIZED_HORZ = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ;
   900     Atom _NET_WM_STATE_FULLSCREEN = data->videodata->_NET_WM_STATE_FULLSCREEN;
   901 
   902     if (X11_IsWindowMapped(_this, window)) {
   903         XEvent e;
   904 
   905         SDL_zero(e);
   906         e.xany.type = ClientMessage;
   907         e.xclient.message_type = _NET_WM_STATE;
   908         e.xclient.format = 32;
   909         e.xclient.window = data->xwindow;
   910         e.xclient.data.l[0] =
   911             fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   912         e.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
   913         e.xclient.data.l[3] = 0l;
   914 
   915         XSendEvent(display, RootWindow(display, displaydata->screen), 0,
   916                    SubstructureNotifyMask | SubstructureRedirectMask, &e);
   917     } else {
   918         int count = 0;
   919         Atom atoms[3];
   920 
   921         if (fullscreen) {
   922             atoms[count++] = _NET_WM_STATE_FULLSCREEN;
   923         }
   924         if (window->flags & SDL_WINDOW_MAXIMIZED) {
   925             atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
   926             atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
   927         }
   928         if (count > 0) {
   929             XChangeProperty(display, data->xwindow, _NET_WM_STATE, XA_ATOM, 32,
   930                             PropModeReplace, (unsigned char *)atoms, count);
   931         } else {
   932             XDeleteProperty(display, data->xwindow, _NET_WM_STATE);
   933         }
   934     }
   935     XFlush(display);
   936 }
   937 
   938 int
   939 X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   940 {
   941     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   942     Display *display = data->videodata->display;
   943     Visual *visual = data->visual;
   944     Colormap colormap = data->colormap;
   945     XColor *colorcells;
   946     int ncolors;
   947     int rmask, gmask, bmask;
   948     int rshift, gshift, bshift;
   949     int i;
   950 
   951     if (visual->class != DirectColor) {
   952         SDL_SetError("Window doesn't have DirectColor visual");
   953         return -1;
   954     }
   955 
   956     ncolors = visual->map_entries;
   957     colorcells = SDL_malloc(ncolors * sizeof(XColor));
   958     if (!colorcells) {
   959         SDL_OutOfMemory();
   960         return -1;
   961     }
   962 
   963     rshift = 0;
   964     rmask = visual->red_mask;
   965     while (0 == (rmask & 1)) {
   966         rshift++;
   967         rmask >>= 1;
   968     }
   969 
   970     gshift = 0;
   971     gmask = visual->green_mask;
   972     while (0 == (gmask & 1)) {
   973         gshift++;
   974         gmask >>= 1;
   975     }
   976 
   977     bshift = 0;
   978     bmask = visual->blue_mask;
   979     while (0 == (bmask & 1)) {
   980         bshift++;
   981         bmask >>= 1;
   982     }
   983 
   984     /* build the color table pixel values */
   985     for (i = 0; i < ncolors; i++) {
   986         Uint32 rbits = (rmask * i) / (ncolors - 1);
   987         Uint32 gbits = (gmask * i) / (ncolors - 1);
   988         Uint32 bbits = (bmask * i) / (ncolors - 1);
   989         Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   990 
   991         colorcells[i].pixel = pix;
   992 
   993         colorcells[i].red = ramp[(0 * 256) + i];
   994         colorcells[i].green = ramp[(1 * 256) + i];
   995         colorcells[i].blue = ramp[(2 * 256) + i];
   996 
   997         colorcells[i].flags = DoRed | DoGreen | DoBlue;
   998     }
   999 
  1000     XStoreColors(display, colormap, colorcells, ncolors);
  1001     XFlush(display);
  1002     SDL_free(colorcells);
  1003 
  1004     return 0;
  1005 }
  1006 
  1007 void
  1008 X11_SetWindowGrab(_THIS, SDL_Window * window)
  1009 {
  1010     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1011     Display *display = data->videodata->display;
  1012     SDL_bool oldstyle_fullscreen;
  1013 
  1014     /* ICCCM2.0-compliant window managers can handle fullscreen windows */
  1015     oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
  1016 
  1017     if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
  1018         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1019         /* Try to grab the mouse */
  1020         for (;;) {
  1021             int result =
  1022                 XGrabPointer(display, data->xwindow, True, 0, GrabModeAsync,
  1023                              GrabModeAsync, data->xwindow, None, CurrentTime);
  1024             if (result == GrabSuccess) {
  1025                 break;
  1026             }
  1027             SDL_Delay(100);
  1028         }
  1029 
  1030         /* Raise the window if we grab the mouse */
  1031         XRaiseWindow(display, data->xwindow);
  1032 
  1033         /* Now grab the keyboard */
  1034         XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
  1035                       GrabModeAsync, CurrentTime);
  1036     } else {
  1037         XUngrabPointer(display, CurrentTime);
  1038         XUngrabKeyboard(display, CurrentTime);
  1039     }
  1040 }
  1041 
  1042 void
  1043 X11_DestroyWindow(_THIS, SDL_Window * window)
  1044 {
  1045     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1046     window->driverdata = NULL;
  1047 
  1048     if (data) {
  1049         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
  1050         Display *display = videodata->display;
  1051         int numwindows = videodata->numwindows;
  1052         SDL_WindowData **windowlist = videodata->windowlist;
  1053         int i;
  1054 
  1055         if (windowlist) {
  1056             for (i = 0; i < numwindows; ++i) {
  1057                 if (windowlist[i] && (windowlist[i]->window == window)) {
  1058                     windowlist[i] = windowlist[numwindows - 1];
  1059                     windowlist[numwindows - 1] = NULL;
  1060                     videodata->numwindows--;
  1061                     break;
  1062                 }
  1063             }
  1064         }
  1065 #ifdef X_HAVE_UTF8_STRING
  1066         if (data->ic) {
  1067             XDestroyIC(data->ic);
  1068         }
  1069 #endif
  1070         if (data->created) {
  1071             XDestroyWindow(display, data->xwindow);
  1072             XFlush(display);
  1073         }
  1074         SDL_free(data);
  1075     }
  1076 }
  1077 
  1078 SDL_bool
  1079 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1080 {
  1081     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1082     Display *display = data->videodata->display;
  1083 
  1084     if (info->version.major == SDL_MAJOR_VERSION &&
  1085         info->version.minor == SDL_MINOR_VERSION) {
  1086         info->subsystem = SDL_SYSWM_X11;
  1087         info->info.x11.display = display;
  1088         info->info.x11.window = data->xwindow;
  1089         return SDL_TRUE;
  1090     } else {
  1091         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1092                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1093         return SDL_FALSE;
  1094     }
  1095 }
  1096 
  1097 #endif /* SDL_VIDEO_DRIVER_X11 */
  1098 
  1099 /* vi: set ts=4 sw=4 expandtab: */