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