src/video/x11/SDL_x11window.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 22 Oct 2011 02:14:57 -0400
changeset 6024 38e2f4644548
parent 6023 6279958d571d
child 6045 b8e995dab018
permissions -rw-r--r--
Set up window focus correctly when using an existing X11 window.

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