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