src/video/x11/SDL_x11window.c
author Bob Pendleton <bob@pendleton.com>
Thu, 15 Jan 2009 21:35:42 +0000
changeset 3044 b36579172f27
parent 3009 546c022a9ae5
child 3052 b7197d7e8566
permissions -rw-r--r--
Changes to hopefully handle the creation of a colormap for 8 bit PseudoColor visuals in X11
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_syswm.h"
    25 #include "../SDL_sysvideo.h"
    26 #include "../../events/SDL_keyboard_c.h"
    27 #include "../../events/SDL_mouse_c.h"
    28 
    29 #include "SDL_x11video.h"
    30 #include "SDL_x11mouse.h"
    31 #include "SDL_x11gamma.h"
    32 #include "../Xext/extensions/StdCmap.h"
    33 
    34 static void
    35 X11_GetDisplaySize(_THIS, SDL_Window * window, int *w, int *h)
    36 {
    37     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    38     SDL_DisplayData *displaydata =
    39         (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
    40     XWindowAttributes attr;
    41 
    42     XGetWindowAttributes(data->display, RootWindow(data->display,
    43                                                    displaydata->screen),
    44                          &attr);
    45     if (w) {
    46         *w = attr.width;
    47     }
    48     if (h) {
    49         *h = attr.height;
    50     }
    51 }
    52 
    53 static int
    54 SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
    55 {
    56     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    57     SDL_WindowData *data;
    58     int numwindows = videodata->numwindows;
    59     int windowlistlength = videodata->windowlistlength;
    60     SDL_WindowData **windowlist = videodata->windowlist;
    61     int index;
    62 
    63     /* Allocate the window data */
    64     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
    65     if (!data) {
    66         SDL_OutOfMemory();
    67         return -1;
    68     }
    69     data->windowID = window->id;
    70     data->window = w;
    71 #ifdef X_HAVE_UTF8_STRING
    72     if (SDL_X11_HAVE_UTF8) {
    73         data->ic =
    74             pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w,
    75                        XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
    76                        XNResourceName, videodata->classname, XNResourceClass,
    77                        videodata->classname, NULL);
    78     }
    79 #endif
    80     data->created = created;
    81     data->videodata = videodata;
    82 
    83     /* Associate the data with the window */
    84 
    85     if (numwindows < windowlistlength) {
    86         windowlist[numwindows] = data;
    87         videodata->numwindows++;
    88     } else {
    89         windowlist =
    90             (SDL_WindowData **) SDL_realloc(windowlist,
    91                                             (numwindows +
    92                                              1) * sizeof(*windowlist));
    93         if (!windowlist) {
    94             SDL_OutOfMemory();
    95             SDL_free(data);
    96             return -1;
    97         }
    98         windowlist[numwindows] = data;
    99         videodata->numwindows++;
   100         videodata->windowlistlength++;
   101         videodata->windowlist = windowlist;
   102     }
   103 
   104     /* Fill in the SDL window with the window data */
   105     {
   106         XWindowAttributes attrib;
   107 
   108         XGetWindowAttributes(data->videodata->display, w, &attrib);
   109         window->x = attrib.x;
   110         window->y = attrib.y;
   111         window->w = attrib.width;
   112         window->h = attrib.height;
   113         if (attrib.map_state != IsUnmapped) {
   114             window->flags |= SDL_WINDOW_SHOWN;
   115         } else {
   116             window->flags &= ~SDL_WINDOW_SHOWN;
   117         }
   118     }
   119     /* FIXME: How can I tell?
   120        {
   121        DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   122        if (style & WS_VISIBLE) {
   123        if (style & (WS_BORDER | WS_THICKFRAME)) {
   124        window->flags &= ~SDL_WINDOW_BORDERLESS;
   125        } else {
   126        window->flags |= SDL_WINDOW_BORDERLESS;
   127        }
   128        if (style & WS_THICKFRAME) {
   129        window->flags |= SDL_WINDOW_RESIZABLE;
   130        } else {
   131        window->flags &= ~SDL_WINDOW_RESIZABLE;
   132        }
   133        if (style & WS_MAXIMIZE) {
   134        window->flags |= SDL_WINDOW_MAXIMIZED;
   135        } else {
   136        window->flags &= ~SDL_WINDOW_MAXIMIZED;
   137        }
   138        if (style & WS_MINIMIZE) {
   139        window->flags |= SDL_WINDOW_MINIMIZED;
   140        } else {
   141        window->flags &= ~SDL_WINDOW_MINIMIZED;
   142        }
   143        }
   144        if (GetFocus() == hwnd) {
   145        int index = data->videodata->keyboard;
   146        window->flags |= SDL_WINDOW_INPUT_FOCUS;
   147        SDL_SetKeyboardFocus(index, data->windowID);
   148 
   149        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   150        RECT rect;
   151        GetClientRect(hwnd, &rect);
   152        ClientToScreen(hwnd, (LPPOINT) & rect);
   153        ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   154        ClipCursor(&rect);
   155        }
   156        }
   157      */
   158 
   159     /* All done! */
   160     window->driverdata = data;
   161     return 0;
   162 }
   163 
   164 int
   165 X11_CreateWindow(_THIS, SDL_Window * window)
   166 {
   167     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   168     SDL_DisplayData *displaydata =
   169         (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
   170     Visual *visual;
   171     int depth;
   172     XSetWindowAttributes xattr;
   173     int x, y;
   174     Window w;
   175     XSizeHints *sizehints;
   176     XWMHints *wmhints;
   177     XClassHint *classhints;
   178 
   179 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   180 /* FIXME
   181     if ( use_xinerama ) {
   182         x = xinerama_info.x_org;
   183         y = xinerama_info.y_org;
   184     }
   185 */
   186 #endif
   187 #ifdef SDL_VIDEO_OPENGL_GLX
   188     if (window->flags & SDL_WINDOW_OPENGL) {
   189         XVisualInfo *vinfo;
   190 
   191         if (X11_GL_Initialize(_this) < 0) {
   192             return -1;
   193         }
   194         vinfo = X11_GL_GetVisual(_this, data->display, displaydata->screen);
   195         if (!vinfo) {
   196             return -1;
   197         }
   198         visual = vinfo->visual;
   199         depth = vinfo->depth;
   200         XFree(vinfo);
   201     } else
   202 #endif
   203     {
   204         visual = displaydata->visual;
   205         depth = displaydata->depth;
   206     }
   207 
   208     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   209         xattr.override_redirect = True;
   210     } else {
   211         xattr.override_redirect = False;
   212     }
   213     xattr.background_pixel = 0;
   214     xattr.border_pixel = 0;
   215 
   216     if (visual->class == PseudoColor) {
   217         printf("asking for PseudoColor\n");
   218 
   219         Status status;
   220         XStandardColormap cmap;
   221         XColor *colorcells;
   222         Colormap colormap;
   223 	Sint32 pix;
   224         Sint32 ncolors;
   225         Sint32 nbits;
   226         Sint32 rmax, gmax, bmax;
   227 	Sint32 rwidth, gwidth, bwidth;
   228         Sint32 rmask, gmask, bmask;
   229         Sint32 rshift, gshift, bshift;
   230 	Sint32 r, g, b;
   231 
   232         /* Is the colormap we need already registered in SDL? */
   233         if (colormap =
   234             X11_LookupColormap(data->display,
   235                                displaydata->screen, visual->visualid)) {
   236             xattr.colormap = colormap;
   237 /*             printf("found existing colormap\n"); */
   238         } else {
   239             /* The colormap is not known to SDL so we will create it */
   240             colormap = XCreateColormap(data->display,
   241                                        RootWindow(data->display,
   242                                                   displaydata->screen),
   243                                        visual, AllocAll);
   244 /*             printf("colormap = %x\n", colormap); */
   245 
   246             /* If we can't create a colormap, then we must die */
   247             if (!colormap) {
   248                 SDL_SetError
   249                     ("Couldn't create window: Could not create writable colormap");
   250                 return -1;
   251             }
   252 
   253             /* OK, we got a colormap, now fill it in as best as we can */
   254 
   255             colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   256             if (NULL == colorcells) {
   257                 SDL_SetError("out of memory in X11_CreateWindow");
   258                 return -1;
   259             }
   260 
   261             ncolors = visual->map_entries;
   262 	    nbits = visual->bits_per_rgb;
   263 
   264 /* 	    printf("ncolors = %d nbits = %d\n", ncolors, nbits); */
   265 
   266 	    /* what if ncolors != (1 << nbits)? That can happen on a
   267 	       true PseudoColor display.  I'm assuming that we will
   268 	       always have ncolors == (1 << nbits)*/
   269 
   270 	    /* I'm making a lot of assumptions here. */
   271 	    
   272 	    /* Compute the width of each field. If there is one extra
   273 	       bit, give it to green. If there are two extra bits give
   274 	       them to red and greed.  We can get extra bits when the
   275 	       number of bits per pixel is not a multiple of 3. For
   276 	       example when we have 16 bits per pixel and need a 5/6/5
   277 	       layout for the RGB fields */
   278 
   279 	    rwidth = (nbits / 3) + (((nbits % 3) == 2) ? 1 : 0);
   280 	    gwidth = (nbits / 3) + (((nbits % 3) >= 1) ? 1 : 0);
   281 	    bwidth = (nbits / 3);
   282 
   283             rshift = gwidth + bwidth;
   284             gshift = bwidth;
   285             bshift = 0;
   286 
   287             rmax = 1 << rwidth;
   288             gmax = 1 << gwidth;
   289             bmax = 1 << bwidth;
   290 
   291             rmask = rmax - 1;
   292             gmask = gmax - 1;
   293             bmask = bmax - 1;
   294 
   295 /*             printf("red   mask = %4x shift = %4d width = %d\n", rmask, rshift, rwidth); */
   296 /*             printf("green mask = %4x shift = %4d width = %d\n", gmask, gshift, gwidth); */
   297 /*             printf("blue  mask = %4x shift = %4d width = %d\n", bmask, bshift, bwidth); */
   298 
   299             /* build the color table pixel values */
   300 	    pix = 0;
   301 	    for (r = 0; r < rmax; r++) {
   302 	      for (g = 0; g < gmax; g++) {
   303 		for (b = 0; b < bmax; b++) {
   304 		  colorcells[pix].pixel = (r << rshift) | (g << gshift) | (b << bshift);
   305 		  colorcells[pix].red   = (0xffff * r) / rmask;
   306 		  colorcells[pix].green = (0xffff * g) / gmask;
   307 		  colorcells[pix].blue  = (0xffff * b) / bmask;
   308 /* 		  printf("%4x:%4x [%4x %4x %4x]\n",  */
   309 /* 			 pix,  */
   310 /* 			 colorcells[pix].pixel, */
   311 /* 			 colorcells[pix].red, */
   312 /* 			 colorcells[pix].green, */
   313 /* 			 colorcells[pix].blue); */
   314 		  pix++;
   315 		}
   316 	      }
   317 	    }
   318 
   319 /*             status = */
   320 /*                 XStoreColors(data->display, colormap, colorcells, ncolors); */
   321 
   322             xattr.colormap = colormap;
   323             X11_TrackColormap(data->display, displaydata->screen,
   324                               colormap, visual, NULL);
   325 
   326             SDL_free(colorcells);
   327         }
   328     } else if (visual->class == DirectColor) {
   329         Status status;
   330         XStandardColormap cmap;
   331         XColor *colorcells;
   332         Colormap colormap;
   333         int i;
   334         int ncolors;
   335         int rmax, gmax, bmax;
   336         int rmask, gmask, bmask;
   337         int rshift, gshift, bshift;
   338 
   339         /* Is the colormap we need already registered in SDL? */
   340         if (colormap =
   341             X11_LookupColormap(data->display,
   342                                displaydata->screen, visual->visualid)) {
   343             xattr.colormap = colormap;
   344 /*             printf("found existing colormap\n"); */
   345         } else {
   346             /* The colormap is not known to SDL so we will create it */
   347             colormap = XCreateColormap(data->display,
   348                                        RootWindow(data->display,
   349                                                   displaydata->screen),
   350                                        visual, AllocAll);
   351 /*             printf("colormap = %x\n", colormap); */
   352 
   353             /* If we can't create a colormap, then we must die */
   354             if (!colormap) {
   355                 SDL_SetError
   356                     ("Couldn't create window: Could not create writable colormap");
   357                 return -1;
   358             }
   359 
   360             /* OK, we got a colormap, now fill it in as best as we can */
   361 
   362             colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
   363             if (NULL == colorcells) {
   364                 SDL_SetError("out of memory in X11_CreateWindow");
   365                 return -1;
   366             }
   367             ncolors = visual->map_entries;
   368             rmax = 0xffff;
   369             gmax = 0xffff;
   370             bmax = 0xffff;
   371 
   372             rshift = 0;
   373             rmask = visual->red_mask;
   374             while (0 == (rmask & 1)) {
   375                 rshift++;
   376                 rmask >>= 1;
   377             }
   378 
   379 /*             printf("rmask = %4x rshift = %4d\n", rmask, rshift); */
   380 
   381             gshift = 0;
   382             gmask = visual->green_mask;
   383             while (0 == (gmask & 1)) {
   384                 gshift++;
   385                 gmask >>= 1;
   386             }
   387 
   388 /*             printf("gmask = %4x gshift = %4d\n", gmask, gshift); */
   389 
   390             bshift = 0;
   391             bmask = visual->blue_mask;
   392             while (0 == (bmask & 1)) {
   393                 bshift++;
   394                 bmask >>= 1;
   395             }
   396 
   397 /*             printf("bmask = %4x bshift = %4d\n", bmask, bshift); */
   398 
   399             /* build the color table pixel values */
   400             for (i = 0; i < ncolors; i++) {
   401                 Uint32 red = (rmax * i) / (ncolors - 1);
   402                 Uint32 green = (gmax * i) / (ncolors - 1);
   403                 Uint32 blue = (bmax * i) / (ncolors - 1);
   404 
   405                 Uint32 rbits = (rmask * i) / (ncolors - 1);
   406                 Uint32 gbits = (gmask * i) / (ncolors - 1);
   407                 Uint32 bbits = (bmask * i) / (ncolors - 1);
   408 
   409                 Uint32 pix =
   410                     (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
   411 
   412                 colorcells[i].pixel = pix;
   413 
   414                 colorcells[i].red = red;
   415                 colorcells[i].green = green;
   416                 colorcells[i].blue = blue;
   417 
   418                 colorcells[i].flags = DoRed | DoGreen | DoBlue;
   419 /* 		printf("%2d:%4x [%4x %4x %4x]\n", i, pix, red, green, blue); */
   420             }
   421 
   422             status =
   423                 XStoreColors(data->display, colormap, colorcells, ncolors);
   424 
   425             xattr.colormap = colormap;
   426             X11_TrackColormap(data->display, displaydata->screen,
   427                               colormap, visual, colorcells);
   428 
   429             SDL_free(colorcells);
   430         }
   431     } else {
   432         xattr.colormap =
   433             XCreateColormap(data->display,
   434                             RootWindow(data->display, displaydata->screen),
   435                             visual, AllocNone);
   436     }
   437 
   438     if ((window->flags & SDL_WINDOW_FULLSCREEN)
   439         || window->x == SDL_WINDOWPOS_CENTERED) {
   440         X11_GetDisplaySize(_this, window, &x, NULL);
   441         x = (x - window->w) / 2;
   442     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   443         x = 0;
   444     } else {
   445         x = window->x;
   446     }
   447     if ((window->flags & SDL_WINDOW_FULLSCREEN)
   448         || window->y == SDL_WINDOWPOS_CENTERED) {
   449         X11_GetDisplaySize(_this, window, NULL, &y);
   450         y = (y - window->h) / 2;
   451     } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   452         y = 0;
   453     } else {
   454         y = window->y;
   455     }
   456 
   457     w = XCreateWindow(data->display,
   458                       RootWindow(data->display, displaydata->screen), x, y,
   459                       window->w, window->h, 0, depth, InputOutput, visual,
   460                       (CWOverrideRedirect | CWBackPixel | CWBorderPixel |
   461                        CWColormap), &xattr);
   462     if (!w) {
   463 #ifdef SDL_VIDEO_OPENGL_GLX
   464         if (window->flags & SDL_WINDOW_OPENGL) {
   465             X11_GL_Shutdown(_this);
   466         }
   467 #endif
   468         SDL_SetError("Couldn't create window");
   469         return -1;
   470     }
   471 
   472     sizehints = XAllocSizeHints();
   473     if (sizehints) {
   474         if ((window->flags & SDL_WINDOW_RESIZABLE)
   475             && !(window->flags & SDL_WINDOW_FULLSCREEN)) {
   476             sizehints->min_width = 32;
   477             sizehints->min_height = 32;
   478             sizehints->max_height = 4096;
   479             sizehints->max_width = 4096;
   480         } else {
   481             sizehints->min_width = sizehints->max_width = window->w;
   482             sizehints->min_height = sizehints->max_height = window->h;
   483         }
   484         sizehints->flags = PMaxSize | PMinSize;
   485         if (!(window->flags & SDL_WINDOW_FULLSCREEN)
   486             && window->x != SDL_WINDOWPOS_UNDEFINED
   487             && window->y != SDL_WINDOWPOS_UNDEFINED) {
   488             sizehints->x = x;
   489             sizehints->y = y;
   490             sizehints->flags |= USPosition;
   491         }
   492         XSetWMNormalHints(data->display, w, sizehints);
   493         XFree(sizehints);
   494     }
   495 
   496     if (window->flags & (SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN)) {
   497         SDL_bool set;
   498         Atom WM_HINTS;
   499 
   500         /* We haven't modified the window manager hints yet */
   501         set = SDL_FALSE;
   502 
   503         /* First try to set MWM hints */
   504         WM_HINTS = XInternAtom(data->display, "_MOTIF_WM_HINTS", True);
   505         if (WM_HINTS != None) {
   506             /* Hints used by Motif compliant window managers */
   507             struct
   508             {
   509                 unsigned long flags;
   510                 unsigned long functions;
   511                 unsigned long decorations;
   512                 long input_mode;
   513                 unsigned long status;
   514             } MWMHints = {
   515             (1L << 1), 0, 0, 0, 0};
   516 
   517             XChangeProperty(data->display, w, WM_HINTS, WM_HINTS, 32,
   518                             PropModeReplace, (unsigned char *) &MWMHints,
   519                             sizeof(MWMHints) / sizeof(long));
   520             set = SDL_TRUE;
   521         }
   522         /* Now try to set KWM hints */
   523         WM_HINTS = XInternAtom(data->display, "KWM_WIN_DECORATION", True);
   524         if (WM_HINTS != None) {
   525             long KWMHints = 0;
   526 
   527             XChangeProperty(data->display, w,
   528                             WM_HINTS, WM_HINTS, 32,
   529                             PropModeReplace,
   530                             (unsigned char *) &KWMHints,
   531                             sizeof(KWMHints) / sizeof(long));
   532             set = SDL_TRUE;
   533         }
   534         /* Now try to set GNOME hints */
   535         WM_HINTS = XInternAtom(data->display, "_WIN_HINTS", True);
   536         if (WM_HINTS != None) {
   537             long GNOMEHints = 0;
   538 
   539             XChangeProperty(data->display, w,
   540                             WM_HINTS, WM_HINTS, 32,
   541                             PropModeReplace,
   542                             (unsigned char *) &GNOMEHints,
   543                             sizeof(GNOMEHints) / sizeof(long));
   544             set = SDL_TRUE;
   545         }
   546         /* Finally set the transient hints if necessary */
   547         if (!set) {
   548             XSetTransientForHint(data->display, w,
   549                                  RootWindow(data->display,
   550                                             displaydata->screen));
   551         }
   552     } else {
   553         SDL_bool set;
   554         Atom WM_HINTS;
   555 
   556         /* We haven't modified the window manager hints yet */
   557         set = SDL_FALSE;
   558 
   559         /* First try to unset MWM hints */
   560         WM_HINTS = XInternAtom(data->display, "_MOTIF_WM_HINTS", True);
   561         if (WM_HINTS != None) {
   562             XDeleteProperty(data->display, w, WM_HINTS);
   563             set = SDL_TRUE;
   564         }
   565         /* Now try to unset KWM hints */
   566         WM_HINTS = XInternAtom(data->display, "KWM_WIN_DECORATION", True);
   567         if (WM_HINTS != None) {
   568             XDeleteProperty(data->display, w, WM_HINTS);
   569             set = SDL_TRUE;
   570         }
   571         /* Now try to unset GNOME hints */
   572         WM_HINTS = XInternAtom(data->display, "_WIN_HINTS", True);
   573         if (WM_HINTS != None) {
   574             XDeleteProperty(data->display, w, WM_HINTS);
   575             set = SDL_TRUE;
   576         }
   577         /* Finally unset the transient hints if necessary */
   578         if (!set) {
   579             /* NOTE: Does this work? */
   580             XSetTransientForHint(data->display, w, None);
   581         }
   582     }
   583 
   584     /* Tell KDE to keep fullscreen windows on top */
   585     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   586         XEvent ev;
   587         long mask;
   588 
   589         SDL_zero(ev);
   590         ev.xclient.type = ClientMessage;
   591         ev.xclient.window = RootWindow(data->display, displaydata->screen);
   592         ev.xclient.message_type =
   593             XInternAtom(data->display, "KWM_KEEP_ON_TOP", False);
   594         ev.xclient.format = 32;
   595         ev.xclient.data.l[0] = w;
   596         ev.xclient.data.l[1] = CurrentTime;
   597         XSendEvent(data->display,
   598                    RootWindow(data->display, displaydata->screen), False,
   599                    SubstructureRedirectMask, &ev);
   600     }
   601 
   602     /* Set the input hints so we get keyboard input */
   603     wmhints = XAllocWMHints();
   604     if (wmhints) {
   605         wmhints->input = True;
   606         wmhints->flags = InputHint;
   607         XSetWMHints(data->display, w, wmhints);
   608         XFree(wmhints);
   609     }
   610 
   611     /* Set the class hints so we can get an icon (AfterStep) */
   612     classhints = XAllocClassHint();
   613     if (classhints != NULL) {
   614         classhints->res_name = data->classname;
   615         classhints->res_class = data->classname;
   616         XSetClassHint(data->display, w, classhints);
   617         XFree(classhints);
   618     }
   619 
   620     /* Allow the window to be deleted by the window manager */
   621     XSetWMProtocols(data->display, w, &data->WM_DELETE_WINDOW, 1);
   622 
   623     if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {
   624 #ifdef SDL_VIDEO_OPENGL_GLX
   625         if (window->flags & SDL_WINDOW_OPENGL) {
   626             X11_GL_Shutdown(_this);
   627         }
   628 #endif
   629         XDestroyWindow(data->display, w);
   630         return -1;
   631     }
   632 #ifdef X_HAVE_UTF8_STRING
   633     {
   634         Uint32 fevent = 0;
   635         pXGetICValues(((SDL_WindowData *) window->driverdata)->ic,
   636                       XNFilterEvents, &fevent, NULL);
   637         XSelectInput(data->display, w,
   638                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   639                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   640                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   641                       PropertyChangeMask | StructureNotifyMask |
   642                       KeymapStateMask | fevent));
   643     }
   644 #else
   645     {
   646         XSelectInput(data->display, w,
   647                      (FocusChangeMask | EnterWindowMask | LeaveWindowMask |
   648                       ExposureMask | ButtonPressMask | ButtonReleaseMask |
   649                       PointerMotionMask | KeyPressMask | KeyReleaseMask |
   650                       PropertyChangeMask | StructureNotifyMask |
   651                       KeymapStateMask));
   652     }
   653 #endif
   654 
   655 #if SDL_VIDEO_DRIVER_X11_XINPUT
   656     /* we're informing the display what extension events we want to receive from it */
   657     {
   658         int i, j, n = 0;
   659         XEventClass xevents[256];
   660 
   661         for (i = 0; i < SDL_GetNumMice(); ++i) {
   662             SDL_Mouse *mouse;
   663             X11_MouseData *data;
   664 
   665             mouse = SDL_GetMouse(i);
   666             data = (X11_MouseData *) mouse->driverdata;
   667             if (!data) {
   668                 continue;
   669             }
   670 
   671             for (j = 0; j < data->num_xevents; ++j) {
   672                 xevents[n++] = data->xevents[j];
   673             }
   674         }
   675         if (n > 0) {
   676             XSelectExtensionEvent(data->display, w, xevents, n);
   677         }
   678     }
   679 #endif
   680 
   681     return 0;
   682 }
   683 
   684 int
   685 X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   686 {
   687     Window w = (Window) data;
   688 
   689     /* FIXME: Query the title from the existing window */
   690 
   691     if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) {
   692         return -1;
   693     }
   694     return 0;
   695 }
   696 
   697 void
   698 X11_SetWindowTitle(_THIS, SDL_Window * window)
   699 {
   700     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   701     Display *display = data->videodata->display;
   702     XTextProperty titleprop, iconprop;
   703     Status status;
   704     const char *title = window->title;
   705     const char *icon = NULL;
   706 
   707 #ifdef X_HAVE_UTF8_STRING
   708     Atom _NET_WM_NAME = 0;
   709     Atom _NET_WM_ICON_NAME = 0;
   710 
   711     /* Look up some useful Atoms */
   712     if (SDL_X11_HAVE_UTF8) {
   713         _NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", False);
   714         _NET_WM_ICON_NAME = XInternAtom(display, "_NET_WM_ICON_NAME", False);
   715     }
   716 #endif
   717 
   718     if (title != NULL) {
   719         char *title_locale = SDL_iconv_utf8_locale(title);
   720         if (!title_locale) {
   721             SDL_OutOfMemory();
   722             return;
   723         }
   724         status = XStringListToTextProperty(&title_locale, 1, &titleprop);
   725         SDL_free(title_locale);
   726         if (status) {
   727             XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME);
   728             XFree(titleprop.value);
   729         }
   730 #ifdef X_HAVE_UTF8_STRING
   731         if (SDL_X11_HAVE_UTF8) {
   732             status =
   733                 Xutf8TextListToTextProperty(display, (char **) &title, 1,
   734                                             XUTF8StringStyle, &titleprop);
   735             if (status == Success) {
   736                 XSetTextProperty(display, data->window, &titleprop,
   737                                  _NET_WM_NAME);
   738                 XFree(titleprop.value);
   739             }
   740         }
   741 #endif
   742     }
   743     if (icon != NULL) {
   744         char *icon_locale = SDL_iconv_utf8_locale(icon);
   745         if (!icon_locale) {
   746             SDL_OutOfMemory();
   747             return;
   748         }
   749         status = XStringListToTextProperty(&icon_locale, 1, &iconprop);
   750         SDL_free(icon_locale);
   751         if (status) {
   752             XSetTextProperty(display, data->window, &iconprop,
   753                              XA_WM_ICON_NAME);
   754             XFree(iconprop.value);
   755         }
   756 #ifdef X_HAVE_UTF8_STRING
   757         if (SDL_X11_HAVE_UTF8) {
   758             status =
   759                 Xutf8TextListToTextProperty(display, (char **) &icon, 1,
   760                                             XUTF8StringStyle, &iconprop);
   761             if (status == Success) {
   762                 XSetTextProperty(display, data->window, &iconprop,
   763                                  _NET_WM_ICON_NAME);
   764                 XFree(iconprop.value);
   765             }
   766         }
   767 #endif
   768     }
   769 }
   770 
   771 void
   772 X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   773 {
   774     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   775     Display *display = data->videodata->display;
   776     Atom _NET_WM_ICON = XInternAtom(display, "_NET_WM_ICON", False);
   777 
   778     if (icon) {
   779         SDL_PixelFormat format;
   780         SDL_Surface *surface;
   781         int propsize;
   782         Uint32 *propdata;
   783 
   784         /* Convert the icon to ARGB for modern window managers */
   785         SDL_InitFormat(&format, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   786                        0xFF000000);
   787         surface = SDL_ConvertSurface(icon, &format, 0);
   788         if (!surface) {
   789             return;
   790         }
   791 
   792         /* Set the _NET_WM_ICON property */
   793         propsize = 2 + (icon->w * icon->h);
   794         propdata = SDL_malloc(propsize * sizeof(Uint32));
   795         if (propdata) {
   796             propdata[0] = icon->w;
   797             propdata[1] = icon->h;
   798             SDL_memcpy(&propdata[2], surface->pixels,
   799                        surface->h * surface->pitch);
   800             XChangeProperty(display, data->window, _NET_WM_ICON, XA_CARDINAL,
   801                             32, PropModeReplace, (unsigned char *) propdata,
   802                             propsize);
   803         }
   804         SDL_FreeSurface(surface);
   805     } else {
   806         XDeleteProperty(display, data->window, _NET_WM_ICON);
   807     }
   808 }
   809 
   810 void
   811 X11_SetWindowPosition(_THIS, SDL_Window * window)
   812 {
   813     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   814     SDL_DisplayData *displaydata =
   815         (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
   816     Display *display = data->videodata->display;
   817     int x, y;
   818 
   819     if ((window->flags & SDL_WINDOW_FULLSCREEN)
   820         || window->x == SDL_WINDOWPOS_CENTERED) {
   821         X11_GetDisplaySize(_this, window, &x, NULL);
   822         x = (x - window->w) / 2;
   823     } else {
   824         x = window->x;
   825     }
   826     if ((window->flags & SDL_WINDOW_FULLSCREEN)
   827         || window->y == SDL_WINDOWPOS_CENTERED) {
   828         X11_GetDisplaySize(_this, window, NULL, &y);
   829         y = (y - window->h) / 2;
   830     } else {
   831         y = window->y;
   832     }
   833     XMoveWindow(display, data->window, x, y);
   834 }
   835 
   836 void
   837 X11_SetWindowSize(_THIS, SDL_Window * window)
   838 {
   839     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   840     Display *display = data->videodata->display;
   841 
   842     XResizeWindow(display, data->window, window->w, window->h);
   843 }
   844 
   845 void
   846 X11_ShowWindow(_THIS, SDL_Window * window)
   847 {
   848     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   849     Display *display = data->videodata->display;
   850 
   851     XMapRaised(display, data->window);
   852 }
   853 
   854 void
   855 X11_HideWindow(_THIS, SDL_Window * window)
   856 {
   857     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   858     Display *display = data->videodata->display;
   859 
   860     XUnmapWindow(display, data->window);
   861 }
   862 
   863 void
   864 X11_RaiseWindow(_THIS, SDL_Window * window)
   865 {
   866     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   867     Display *display = data->videodata->display;
   868 
   869     XRaiseWindow(display, data->window);
   870 }
   871 
   872 void
   873 X11_MaximizeWindow(_THIS, SDL_Window * window)
   874 {
   875     /* FIXME: is this even possible? */
   876 }
   877 
   878 void
   879 X11_MinimizeWindow(_THIS, SDL_Window * window)
   880 {
   881     X11_HideWindow(_this, window);
   882 }
   883 
   884 void
   885 X11_RestoreWindow(_THIS, SDL_Window * window)
   886 {
   887     X11_ShowWindow(_this, window);
   888 }
   889 
   890 void
   891 X11_SetWindowGrab(_THIS, SDL_Window * window)
   892 {
   893     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   894     Display *display = data->videodata->display;
   895 
   896     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
   897         && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   898         /* Try to grab the mouse */
   899         for (;;) {
   900             int result =
   901                 XGrabPointer(display, data->window, True, 0, GrabModeAsync,
   902                              GrabModeAsync, data->window, None, CurrentTime);
   903             if (result == GrabSuccess) {
   904                 break;
   905             }
   906             SDL_Delay(100);
   907         }
   908 
   909         /* Raise the window if we grab the mouse */
   910         XRaiseWindow(display, data->window);
   911 
   912         /* Now grab the keyboard */
   913         XGrabKeyboard(display, data->window, True, GrabModeAsync,
   914                       GrabModeAsync, CurrentTime);
   915     } else {
   916         XUngrabPointer(display, CurrentTime);
   917         XUngrabKeyboard(display, CurrentTime);
   918     }
   919 }
   920 
   921 void
   922 X11_DestroyWindow(_THIS, SDL_Window * window)
   923 {
   924     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   925     window->driverdata = NULL;
   926 
   927     if (data) {
   928         SDL_VideoData *videodata = (SDL_VideoData *) data->videodata;
   929         Display *display = videodata->display;
   930         int numwindows = videodata->numwindows;
   931         SDL_WindowData **windowlist = videodata->windowlist;
   932         int i;
   933 
   934         if (windowlist) {
   935             for (i = 0; i < numwindows; ++i) {
   936                 if (windowlist[i] && (windowlist[i]->windowID == window->id)) {
   937                     windowlist[i] = windowlist[numwindows - 1];
   938                     windowlist[numwindows - 1] = NULL;
   939                     videodata->numwindows--;
   940                     break;
   941                 }
   942             }
   943         }
   944 #ifdef SDL_VIDEO_OPENGL_GLX
   945         if (window->flags & SDL_WINDOW_OPENGL) {
   946             X11_GL_Shutdown(_this);
   947         }
   948 #endif
   949 #ifdef X_HAVE_UTF8_STRING
   950         if (data->ic) {
   951             XDestroyIC(data->ic);
   952         }
   953 #endif
   954         if (data->created) {
   955             XDestroyWindow(display, data->window);
   956         }
   957         SDL_free(data);
   958     }
   959 }
   960 
   961 SDL_bool
   962 X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   963 {
   964     if (info->version.major <= SDL_MAJOR_VERSION) {
   965         /* FIXME! */
   966         return SDL_TRUE;
   967     } else {
   968         SDL_SetError("Application not compiled with SDL %d.%d\n",
   969                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   970         return SDL_FALSE;
   971     }
   972 }
   973 
   974 /* vi: set ts=4 sw=4 expandtab: */