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