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