src/video/x11/SDL_x11video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1690 43ba677b4f62
permissions -rw-r--r--
more tweaking indent options
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* X11 based SDL video driver implementation.
slouken@0
    25
   Note:  This implementation does not currently need X11 thread locking,
slouken@0
    26
          since the event thread uses a separate X connection and any
slouken@0
    27
          additional locking necessary is handled internally.  However,
slouken@0
    28
          if full locking is neccessary, take a look at XInitThreads().
slouken@0
    29
*/
slouken@0
    30
slouken@0
    31
#include <unistd.h>
slouken@0
    32
#include <sys/ioctl.h>
slouken@0
    33
#ifdef MTRR_SUPPORT
slouken@0
    34
#include <asm/mtrr.h>
slouken@0
    35
#include <sys/fcntl.h>
slouken@0
    36
#endif
slouken@0
    37
slouken@1358
    38
#include "SDL_endian.h"
slouken@0
    39
#include "SDL_timer.h"
slouken@0
    40
#include "SDL_thread.h"
slouken@0
    41
#include "SDL_video.h"
slouken@0
    42
#include "SDL_mouse.h"
slouken@1361
    43
#include "../SDL_sysvideo.h"
slouken@1361
    44
#include "../SDL_pixels_c.h"
slouken@1361
    45
#include "../../events/SDL_events_c.h"
slouken@0
    46
#include "SDL_x11video.h"
slouken@0
    47
#include "SDL_x11wm_c.h"
slouken@0
    48
#include "SDL_x11mouse_c.h"
slouken@0
    49
#include "SDL_x11events_c.h"
slouken@0
    50
#include "SDL_x11modes_c.h"
slouken@0
    51
#include "SDL_x11image_c.h"
slouken@0
    52
#include "SDL_x11yuv_c.h"
slouken@0
    53
#include "SDL_x11gl_c.h"
slouken@0
    54
#include "SDL_x11gamma_c.h"
slouken@1361
    55
#include "../blank_cursor.h"
slouken@0
    56
slouken@0
    57
/* Initialization/Query functions */
slouken@1668
    58
static int X11_VideoInit(_THIS);
slouken@1668
    59
static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface * current,
slouken@1668
    60
                                     const SDL_DisplayMode * mode,
slouken@1668
    61
                                     Uint32 flags);
slouken@1668
    62
static int X11_ToggleFullScreen(_THIS, int on);
slouken@1668
    63
static void X11_UpdateMouse(_THIS);
slouken@1668
    64
static int X11_SetColors(_THIS, int firstcolor, int ncolors,
slouken@1668
    65
                         SDL_Color * colors);
slouken@1668
    66
static int X11_SetGammaRamp(_THIS, Uint16 * ramp);
slouken@1668
    67
static void X11_VideoQuit(_THIS);
slouken@0
    68
icculus@1168
    69
slouken@0
    70
/* X11 driver bootstrap functions */
slouken@0
    71
slouken@1662
    72
static int
slouken@1668
    73
X11_Available(void)
slouken@0
    74
{
slouken@1662
    75
    Display *display = NULL;
slouken@1668
    76
    if (SDL_X11_LoadSymbols()) {
slouken@1668
    77
        display = XOpenDisplay(NULL);
slouken@1662
    78
        if (display != NULL) {
slouken@1668
    79
            XCloseDisplay(display);
slouken@1662
    80
        }
slouken@1668
    81
        SDL_X11_UnloadSymbols();
slouken@1662
    82
    }
slouken@1662
    83
    return (display != NULL);
slouken@0
    84
}
slouken@0
    85
slouken@1662
    86
static void
slouken@1668
    87
X11_DeleteDevice(SDL_VideoDevice * device)
slouken@0
    88
{
slouken@1662
    89
    if (device) {
slouken@1662
    90
        if (device->hidden) {
slouken@1668
    91
            SDL_free(device->hidden);
slouken@1662
    92
        }
slouken@1662
    93
        if (device->gl_data) {
slouken@1668
    94
            SDL_free(device->gl_data);
slouken@1662
    95
        }
slouken@1668
    96
        SDL_free(device);
slouken@1668
    97
        SDL_X11_UnloadSymbols();
slouken@1662
    98
    }
slouken@0
    99
}
slouken@0
   100
slouken@1662
   101
static SDL_VideoDevice *
slouken@1668
   102
X11_CreateDevice(int devindex)
slouken@0
   103
{
slouken@1662
   104
    SDL_VideoDevice *device = NULL;
slouken@0
   105
slouken@1668
   106
    if (SDL_X11_LoadSymbols()) {
slouken@1662
   107
        /* Initialize all variables that we clean on shutdown */
slouken@1668
   108
        device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
slouken@1662
   109
        if (device) {
slouken@1668
   110
            SDL_memset(device, 0, (sizeof *device));
slouken@1662
   111
            device->hidden = (struct SDL_PrivateVideoData *)
slouken@1668
   112
                SDL_malloc((sizeof *device->hidden));
slouken@1662
   113
            device->gl_data = (struct SDL_PrivateGLData *)
slouken@1668
   114
                SDL_malloc((sizeof *device->gl_data));
slouken@1662
   115
        }
slouken@1662
   116
        if ((device == NULL) || (device->hidden == NULL) ||
slouken@1662
   117
            (device->gl_data == NULL)) {
slouken@1668
   118
            SDL_OutOfMemory();
slouken@1668
   119
            X11_DeleteDevice(device);   /* calls SDL_X11_UnloadSymbols(). */
slouken@1662
   120
            return (0);
slouken@1662
   121
        }
slouken@1668
   122
        SDL_memset(device->hidden, 0, (sizeof *device->hidden));
slouken@1668
   123
        SDL_memset(device->gl_data, 0, (sizeof *device->gl_data));
icculus@1168
   124
slouken@1662
   125
        /* Set the driver flags */
slouken@1662
   126
        device->handles_any_size = 1;
icculus@1168
   127
slouken@1662
   128
        /* Set the function pointers */
slouken@1662
   129
        device->VideoInit = X11_VideoInit;
slouken@1662
   130
        device->SetVideoMode = X11_SetVideoMode;
slouken@1662
   131
        device->ToggleFullScreen = X11_ToggleFullScreen;
slouken@1662
   132
        device->UpdateMouse = X11_UpdateMouse;
slouken@1361
   133
#if SDL_VIDEO_DRIVER_X11_XV
slouken@1662
   134
        device->CreateYUVOverlay = X11_CreateYUVOverlay;
icculus@1168
   135
#endif
slouken@1662
   136
        device->SetColors = X11_SetColors;
slouken@1662
   137
        device->UpdateRects = NULL;
slouken@1662
   138
        device->VideoQuit = X11_VideoQuit;
slouken@1662
   139
        device->AllocHWSurface = X11_AllocHWSurface;
slouken@1662
   140
        device->CheckHWBlit = NULL;
slouken@1662
   141
        device->FillHWRect = NULL;
slouken@1662
   142
        device->SetHWColorKey = NULL;
slouken@1662
   143
        device->SetHWAlpha = NULL;
slouken@1662
   144
        device->LockHWSurface = X11_LockHWSurface;
slouken@1662
   145
        device->UnlockHWSurface = X11_UnlockHWSurface;
slouken@1662
   146
        device->FlipHWSurface = X11_FlipHWSurface;
slouken@1662
   147
        device->FreeHWSurface = X11_FreeHWSurface;
slouken@1662
   148
        device->SetGamma = X11_SetVidModeGamma;
slouken@1662
   149
        device->GetGamma = X11_GetVidModeGamma;
slouken@1662
   150
        device->SetGammaRamp = X11_SetGammaRamp;
slouken@1662
   151
        device->GetGammaRamp = NULL;
slouken@1361
   152
#if SDL_VIDEO_OPENGL_GLX
slouken@1662
   153
        device->GL_LoadLibrary = X11_GL_LoadLibrary;
slouken@1662
   154
        device->GL_GetProcAddress = X11_GL_GetProcAddress;
slouken@1662
   155
        device->GL_GetAttribute = X11_GL_GetAttribute;
slouken@1662
   156
        device->GL_MakeCurrent = X11_GL_MakeCurrent;
slouken@1662
   157
        device->GL_SwapBuffers = X11_GL_SwapBuffers;
icculus@1168
   158
#endif
slouken@1662
   159
        device->SetCaption = X11_SetCaption;
slouken@1662
   160
        device->SetIcon = X11_SetIcon;
slouken@1662
   161
        device->IconifyWindow = X11_IconifyWindow;
slouken@1662
   162
        device->GrabInput = X11_GrabInput;
slouken@1662
   163
        device->GetWMInfo = X11_GetWMInfo;
slouken@1662
   164
        device->FreeWMCursor = X11_FreeWMCursor;
slouken@1662
   165
        device->CreateWMCursor = X11_CreateWMCursor;
slouken@1662
   166
        device->ShowWMCursor = X11_ShowWMCursor;
slouken@1662
   167
        device->WarpWMCursor = X11_WarpWMCursor;
slouken@1662
   168
        device->CheckMouseMode = X11_CheckMouseMode;
slouken@1662
   169
        device->InitOSKeymap = X11_InitOSKeymap;
slouken@1662
   170
        device->PumpEvents = X11_PumpEvents;
icculus@1168
   171
slouken@1662
   172
        device->free = X11_DeleteDevice;
slouken@1662
   173
    }
slouken@0
   174
slouken@1662
   175
    return device;
slouken@0
   176
}
slouken@0
   177
slouken@0
   178
VideoBootStrap X11_bootstrap = {
slouken@1662
   179
    "x11", "X Window System",
slouken@1662
   180
    X11_Available, X11_CreateDevice
slouken@0
   181
};
slouken@0
   182
slouken@0
   183
/* Normal X11 error handler routine */
slouken@1662
   184
static int (*X_handler) (Display *, XErrorEvent *) = NULL;
slouken@1662
   185
static int
slouken@1668
   186
x_errhandler(Display * d, XErrorEvent * e)
slouken@0
   187
{
slouken@1361
   188
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@1662
   189
    extern int vm_error;
slouken@0
   190
#endif
slouken@1361
   191
#if SDL_VIDEO_DRIVER_X11_DGAMOUSE
slouken@1662
   192
    extern int dga_error;
slouken@0
   193
#endif
slouken@0
   194
slouken@1361
   195
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@1662
   196
    /* VidMode errors are non-fatal. :) */
slouken@1662
   197
    /* Are the errors offset by one from the error base?
slouken@1662
   198
       e.g. the error base is 143, the code is 148, and the
slouken@1662
   199
       actual error is XF86VidModeExtensionDisabled (4) ?
slouken@1662
   200
     */
slouken@1662
   201
    if ((vm_error >= 0) &&
slouken@1662
   202
        (((e->error_code == BadRequest) && (e->request_code == vm_error)) ||
slouken@1662
   203
         ((e->error_code > vm_error) &&
slouken@1662
   204
          (e->error_code <= (vm_error + XF86VidModeNumberErrors))))) {
slouken@1659
   205
#ifdef X11_DEBUG
slouken@1662
   206
        {
slouken@1662
   207
            char errmsg[1024];
slouken@1668
   208
            XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
slouken@1668
   209
            printf("VidMode error: %s\n", errmsg);
slouken@1662
   210
        }
slouken@0
   211
#endif
slouken@1662
   212
        return (0);
slouken@1662
   213
    }
slouken@1361
   214
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@0
   215
slouken@1361
   216
#if SDL_VIDEO_DRIVER_X11_DGAMOUSE
slouken@1662
   217
    /* DGA errors can be non-fatal. :) */
slouken@1662
   218
    if ((dga_error >= 0) &&
slouken@1662
   219
        ((e->error_code > dga_error) &&
slouken@1662
   220
         (e->error_code <= (dga_error + XF86DGANumberErrors)))) {
slouken@1659
   221
#ifdef X11_DEBUG
slouken@1662
   222
        {
slouken@1662
   223
            char errmsg[1024];
slouken@1668
   224
            XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
slouken@1668
   225
            printf("DGA error: %s\n", errmsg);
slouken@1662
   226
        }
slouken@0
   227
#endif
slouken@1662
   228
        return (0);
slouken@1662
   229
    }
slouken@1361
   230
#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */
slouken@0
   231
slouken@1668
   232
    return (X_handler(d, e));
slouken@0
   233
}
slouken@0
   234
slouken@0
   235
/* X11 I/O error handler routine */
slouken@1662
   236
static int (*XIO_handler) (Display *) = NULL;
slouken@1662
   237
static int
slouken@1668
   238
xio_errhandler(Display * d)
slouken@0
   239
{
slouken@1662
   240
    /* Ack!  Lost X11 connection! */
slouken@0
   241
slouken@1662
   242
    /* We will crash if we try to clean up our display */
slouken@1662
   243
    if (current_video->hidden->Ximage) {
slouken@1662
   244
        SDL_VideoSurface->pixels = NULL;
slouken@1662
   245
    }
slouken@1662
   246
    current_video->hidden->X11_Display = NULL;
slouken@0
   247
slouken@1662
   248
    /* Continue with the standard X11 error handler */
slouken@1668
   249
    return (XIO_handler(d));
slouken@0
   250
}
slouken@0
   251
slouken@1662
   252
static int (*Xext_handler) (Display *, _Xconst char *, _Xconst char *) = NULL;
slouken@1662
   253
static int
slouken@1668
   254
xext_errhandler(Display * d, _Xconst char *ext, _Xconst char *reason)
icculus@1248
   255
{
slouken@1659
   256
#ifdef X11_DEBUG
slouken@1668
   257
    printf("Xext error inside SDL (may be harmless):\n");
slouken@1668
   258
    printf("  Extension \"%s\" %s on display \"%s\".\n",
slouken@1668
   259
           ext, reason, XDisplayString(d));
icculus@1248
   260
#endif
icculus@1248
   261
slouken@1668
   262
    if (SDL_strcmp(reason, "missing") == 0) {
slouken@1662
   263
        /*
slouken@1662
   264
         * Since the query itself, elsewhere, can handle a missing extension
slouken@1662
   265
         *  and the default behaviour in Xlib is to write to stderr, which
slouken@1662
   266
         *  generates unnecessary bug reports, we just ignore these.
slouken@1662
   267
         */
slouken@1662
   268
        return 0;
slouken@1662
   269
    }
icculus@1248
   270
slouken@1662
   271
    /* Everything else goes to the default handler... */
slouken@1668
   272
    return Xext_handler(d, ext, reason);
icculus@1248
   273
}
icculus@1248
   274
slouken@1325
   275
/* Find out what class name we should use */
slouken@1662
   276
static char *
slouken@1668
   277
get_classname(char *classname, int maxlen)
slouken@1325
   278
{
slouken@1662
   279
    char *spot;
slouken@1402
   280
#if defined(__LINUX__) || defined(__FREEBSD__)
slouken@1662
   281
    char procfile[1024];
slouken@1662
   282
    char linkfile[1024];
slouken@1662
   283
    int linksize;
slouken@1325
   284
#endif
slouken@1325
   285
slouken@1662
   286
    /* First allow environment variable override */
slouken@1668
   287
    spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
slouken@1662
   288
    if (spot) {
slouken@1668
   289
        SDL_strlcpy(classname, spot, maxlen);
slouken@1662
   290
        return classname;
slouken@1662
   291
    }
slouken@1325
   292
slouken@1662
   293
    /* Next look at the application's executable name */
slouken@1402
   294
#if defined(__LINUX__) || defined(__FREEBSD__)
slouken@1402
   295
#if defined(__LINUX__)
slouken@1668
   296
    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
slouken@1402
   297
#elif defined(__FREEBSD__)
slouken@1668
   298
    SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
slouken@1668
   299
                 getpid());
slouken@1325
   300
#else
slouken@1325
   301
#error Where can we find the executable name?
slouken@1325
   302
#endif
slouken@1668
   303
    linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
slouken@1662
   304
    if (linksize > 0) {
slouken@1662
   305
        linkfile[linksize] = '\0';
slouken@1668
   306
        spot = SDL_strrchr(linkfile, '/');
slouken@1662
   307
        if (spot) {
slouken@1668
   308
            SDL_strlcpy(classname, spot + 1, maxlen);
slouken@1662
   309
        } else {
slouken@1668
   310
            SDL_strlcpy(classname, linkfile, maxlen);
slouken@1662
   311
        }
slouken@1662
   312
        return classname;
slouken@1662
   313
    }
slouken@1402
   314
#endif /* __LINUX__ */
slouken@1325
   315
slouken@1662
   316
    /* Finally use the default we've used forever */
slouken@1668
   317
    SDL_strlcpy(classname, "SDL_App", maxlen);
slouken@1662
   318
    return classname;
slouken@1325
   319
}
slouken@1325
   320
slouken@0
   321
/* Create auxiliary (toplevel) windows with the current visual */
slouken@1662
   322
static void
slouken@1668
   323
create_aux_windows(_THIS)
slouken@0
   324
{
slouken@1659
   325
    int x = 0, y = 0;
slouken@1325
   326
    char classname[1024];
slouken@0
   327
    XSetWindowAttributes xattr;
slouken@0
   328
    XWMHints *hints;
slouken@1668
   329
    int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen));
slouken@0
   330
slouken@1558
   331
    /* Look up some useful Atoms */
slouken@1668
   332
    WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False);
slouken@1558
   333
slouken@0
   334
    /* Don't create any extra windows if we are being managed */
slouken@1662
   335
    if (SDL_windowid) {
slouken@1662
   336
        FSwindow = 0;
slouken@1668
   337
        WMwindow = SDL_strtol(SDL_windowid, NULL, 0);
slouken@0
   338
        return;
slouken@0
   339
    }
slouken@0
   340
slouken@1662
   341
    if (FSwindow)
slouken@1668
   342
        XDestroyWindow(SDL_Display, FSwindow);
slouken@0
   343
slouken@1659
   344
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@1662
   345
    if (use_xinerama) {
slouken@1662
   346
        x = xinerama[this->current_display].x_org;
slouken@1662
   347
        y = xinerama[this->current_display].y_org;
slouken@1659
   348
    }
slouken@1659
   349
#endif
slouken@0
   350
    xattr.override_redirect = True;
slouken@1662
   351
    xattr.background_pixel =
slouken@1668
   352
        def_vis ? BlackPixel(SDL_Display, SDL_Screen) : 0;
slouken@0
   353
    xattr.border_pixel = 0;
slouken@0
   354
    xattr.colormap = SDL_XColorMap;
slouken@0
   355
slouken@1668
   356
    FSwindow = XCreateWindow(SDL_Display, SDL_Root,
slouken@1668
   357
                             x, y, 32, 32, 0,
slouken@1668
   358
                             this->hidden->depth, InputOutput, SDL_Visual,
slouken@1668
   359
                             CWOverrideRedirect | CWBackPixel | CWBorderPixel
slouken@1668
   360
                             | CWColormap, &xattr);
slouken@0
   361
slouken@1668
   362
    XSelectInput(SDL_Display, FSwindow, StructureNotifyMask);
slouken@0
   363
slouken@0
   364
    /* Tell KDE to keep the fullscreen window on top */
slouken@0
   365
    {
slouken@1662
   366
        XEvent ev;
slouken@1662
   367
        long mask;
slouken@0
   368
slouken@1668
   369
        SDL_memset(&ev, 0, sizeof(ev));
slouken@1662
   370
        ev.xclient.type = ClientMessage;
slouken@1662
   371
        ev.xclient.window = SDL_Root;
slouken@1668
   372
        ev.xclient.message_type = XInternAtom(SDL_Display,
slouken@1668
   373
                                              "KWM_KEEP_ON_TOP", False);
slouken@1662
   374
        ev.xclient.format = 32;
slouken@1662
   375
        ev.xclient.data.l[0] = FSwindow;
slouken@1662
   376
        ev.xclient.data.l[1] = CurrentTime;
slouken@1662
   377
        mask = SubstructureRedirectMask;
slouken@1668
   378
        XSendEvent(SDL_Display, SDL_Root, False, mask, &ev);
slouken@0
   379
    }
slouken@0
   380
slouken@0
   381
    hints = NULL;
slouken@1662
   382
    if (WMwindow) {
slouken@1662
   383
        /* All window attributes must survive the recreation */
slouken@1668
   384
        hints = XGetWMHints(SDL_Display, WMwindow);
slouken@1668
   385
        XDestroyWindow(SDL_Display, WMwindow);
slouken@0
   386
    }
slouken@0
   387
slouken@0
   388
    /* Create the window for windowed management */
slouken@0
   389
    /* (reusing the xattr structure above) */
slouken@1668
   390
    WMwindow = XCreateWindow(SDL_Display, SDL_Root,
slouken@1668
   391
                             x, y, 32, 32, 0,
slouken@1668
   392
                             this->hidden->depth, InputOutput, SDL_Visual,
slouken@1668
   393
                             CWBackPixel | CWBorderPixel | CWColormap,
slouken@1668
   394
                             &xattr);
slouken@0
   395
slouken@0
   396
    /* Set the input hints so we get keyboard input */
slouken@1662
   397
    if (!hints) {
slouken@1668
   398
        hints = XAllocWMHints();
slouken@1662
   399
        hints->input = True;
slouken@1662
   400
        hints->flags = InputHint;
slouken@0
   401
    }
slouken@1668
   402
    XSetWMHints(SDL_Display, WMwindow, hints);
slouken@1668
   403
    XFree(hints);
slouken@1668
   404
    X11_SetCaptionNoLock(this, SDL_CurrentWindow.wm_title,
slouken@1668
   405
                         SDL_CurrentWindow.wm_icon);
slouken@0
   406
slouken@1668
   407
    XSelectInput(SDL_Display, WMwindow,
slouken@1668
   408
                 FocusChangeMask | KeyPressMask | KeyReleaseMask
slouken@1668
   409
                 | PropertyChangeMask | StructureNotifyMask |
slouken@1668
   410
                 KeymapStateMask);
slouken@0
   411
slouken@0
   412
    /* Set the class hints so we can get an icon (AfterStep) */
slouken@1668
   413
    get_classname(classname, sizeof(classname));
slouken@0
   414
    {
slouken@1662
   415
        XClassHint *classhints;
slouken@1668
   416
        classhints = XAllocClassHint();
slouken@1662
   417
        if (classhints != NULL) {
slouken@1662
   418
            classhints->res_name = classname;
slouken@1662
   419
            classhints->res_class = classname;
slouken@1668
   420
            XSetClassHint(SDL_Display, WMwindow, classhints);
slouken@1668
   421
            XFree(classhints);
slouken@1662
   422
        }
slouken@0
   423
    }
slouken@0
   424
icculus@1178
   425
    /* Setup the communication with the IM server */
slouken@1662
   426
    SDL_IM = NULL;
slouken@1662
   427
    SDL_IC = NULL;
icculus@1178
   428
slouken@1662
   429
#ifdef X_HAVE_UTF8_STRING
slouken@1662
   430
    if (SDL_X11_HAVE_UTF8) {
slouken@1668
   431
        SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname);
slouken@1662
   432
        if (SDL_IM == NULL) {
slouken@1668
   433
            SDL_SetError("no input method could be opened");
slouken@1662
   434
        } else {
slouken@1668
   435
            SDL_IC = pXCreateIC(SDL_IM,
slouken@1668
   436
                                XNClientWindow, WMwindow,
slouken@1668
   437
                                XNFocusWindow, WMwindow,
slouken@1668
   438
                                XNInputStyle,
slouken@1668
   439
                                XIMPreeditNothing | XIMStatusNothing,
slouken@1668
   440
                                XNResourceName, classname,
slouken@1668
   441
                                XNResourceClass, classname, NULL);
icculus@1575
   442
slouken@1662
   443
            if (SDL_IC == NULL) {
slouken@1668
   444
                SDL_SetError("no input context could be created");
slouken@1668
   445
                XCloseIM(SDL_IM);
slouken@1662
   446
                SDL_IM = NULL;
slouken@1662
   447
            }
slouken@1662
   448
        }
slouken@1662
   449
    }
slouken@1662
   450
#endif
icculus@1178
   451
slouken@1662
   452
    /* Allow the window to be deleted by the window manager */
slouken@1668
   453
    XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1);
slouken@0
   454
}
slouken@0
   455
slouken@1662
   456
static int
slouken@1668
   457
X11_VideoInit(_THIS)
slouken@0
   458
{
slouken@1662
   459
    char *display;
slouken@1662
   460
    int i;
slouken@1662
   461
    SDL_DisplayMode desktop_mode;
slouken@0
   462
slouken@1662
   463
    /* Open the X11 display */
slouken@1662
   464
    display = NULL;             /* Get it from DISPLAY environment variable */
slouken@0
   465
slouken@1668
   466
    if ((SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
slouken@1668
   467
        (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0)) {
slouken@1662
   468
        local_X11 = 1;
slouken@1662
   469
    } else {
slouken@1662
   470
        local_X11 = 0;
slouken@1662
   471
    }
slouken@1668
   472
    SDL_Display = XOpenDisplay(display);
slouken@1361
   473
#if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
slouken@1662
   474
    /* On Tru64 if linking without -lX11, it fails and you get following message.
slouken@1662
   475
     * Xlib: connection to ":0.0" refused by server
slouken@1662
   476
     * Xlib: XDM authorization key matches an existing client!
slouken@1662
   477
     *
slouken@1662
   478
     * It succeeds if retrying 1 second later
slouken@1662
   479
     * or if running xhost +localhost on shell.
slouken@1662
   480
     *
slouken@1662
   481
     */
slouken@1662
   482
    if (SDL_Display == NULL) {
slouken@1668
   483
        SDL_Delay(1000);
slouken@1668
   484
        SDL_Display = XOpenDisplay(display);
slouken@1662
   485
    }
icculus@1299
   486
#endif
slouken@1662
   487
    if (SDL_Display == NULL) {
slouken@1668
   488
        SDL_SetError("Couldn't open X11 display");
slouken@1662
   489
        return (-1);
slouken@1662
   490
    }
slouken@0
   491
#ifdef X11_DEBUG
slouken@1668
   492
    XSynchronize(SDL_Display, True);
slouken@0
   493
#endif
slouken@0
   494
slouken@1662
   495
    /* Create an alternate X display for graphics updates -- allows us
slouken@1662
   496
       to do graphics updates in a separate thread from event handling.
slouken@1662
   497
       Thread-safe X11 doesn't seem to exist.
slouken@1662
   498
     */
slouken@1668
   499
    GFX_Display = XOpenDisplay(display);
slouken@1662
   500
    if (GFX_Display == NULL) {
slouken@1668
   501
        SDL_SetError("Couldn't open X11 display");
slouken@1662
   502
        return (-1);
slouken@1662
   503
    }
slouken@0
   504
slouken@1662
   505
    /* Set the normal X error handler */
slouken@1668
   506
    X_handler = XSetErrorHandler(x_errhandler);
slouken@0
   507
slouken@1662
   508
    /* Set the error handler if we lose the X display */
slouken@1668
   509
    XIO_handler = XSetIOErrorHandler(xio_errhandler);
slouken@0
   510
slouken@1662
   511
    /* Set the X extension error handler */
slouken@1668
   512
    Xext_handler = XSetExtensionErrorHandler(xext_errhandler);
icculus@1248
   513
slouken@1662
   514
    /* use default screen (from $DISPLAY) */
slouken@1668
   515
    SDL_Screen = DefaultScreen(SDL_Display);
slouken@0
   516
slouken@0
   517
#ifndef NO_SHARED_MEMORY
slouken@1662
   518
    /* Check for MIT shared memory extension */
slouken@1662
   519
    use_mitshm = 0;
slouken@1662
   520
    if (local_X11) {
slouken@1668
   521
        use_mitshm = XShmQueryExtension(SDL_Display);
slouken@1662
   522
    }
slouken@0
   523
#endif /* NO_SHARED_MEMORY */
slouken@0
   524
slouken@1662
   525
    /* Get the available visuals */
slouken@1668
   526
    if (X11_GetVisuals(this) < 0)
slouken@1662
   527
        return -1;
slouken@0
   528
slouken@1662
   529
    /* Determine the default screen mode:
slouken@1662
   530
       Use the default visual (or at least one with the same depth) */
slouken@1668
   531
    SDL_DisplayColormap = DefaultColormap(SDL_Display, SDL_Screen);
slouken@1662
   532
    for (i = 0; i < this->hidden->nvisuals; i++)
slouken@1668
   533
        if (this->hidden->visuals[i].depth == DefaultDepth(SDL_Display,
slouken@1668
   534
                                                           SDL_Screen))
slouken@1662
   535
            break;
slouken@1662
   536
    if (i == this->hidden->nvisuals) {
slouken@1662
   537
        /* default visual was useless, take the deepest one instead */
slouken@1662
   538
        i = 0;
slouken@1662
   539
    }
slouken@1662
   540
    SDL_Visual = this->hidden->visuals[i].visual;
slouken@1668
   541
    if (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)) {
slouken@1662
   542
        SDL_XColorMap = SDL_DisplayColormap;
slouken@1662
   543
    } else {
slouken@1668
   544
        SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
slouken@1668
   545
                                        SDL_Visual, AllocNone);
slouken@1662
   546
    }
slouken@1662
   547
    desktop_mode.format =
slouken@1668
   548
        X11_VisualToFormat(this->hidden->visuals[i].visual,
slouken@1668
   549
                           this->hidden->visuals[i].depth,
slouken@1668
   550
                           this->hidden->visuals[i].bpp);
slouken@1668
   551
    desktop_mode.w = DisplayWidth(SDL_Display, SDL_Screen);
slouken@1668
   552
    desktop_mode.h = DisplayHeight(SDL_Display, SDL_Screen);
slouken@1662
   553
    desktop_mode.refresh_rate = 0;
slouken@1668
   554
    SDL_AddVideoDisplay(&desktop_mode);
slouken@1545
   555
slouken@1662
   556
    /* Get the available video modes */
slouken@1668
   557
    if (X11_GetVideoModes(this) < 0)
slouken@1662
   558
        return -1;
slouken@0
   559
slouken@1668
   560
    X11_SaveVidModeGamma(this);
slouken@1659
   561
slouken@1662
   562
    /* Save DPMS and screensaver settings */
slouken@1668
   563
    X11_SaveScreenSaver(SDL_Display, &screensaver_timeout, &dpms_enabled);
slouken@1668
   564
    X11_DisableScreenSaver(SDL_Display);
slouken@0
   565
slouken@1662
   566
    /* See if we have been passed a window to use */
slouken@1668
   567
    SDL_windowid = SDL_getenv("SDL_WINDOWID");
slouken@0
   568
slouken@1662
   569
    /* Create the fullscreen and managed windows */
slouken@1668
   570
    create_aux_windows(this);
slouken@0
   571
slouken@1662
   572
    /* Create the blank cursor */
slouken@1668
   573
    SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask,
slouken@1668
   574
                                           BLANK_CWIDTH, BLANK_CHEIGHT,
slouken@1668
   575
                                           BLANK_CHOTX, BLANK_CHOTY);
slouken@0
   576
slouken@1662
   577
    /* Fill in some window manager capabilities */
slouken@1662
   578
    this->info.wm_available = 1;
slouken@1662
   579
slouken@1662
   580
    /* We're done! */
slouken@1668
   581
    XFlush(SDL_Display);
slouken@1662
   582
    return (0);
slouken@0
   583
}
slouken@0
   584
slouken@1662
   585
static void
slouken@1668
   586
X11_DestroyWindow(_THIS, SDL_Surface * screen)
slouken@0
   587
{
slouken@1662
   588
    /* Clean up OpenGL */
slouken@1662
   589
    if (screen) {
slouken@1662
   590
        screen->flags &= ~SDL_INTERNALOPENGL;
slouken@1662
   591
    }
slouken@1668
   592
    X11_GL_Shutdown(this);
slouken@0
   593
slouken@1662
   594
    if (!SDL_windowid) {
slouken@1662
   595
        /* Hide the managed window */
slouken@1662
   596
        if (WMwindow) {
slouken@1668
   597
            XUnmapWindow(SDL_Display, WMwindow);
slouken@1662
   598
        }
slouken@1662
   599
        if (screen && (screen->flags & SDL_FULLSCREEN)) {
slouken@1662
   600
            screen->flags &= ~SDL_FULLSCREEN;
slouken@1668
   601
            X11_LeaveFullScreen(this);
slouken@1662
   602
        }
slouken@0
   603
slouken@1662
   604
        /* Destroy the output window */
slouken@1662
   605
        if (SDL_Window) {
slouken@1668
   606
            XDestroyWindow(SDL_Display, SDL_Window);
slouken@1662
   607
        }
slouken@0
   608
slouken@1662
   609
        /* Free the colormap entries */
slouken@1662
   610
        if (SDL_XPixels) {
slouken@1662
   611
            int numcolors;
slouken@1662
   612
            unsigned long pixel;
slouken@1662
   613
            numcolors = SDL_Visual->map_entries;
slouken@1662
   614
            for (pixel = 0; pixel < numcolors; ++pixel) {
slouken@1662
   615
                while (SDL_XPixels[pixel] > 0) {
slouken@1668
   616
                    XFreeColors(GFX_Display,
slouken@1668
   617
                                SDL_DisplayColormap, &pixel, 1, 0);
slouken@1662
   618
                    --SDL_XPixels[pixel];
slouken@1662
   619
                }
slouken@1662
   620
            }
slouken@1668
   621
            SDL_free(SDL_XPixels);
slouken@1662
   622
            SDL_XPixels = NULL;
slouken@1662
   623
        }
slouken@0
   624
slouken@1662
   625
        /* Free the graphics context */
slouken@1662
   626
        if (SDL_GC) {
slouken@1668
   627
            XFreeGC(SDL_Display, SDL_GC);
slouken@1662
   628
            SDL_GC = 0;
slouken@1662
   629
        }
slouken@1662
   630
    }
slouken@0
   631
}
slouken@0
   632
slouken@1662
   633
static SDL_bool
slouken@1668
   634
X11_WindowPosition(_THIS, int *x, int *y, int w, int h)
slouken@497
   635
{
slouken@1668
   636
    const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
slouken@1668
   637
    const char *center = SDL_getenv("SDL_VIDEO_CENTERED");
slouken@1662
   638
    if (window) {
slouken@1668
   639
        if (SDL_sscanf(window, "%d,%d", x, y) == 2) {
slouken@1662
   640
            return SDL_TRUE;
slouken@1662
   641
        }
slouken@1668
   642
        if (SDL_strcmp(window, "center") == 0) {
slouken@1662
   643
            center = window;
slouken@1662
   644
        }
slouken@1662
   645
    }
slouken@1662
   646
    if (center) {
slouken@1668
   647
        *x = (DisplayWidth(SDL_Display, SDL_Screen) - w) / 2;
slouken@1668
   648
        *y = (DisplayHeight(SDL_Display, SDL_Screen) - h) / 2;
slouken@1662
   649
        return SDL_TRUE;
slouken@1662
   650
    }
slouken@1662
   651
    return SDL_FALSE;
slouken@497
   652
}
slouken@497
   653
slouken@1662
   654
static void
slouken@1668
   655
X11_SetSizeHints(_THIS, int w, int h, Uint32 flags)
slouken@0
   656
{
slouken@1662
   657
    XSizeHints *hints;
slouken@0
   658
slouken@1668
   659
    hints = XAllocSizeHints();
slouken@1662
   660
    if (hints) {
slouken@1662
   661
        if (flags & SDL_RESIZABLE) {
slouken@1662
   662
            hints->min_width = 32;
slouken@1662
   663
            hints->min_height = 32;
slouken@1662
   664
            hints->max_height = 4096;
slouken@1662
   665
            hints->max_width = 4096;
slouken@1662
   666
        } else {
slouken@1662
   667
            hints->min_width = hints->max_width = w;
slouken@1662
   668
            hints->min_height = hints->max_height = h;
slouken@1662
   669
        }
slouken@1662
   670
        hints->flags = PMaxSize | PMinSize;
slouken@1662
   671
        if (flags & SDL_FULLSCREEN) {
slouken@1662
   672
            hints->x = 0;
slouken@1662
   673
            hints->y = 0;
slouken@1662
   674
            hints->flags |= USPosition;
slouken@1662
   675
        } else
slouken@1662
   676
            /* Center it, if desired */
slouken@1668
   677
        if (X11_WindowPosition(this, &hints->x, &hints->y, w, h)) {
slouken@1662
   678
            hints->flags |= USPosition;
slouken@1668
   679
            XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y);
slouken@0
   680
slouken@1662
   681
            /* Flush the resize event so we don't catch it later */
slouken@1668
   682
            XSync(SDL_Display, True);
slouken@1662
   683
        }
slouken@1668
   684
        XSetWMNormalHints(SDL_Display, WMwindow, hints);
slouken@1668
   685
        XFree(hints);
slouken@1662
   686
    }
slouken@0
   687
slouken@1662
   688
    /* Respect the window caption style */
slouken@1662
   689
    if (flags & SDL_NOFRAME) {
slouken@1662
   690
        SDL_bool set;
slouken@1662
   691
        Atom WM_HINTS;
slouken@0
   692
slouken@1662
   693
        /* We haven't modified the window manager hints yet */
slouken@1662
   694
        set = SDL_FALSE;
slouken@0
   695
slouken@1662
   696
        /* First try to set MWM hints */
slouken@1668
   697
        WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True);
slouken@1662
   698
        if (WM_HINTS != None) {
slouken@1662
   699
            /* Hints used by Motif compliant window managers */
slouken@1662
   700
            struct
slouken@1662
   701
            {
slouken@1662
   702
                unsigned long flags;
slouken@1662
   703
                unsigned long functions;
slouken@1662
   704
                unsigned long decorations;
slouken@1662
   705
                long input_mode;
slouken@1662
   706
                unsigned long status;
slouken@1662
   707
            } MWMHints = {
slouken@1662
   708
            (1L << 1), 0, 0, 0, 0};
slouken@0
   709
slouken@1668
   710
            XChangeProperty(SDL_Display, WMwindow,
slouken@1668
   711
                            WM_HINTS, WM_HINTS, 32,
slouken@1668
   712
                            PropModeReplace,
slouken@1668
   713
                            (unsigned char *) &MWMHints,
slouken@1668
   714
                            sizeof(MWMHints) / sizeof(long));
slouken@1662
   715
            set = SDL_TRUE;
slouken@1662
   716
        }
slouken@1662
   717
        /* Now try to set KWM hints */
slouken@1668
   718
        WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True);
slouken@1662
   719
        if (WM_HINTS != None) {
slouken@1662
   720
            long KWMHints = 0;
slouken@0
   721
slouken@1668
   722
            XChangeProperty(SDL_Display, WMwindow,
slouken@1668
   723
                            WM_HINTS, WM_HINTS, 32,
slouken@1668
   724
                            PropModeReplace,
slouken@1668
   725
                            (unsigned char *) &KWMHints,
slouken@1668
   726
                            sizeof(KWMHints) / sizeof(long));
slouken@1662
   727
            set = SDL_TRUE;
slouken@1662
   728
        }
slouken@1662
   729
        /* Now try to set GNOME hints */
slouken@1668
   730
        WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True);
slouken@1662
   731
        if (WM_HINTS != None) {
slouken@1662
   732
            long GNOMEHints = 0;
slouken@0
   733
slouken@1668
   734
            XChangeProperty(SDL_Display, WMwindow,
slouken@1668
   735
                            WM_HINTS, WM_HINTS, 32,
slouken@1668
   736
                            PropModeReplace,
slouken@1668
   737
                            (unsigned char *) &GNOMEHints,
slouken@1668
   738
                            sizeof(GNOMEHints) / sizeof(long));
slouken@1662
   739
            set = SDL_TRUE;
slouken@1662
   740
        }
slouken@1662
   741
        /* Finally set the transient hints if necessary */
slouken@1662
   742
        if (!set) {
slouken@1668
   743
            XSetTransientForHint(SDL_Display, WMwindow, SDL_Root);
slouken@1662
   744
        }
slouken@1662
   745
    } else {
slouken@1662
   746
        SDL_bool set;
slouken@1662
   747
        Atom WM_HINTS;
slouken@0
   748
slouken@1662
   749
        /* We haven't modified the window manager hints yet */
slouken@1662
   750
        set = SDL_FALSE;
slouken@0
   751
slouken@1662
   752
        /* First try to unset MWM hints */
slouken@1668
   753
        WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True);
slouken@1662
   754
        if (WM_HINTS != None) {
slouken@1668
   755
            XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
slouken@1662
   756
            set = SDL_TRUE;
slouken@1662
   757
        }
slouken@1662
   758
        /* Now try to unset KWM hints */
slouken@1668
   759
        WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True);
slouken@1662
   760
        if (WM_HINTS != None) {
slouken@1668
   761
            XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
slouken@1662
   762
            set = SDL_TRUE;
slouken@1662
   763
        }
slouken@1662
   764
        /* Now try to unset GNOME hints */
slouken@1668
   765
        WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True);
slouken@1662
   766
        if (WM_HINTS != None) {
slouken@1668
   767
            XDeleteProperty(SDL_Display, WMwindow, WM_HINTS);
slouken@1662
   768
            set = SDL_TRUE;
slouken@1662
   769
        }
slouken@1662
   770
        /* Finally unset the transient hints if necessary */
slouken@1662
   771
        if (!set) {
slouken@1662
   772
            /* NOTE: Does this work? */
slouken@1668
   773
            XSetTransientForHint(SDL_Display, WMwindow, None);
slouken@1662
   774
        }
slouken@1662
   775
    }
slouken@0
   776
}
slouken@0
   777
slouken@1662
   778
static int
slouken@1668
   779
X11_CreateWindow(_THIS, SDL_Surface * screen,
slouken@1668
   780
                 const SDL_DisplayMode * mode, Uint32 flags)
slouken@0
   781
{
slouken@1662
   782
    int i, depth;
slouken@1662
   783
    Visual *vis;
slouken@1662
   784
    int vis_change;
slouken@1662
   785
    int bpp;
slouken@1662
   786
    Uint32 Rmask, Gmask, Bmask, Amask;
slouken@0
   787
slouken@1668
   788
    SDL_PixelFormatEnumToMasks(mode->format, &bpp, &Rmask, &Gmask, &Bmask,
slouken@1668
   789
                               &Amask);
slouken@0
   790
slouken@1662
   791
    /* If a window is already present, destroy it and start fresh */
slouken@1662
   792
    if (SDL_Window) {
slouken@1668
   793
        X11_DestroyWindow(this, screen);
slouken@1662
   794
        switch_waiting = 0;     /* Prevent jump back to now-meaningless state. */
slouken@1662
   795
    }
slouken@0
   796
slouken@1662
   797
    /* See if we have been given a window id */
slouken@1662
   798
    if (SDL_windowid) {
slouken@1668
   799
        SDL_Window = SDL_strtol(SDL_windowid, NULL, 0);
slouken@1662
   800
    } else {
slouken@1662
   801
        SDL_Window = 0;
slouken@1662
   802
    }
slouken@0
   803
slouken@1662
   804
    /* find out which visual we are going to use */
slouken@1662
   805
    if (flags & SDL_INTERNALOPENGL) {
slouken@1662
   806
        XVisualInfo *vi;
slouken@0
   807
slouken@1668
   808
        vi = X11_GL_GetVisual(this);
slouken@1662
   809
        if (!vi) {
slouken@1662
   810
            return -1;
slouken@1662
   811
        }
slouken@1662
   812
        vis = vi->visual;
slouken@1662
   813
        depth = vi->depth;
slouken@1662
   814
    } else if (SDL_windowid) {
slouken@1662
   815
        XWindowAttributes a;
slouken@1662
   816
slouken@1668
   817
        XGetWindowAttributes(SDL_Display, SDL_Window, &a);
slouken@1662
   818
        vis = a.visual;
slouken@1662
   819
        depth = a.depth;
slouken@1662
   820
    } else {
slouken@1662
   821
        for (i = 0; i < this->hidden->nvisuals; i++) {
slouken@1662
   822
            if (this->hidden->visuals[i].bpp == bpp &&
slouken@1662
   823
                this->hidden->visuals[i].visual->red_mask == Rmask &&
slouken@1662
   824
                this->hidden->visuals[i].visual->green_mask == Gmask &&
slouken@1662
   825
                this->hidden->visuals[i].visual->blue_mask == Bmask)
slouken@1662
   826
                break;
slouken@1662
   827
        }
slouken@1662
   828
        if (i == this->hidden->nvisuals) {
slouken@1668
   829
            SDL_SetError("No matching visual for requested depth");
slouken@1662
   830
            return -1;          /* should never happen */
slouken@1662
   831
        }
slouken@1662
   832
        vis = this->hidden->visuals[i].visual;
slouken@1662
   833
        depth = this->hidden->visuals[i].depth;
slouken@1662
   834
    }
slouken@0
   835
#ifdef X11_DEBUG
slouken@1668
   836
    printf("Choosing %s visual at %d bpp - %d colormap entries\n",
slouken@1668
   837
           vis->class == PseudoColor ? "PseudoColor" : (vis->class ==
slouken@1668
   838
                                                        TrueColor ?
slouken@1668
   839
                                                        "TrueColor" : (vis->
slouken@1668
   840
                                                                       class
slouken@1668
   841
                                                                       ==
slouken@1668
   842
                                                                       DirectColor
slouken@1668
   843
                                                                       ?
slouken@1668
   844
                                                                       "DirectColor"
slouken@1668
   845
                                                                       :
slouken@1668
   846
                                                                       "Unknown")),
slouken@1668
   847
           depth, vis->map_entries);
slouken@0
   848
#endif
slouken@1662
   849
    vis_change = (vis != SDL_Visual);
slouken@1662
   850
    SDL_Visual = vis;
slouken@1662
   851
    this->hidden->depth = depth;
slouken@0
   852
slouken@1662
   853
    /* Allocate the new pixel format for this video mode */
slouken@1668
   854
    if (!SDL_ReallocFormat(screen, bpp, Rmask, Gmask, Bmask, Amask)) {
slouken@1662
   855
        return -1;
slouken@1662
   856
    }
slouken@0
   857
slouken@1662
   858
    /* Create the appropriate colormap */
slouken@1662
   859
    if (SDL_XColorMap != SDL_DisplayColormap) {
slouken@1668
   860
        XFreeColormap(SDL_Display, SDL_XColorMap);
slouken@1662
   861
    }
slouken@1662
   862
    if (SDL_Visual->class == PseudoColor) {
slouken@1662
   863
        int ncolors;
slouken@0
   864
slouken@1662
   865
        /* Allocate the pixel flags */
slouken@1662
   866
        ncolors = SDL_Visual->map_entries;
slouken@1668
   867
        SDL_XPixels = SDL_malloc(ncolors * sizeof(int));
slouken@1662
   868
        if (SDL_XPixels == NULL) {
slouken@1668
   869
            SDL_OutOfMemory();
slouken@1662
   870
            return -1;
slouken@1662
   871
        }
slouken@1668
   872
        SDL_memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels));
slouken@0
   873
slouken@1662
   874
        /* always allocate a private colormap on non-default visuals */
slouken@1668
   875
        if (SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen)) {
slouken@1662
   876
            flags |= SDL_HWPALETTE;
slouken@1662
   877
        }
slouken@1662
   878
        if (flags & SDL_HWPALETTE) {
slouken@1662
   879
            screen->flags |= SDL_HWPALETTE;
slouken@1668
   880
            SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
slouken@1668
   881
                                            SDL_Visual, AllocAll);
slouken@1662
   882
        } else {
slouken@1662
   883
            SDL_XColorMap = SDL_DisplayColormap;
slouken@1662
   884
        }
slouken@1662
   885
    } else if (SDL_Visual->class == DirectColor) {
slouken@0
   886
slouken@1662
   887
        /* Create a colormap which we can manipulate for gamma */
slouken@1668
   888
        SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
slouken@1668
   889
                                        SDL_Visual, AllocAll);
slouken@1668
   890
        XSync(SDL_Display, False);
slouken@0
   891
slouken@1662
   892
        /* Initialize the colormap to the identity mapping */
slouken@1668
   893
        SDL_GetGammaRamp(0, 0, 0);
slouken@1662
   894
        SDL_VideoSurface = screen;
slouken@1668
   895
        X11_SetGammaRamp(this, SDL_CurrentWindow.gamma);
slouken@1662
   896
        SDL_VideoSurface = NULL;
slouken@1662
   897
    } else {
slouken@1662
   898
        /* Create a read-only colormap for our window */
slouken@1668
   899
        SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
slouken@1668
   900
                                        SDL_Visual, AllocNone);
slouken@1662
   901
    }
slouken@0
   902
slouken@1662
   903
    /* Recreate the auxiliary windows, if needed (required for GL) */
slouken@1662
   904
    if (vis_change)
slouken@1668
   905
        create_aux_windows(this);
slouken@0
   906
slouken@1662
   907
    if (screen->flags & SDL_HWPALETTE) {
slouken@1662
   908
        /* Since the full-screen window might have got a nonzero background
slouken@1662
   909
           colour (0 is white on some displays), we should reset the
slouken@1662
   910
           background to 0 here since that is what the user expects
slouken@1662
   911
           with a private colormap */
slouken@1668
   912
        XSetWindowBackground(SDL_Display, FSwindow, 0);
slouken@1668
   913
        XClearWindow(SDL_Display, FSwindow);
slouken@1662
   914
    }
slouken@0
   915
slouken@1662
   916
    /* resize the (possibly new) window manager window */
slouken@1662
   917
    if (!SDL_windowid) {
slouken@1668
   918
        X11_SetSizeHints(this, mode->w, mode->h, flags);
slouken@1662
   919
        window_w = mode->w;
slouken@1662
   920
        window_h = mode->h;
slouken@1668
   921
        XResizeWindow(SDL_Display, WMwindow, mode->w, mode->h);
slouken@1662
   922
    }
slouken@0
   923
slouken@1662
   924
    /* Create (or use) the X11 display window */
slouken@1662
   925
    if (!SDL_windowid) {
slouken@1662
   926
        if (flags & SDL_INTERNALOPENGL) {
slouken@1668
   927
            if (X11_GL_CreateWindow(this, mode->w, mode->h) < 0) {
slouken@1662
   928
                return (-1);
slouken@1662
   929
            }
slouken@1662
   930
        } else {
slouken@1662
   931
            XSetWindowAttributes swa;
slouken@0
   932
slouken@1662
   933
            swa.background_pixel = 0;
slouken@1662
   934
            swa.border_pixel = 0;
slouken@1662
   935
            swa.colormap = SDL_XColorMap;
slouken@1668
   936
            SDL_Window = XCreateWindow(SDL_Display, WMwindow,
slouken@1668
   937
                                       0, 0, mode->w, mode->h, 0, depth,
slouken@1668
   938
                                       InputOutput, SDL_Visual,
slouken@1668
   939
                                       CWBackPixel | CWBorderPixel
slouken@1668
   940
                                       | CWColormap, &swa);
slouken@1662
   941
        }
slouken@1662
   942
        /* Only manage our input if we own the window */
slouken@1668
   943
        XSelectInput(SDL_Display, SDL_Window,
slouken@1668
   944
                     (EnterWindowMask | LeaveWindowMask
slouken@1668
   945
                      | ButtonPressMask | ButtonReleaseMask
slouken@1668
   946
                      | PointerMotionMask | ExposureMask));
slouken@1662
   947
    }
slouken@1662
   948
    /* Create the graphics context here, once we have a window */
slouken@1662
   949
    if (flags & SDL_INTERNALOPENGL) {
slouken@1668
   950
        if (X11_GL_CreateContext(this) < 0) {
slouken@1662
   951
            return (-1);
slouken@1662
   952
        } else {
slouken@1662
   953
            screen->flags |= SDL_INTERNALOPENGL;
slouken@1662
   954
        }
slouken@1662
   955
    } else {
slouken@1662
   956
        XGCValues gcv;
slouken@0
   957
slouken@1662
   958
        gcv.graphics_exposures = False;
slouken@1668
   959
        SDL_GC = XCreateGC(SDL_Display, SDL_Window,
slouken@1668
   960
                           GCGraphicsExposures, &gcv);
slouken@1662
   961
        if (!SDL_GC) {
slouken@1668
   962
            SDL_SetError("Couldn't create graphics context");
slouken@1662
   963
            return (-1);
slouken@1662
   964
        }
slouken@1662
   965
    }
slouken@0
   966
slouken@1662
   967
    /* Set our colormaps when not setting a GL mode */
slouken@1662
   968
    if (!(flags & SDL_INTERNALOPENGL)) {
slouken@1668
   969
        XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap);
slouken@1662
   970
        if (!SDL_windowid) {
slouken@1668
   971
            XSetWindowColormap(SDL_Display, FSwindow, SDL_XColorMap);
slouken@1668
   972
            XSetWindowColormap(SDL_Display, WMwindow, SDL_XColorMap);
slouken@1662
   973
        }
slouken@1662
   974
    }
slouken@1662
   975
#if 0                           /* This is an experiment - are the graphics faster now? - nope. */
slouken@1668
   976
    if (SDL_getenv("SDL_VIDEO_X11_BACKINGSTORE"))
slouken@1662
   977
#endif
slouken@1662
   978
        /* Cache the window in the server, when possible */
slouken@1662
   979
    {
slouken@1662
   980
        Screen *xscreen;
slouken@1662
   981
        XSetWindowAttributes a;
slouken@0
   982
slouken@1668
   983
        xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen);
slouken@1668
   984
        a.backing_store = DoesBackingStore(xscreen);
slouken@1662
   985
        if (a.backing_store != NotUseful) {
slouken@1668
   986
            XChangeWindowAttributes(SDL_Display, SDL_Window,
slouken@1668
   987
                                    CWBackingStore, &a);
slouken@1662
   988
        }
slouken@1662
   989
    }
slouken@0
   990
slouken@1662
   991
    /* Update the internal keyboard state */
slouken@1668
   992
    X11_SetKeyboardState(SDL_Display, NULL);
slouken@0
   993
slouken@1662
   994
    /* When the window is first mapped, ignore non-modifier keys */
slouken@1662
   995
    {
slouken@1668
   996
        Uint8 *keys = SDL_GetKeyState(NULL);
slouken@1662
   997
        for (i = 0; i < SDLK_LAST; ++i) {
slouken@1662
   998
            switch (i) {
slouken@1662
   999
            case SDLK_NUMLOCK:
slouken@1662
  1000
            case SDLK_CAPSLOCK:
slouken@1662
  1001
            case SDLK_LCTRL:
slouken@1662
  1002
            case SDLK_RCTRL:
slouken@1662
  1003
            case SDLK_LSHIFT:
slouken@1662
  1004
            case SDLK_RSHIFT:
slouken@1662
  1005
            case SDLK_LALT:
slouken@1662
  1006
            case SDLK_RALT:
slouken@1662
  1007
            case SDLK_LMETA:
slouken@1662
  1008
            case SDLK_RMETA:
slouken@1662
  1009
            case SDLK_MODE:
slouken@1662
  1010
                break;
slouken@1662
  1011
            default:
slouken@1662
  1012
                keys[i] = SDL_RELEASED;
slouken@1662
  1013
                break;
slouken@1662
  1014
            }
slouken@1662
  1015
        }
slouken@1662
  1016
    }
slouken@0
  1017
slouken@1662
  1018
    /* Map them both and go fullscreen, if requested */
slouken@1662
  1019
    if (!SDL_windowid) {
slouken@1668
  1020
        XMapWindow(SDL_Display, SDL_Window);
slouken@1668
  1021
        XMapWindow(SDL_Display, WMwindow);
slouken@1668
  1022
        X11_WaitMapped(this, WMwindow);
slouken@1662
  1023
        if (flags & SDL_FULLSCREEN) {
slouken@1662
  1024
            screen->flags |= SDL_FULLSCREEN;
slouken@1668
  1025
            X11_EnterFullScreen(this);
slouken@1662
  1026
        } else {
slouken@1662
  1027
            screen->flags &= ~SDL_FULLSCREEN;
slouken@1662
  1028
        }
slouken@1662
  1029
    }
slouken@444
  1030
slouken@1662
  1031
    return (0);
slouken@0
  1032
}
slouken@0
  1033
slouken@1662
  1034
static int
slouken@1668
  1035
X11_ResizeWindow(_THIS, SDL_Surface * screen, int w, int h, Uint32 flags)
slouken@0
  1036
{
slouken@1662
  1037
    if (!SDL_windowid) {
slouken@1662
  1038
        /* Resize the window manager window */
slouken@1668
  1039
        X11_SetSizeHints(this, w, h, flags);
slouken@1662
  1040
        window_w = w;
slouken@1662
  1041
        window_h = h;
slouken@1668
  1042
        XResizeWindow(SDL_Display, WMwindow, w, h);
slouken@0
  1043
slouken@1662
  1044
        /* Resize the fullscreen and display windows */
slouken@1662
  1045
        if (flags & SDL_FULLSCREEN) {
slouken@1662
  1046
            if (screen->flags & SDL_FULLSCREEN) {
slouken@1668
  1047
                X11_ResizeFullScreen(this);
slouken@1662
  1048
            } else {
slouken@1662
  1049
                screen->flags |= SDL_FULLSCREEN;
slouken@1668
  1050
                X11_EnterFullScreen(this);
slouken@1662
  1051
            }
slouken@1662
  1052
        } else {
slouken@1662
  1053
            if (screen->flags & SDL_FULLSCREEN) {
slouken@1662
  1054
                screen->flags &= ~SDL_FULLSCREEN;
slouken@1668
  1055
                X11_LeaveFullScreen(this);
slouken@1662
  1056
            }
slouken@1662
  1057
        }
slouken@1668
  1058
        XResizeWindow(SDL_Display, SDL_Window, w, h);
slouken@1662
  1059
    }
slouken@1662
  1060
    return (0);
slouken@0
  1061
}
slouken@0
  1062
slouken@1662
  1063
SDL_Surface *
slouken@1668
  1064
X11_SetVideoMode(_THIS, SDL_Surface * current,
slouken@1668
  1065
                 const SDL_DisplayMode * mode, Uint32 flags)
slouken@0
  1066
{
slouken@1662
  1067
    Uint32 saved_flags;
slouken@0
  1068
slouken@1662
  1069
    /* Lock the event thread, in multi-threading environments */
slouken@1668
  1070
    SDL_Lock_EventThread();
slouken@0
  1071
slouken@1662
  1072
    /* Check the combination of flags we were passed */
slouken@1662
  1073
    if (flags & SDL_FULLSCREEN) {
slouken@1662
  1074
        /* Clear fullscreen flag if not supported */
slouken@1662
  1075
        if (SDL_windowid) {
slouken@1662
  1076
            flags &= ~SDL_FULLSCREEN;
slouken@1662
  1077
        }
slouken@1662
  1078
    }
slouken@0
  1079
slouken@1662
  1080
    /* Flush any delayed updates */
slouken@1668
  1081
    XSync(GFX_Display, False);
slouken@0
  1082
slouken@1662
  1083
    /* Set up the X11 window */
slouken@1662
  1084
    saved_flags = current->flags;
slouken@1662
  1085
    if ((SDL_Window)
slouken@1662
  1086
        && ((saved_flags & SDL_INTERNALOPENGL) ==
slouken@1662
  1087
            (flags & SDL_INTERNALOPENGL))
slouken@1662
  1088
        && (mode->format == SDL_CurrentDisplay.current_mode.format)
slouken@1662
  1089
        && ((saved_flags & SDL_NOFRAME) == (flags & SDL_NOFRAME))) {
slouken@1668
  1090
        if (X11_ResizeWindow(this, current, mode->w, mode->h, flags) < 0) {
slouken@1662
  1091
            current = NULL;
slouken@1662
  1092
            goto done;
slouken@1662
  1093
        }
slouken@1662
  1094
    } else {
slouken@1668
  1095
        if (X11_CreateWindow(this, current, mode, flags) < 0) {
slouken@1662
  1096
            current = NULL;
slouken@1662
  1097
            goto done;
slouken@1662
  1098
        }
slouken@1662
  1099
    }
slouken@0
  1100
slouken@1662
  1101
    /* Set up the new mode framebuffer */
slouken@1662
  1102
    if (((current->w != mode->w) || (current->h != mode->h)) ||
slouken@1662
  1103
        ((saved_flags & SDL_INTERNALOPENGL) != (flags & SDL_INTERNALOPENGL)))
slouken@1662
  1104
    {
slouken@1662
  1105
        current->w = mode->w;
slouken@1662
  1106
        current->h = mode->h;
slouken@1668
  1107
        current->pitch = SDL_CalculatePitch(current);
slouken@1668
  1108
        X11_ResizeImage(this, current, flags);
slouken@1662
  1109
    }
slouken@1662
  1110
    current->flags |= (flags & (SDL_RESIZABLE | SDL_NOFRAME));
slouken@0
  1111
slouken@0
  1112
  done:
slouken@1662
  1113
    /* Release the event thread */
slouken@1668
  1114
    XSync(SDL_Display, False);
slouken@1668
  1115
    SDL_Unlock_EventThread();
slouken@0
  1116
slouken@1662
  1117
    /* We're done! */
slouken@1662
  1118
    return (current);
slouken@0
  1119
}
slouken@0
  1120
slouken@1662
  1121
static int
slouken@1668
  1122
X11_ToggleFullScreen(_THIS, int on)
slouken@0
  1123
{
slouken@1662
  1124
    Uint32 event_thread;
slouken@0
  1125
slouken@1662
  1126
    /* Don't switch if we don't own the window */
slouken@1662
  1127
    if (SDL_windowid) {
slouken@1662
  1128
        return (0);
slouken@1662
  1129
    }
slouken@0
  1130
slouken@1662
  1131
    /* Don't lock if we are the event thread */
slouken@1668
  1132
    event_thread = SDL_EventThreadID();
slouken@1668
  1133
    if (event_thread && (SDL_ThreadID() == event_thread)) {
slouken@1662
  1134
        event_thread = 0;
slouken@1662
  1135
    }
slouken@1662
  1136
    if (event_thread) {
slouken@1668
  1137
        SDL_Lock_EventThread();
slouken@1662
  1138
    }
slouken@1662
  1139
    if (on) {
slouken@1662
  1140
        SDL_VideoSurface->flags |= SDL_FULLSCREEN;
slouken@1668
  1141
        X11_EnterFullScreen(this);
slouken@1662
  1142
    } else {
slouken@1662
  1143
        SDL_VideoSurface->flags &= ~SDL_FULLSCREEN;
slouken@1668
  1144
        X11_LeaveFullScreen(this);
slouken@1662
  1145
    }
slouken@1668
  1146
    X11_RefreshDisplay(this);
slouken@1662
  1147
    if (event_thread) {
slouken@1668
  1148
        SDL_Unlock_EventThread();
slouken@1662
  1149
    }
slouken@1668
  1150
    SDL_ResetKeyboard();
slouken@1662
  1151
    return (1);
slouken@0
  1152
}
slouken@0
  1153
slouken@0
  1154
/* Update the current mouse state and position */
slouken@1662
  1155
static void
slouken@1668
  1156
X11_UpdateMouse(_THIS)
slouken@0
  1157
{
slouken@1662
  1158
    Window u1;
slouken@1662
  1159
    int u2;
slouken@1662
  1160
    Window current_win;
slouken@1662
  1161
    int x, y;
slouken@1662
  1162
    unsigned int mask;
slouken@0
  1163
slouken@1662
  1164
    /* Lock the event thread, in multi-threading environments */
slouken@1668
  1165
    SDL_Lock_EventThread();
slouken@1668
  1166
    if (XQueryPointer(SDL_Display, SDL_Window, &u1, &current_win,
slouken@1668
  1167
                      &u2, &u2, &x, &y, &mask)) {
slouken@1662
  1168
        if ((x >= 0) && (x < SDL_VideoSurface->w) &&
slouken@1662
  1169
            (y >= 0) && (y < SDL_VideoSurface->h)) {
slouken@1668
  1170
            SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
slouken@1668
  1171
            SDL_PrivateMouseMotion(0, 0, x, y);
slouken@1662
  1172
        } else {
slouken@1668
  1173
            SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
slouken@1662
  1174
        }
slouken@1662
  1175
    }
slouken@1668
  1176
    SDL_Unlock_EventThread();
slouken@0
  1177
}
slouken@0
  1178
slouken@0
  1179
/* simple colour distance metric. Supposed to be better than a plain
slouken@0
  1180
   Euclidian distance anyway. */
slouken@0
  1181
#define COLOUR_FACTOR 3
slouken@0
  1182
#define LIGHT_FACTOR 1
slouken@0
  1183
#define COLOUR_DIST(r1, g1, b1, r2, g2, b2)				\
slouken@0
  1184
	(COLOUR_FACTOR * (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2))	\
slouken@0
  1185
	 + LIGHT_FACTOR * abs(r1 + g1 + b1 - (r2 + g2 + b2)))
slouken@0
  1186
slouken@1662
  1187
static void
slouken@1668
  1188
allocate_nearest(_THIS, SDL_Color * colors, SDL_Color * want, int nwant)
slouken@0
  1189
{
slouken@1662
  1190
    /*
slouken@1662
  1191
     * There is no way to know which ones to choose from, so we retrieve
slouken@1662
  1192
     * the entire colormap and try the nearest possible, until we find one
slouken@1662
  1193
     * that is shared.
slouken@1662
  1194
     */
slouken@1662
  1195
    XColor all[256];
slouken@1662
  1196
    int i;
slouken@1662
  1197
    for (i = 0; i < 256; i++)
slouken@1662
  1198
        all[i].pixel = i;
slouken@1662
  1199
    /* 
slouken@1662
  1200
     * XQueryColors sets the flags in the XColor struct, so we use
slouken@1662
  1201
     * that to keep track of which colours are available
slouken@1662
  1202
     */
slouken@1668
  1203
    XQueryColors(GFX_Display, SDL_XColorMap, all, 256);
slouken@0
  1204
slouken@1662
  1205
    for (i = 0; i < nwant; i++) {
slouken@1662
  1206
        XColor *c;
slouken@1662
  1207
        int j;
slouken@1662
  1208
        int best = 0;
slouken@1662
  1209
        int mindist = 0x7fffffff;
slouken@1662
  1210
        int ri = want[i].r;
slouken@1662
  1211
        int gi = want[i].g;
slouken@1662
  1212
        int bi = want[i].b;
slouken@1662
  1213
        for (j = 0; j < 256; j++) {
slouken@1662
  1214
            int rj, gj, bj, d2;
slouken@1662
  1215
            if (!all[j].flags)
slouken@1662
  1216
                continue;       /* unavailable colour cell */
slouken@1662
  1217
            rj = all[j].red >> 8;
slouken@1662
  1218
            gj = all[j].green >> 8;
slouken@1662
  1219
            bj = all[j].blue >> 8;
slouken@1668
  1220
            d2 = COLOUR_DIST(ri, gi, bi, rj, gj, bj);
slouken@1662
  1221
            if (d2 < mindist) {
slouken@1662
  1222
                mindist = d2;
slouken@1662
  1223
                best = j;
slouken@1662
  1224
            }
slouken@1662
  1225
        }
slouken@1662
  1226
        if (SDL_XPixels[best])
slouken@1662
  1227
            continue;           /* already allocated, waste no more time */
slouken@1662
  1228
        c = all + best;
slouken@1668
  1229
        if (XAllocColor(GFX_Display, SDL_XColorMap, c)) {
slouken@1662
  1230
            /* got it */
slouken@1662
  1231
            colors[c->pixel].r = c->red >> 8;
slouken@1662
  1232
            colors[c->pixel].g = c->green >> 8;
slouken@1662
  1233
            colors[c->pixel].b = c->blue >> 8;
slouken@1662
  1234
            ++SDL_XPixels[c->pixel];
slouken@1662
  1235
        } else {
slouken@1662
  1236
            /* 
slouken@1662
  1237
             * The colour couldn't be allocated, probably being
slouken@1662
  1238
             * owned as a r/w cell by another client. Flag it as
slouken@1662
  1239
             * unavailable and try again. The termination of the
slouken@1662
  1240
             * loop is guaranteed since at least black and white
slouken@1662
  1241
             * are always there.
slouken@1662
  1242
             */
slouken@1662
  1243
            c->flags = 0;
slouken@1662
  1244
            i--;
slouken@1662
  1245
        }
slouken@1662
  1246
    }
slouken@0
  1247
}
slouken@0
  1248
slouken@1662
  1249
int
slouken@1668
  1250
X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
slouken@0
  1251
{
slouken@1662
  1252
    int nrej = 0;
slouken@0
  1253
slouken@1662
  1254
    /* Check to make sure we have a colormap allocated */
slouken@1662
  1255
    if (SDL_XPixels == NULL) {
slouken@1662
  1256
        return (0);
slouken@1662
  1257
    }
slouken@1662
  1258
    if ((SDL_VideoSurface->flags & SDL_HWPALETTE) == SDL_HWPALETTE) {
slouken@1662
  1259
        /* private writable colormap: just set the colours we need */
slouken@1662
  1260
        XColor *xcmap;
slouken@1662
  1261
        int i;
slouken@1668
  1262
        xcmap = SDL_stack_alloc(XColor, ncolors);
slouken@1662
  1263
        if (xcmap == NULL)
slouken@1662
  1264
            return 0;
slouken@1662
  1265
        for (i = 0; i < ncolors; ++i) {
slouken@1662
  1266
            xcmap[i].pixel = i + firstcolor;
slouken@1662
  1267
            xcmap[i].red = (colors[i].r << 8) | colors[i].r;
slouken@1662
  1268
            xcmap[i].green = (colors[i].g << 8) | colors[i].g;
slouken@1662
  1269
            xcmap[i].blue = (colors[i].b << 8) | colors[i].b;
slouken@1662
  1270
            xcmap[i].flags = (DoRed | DoGreen | DoBlue);
slouken@1662
  1271
        }
slouken@1668
  1272
        XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
slouken@1668
  1273
        XSync(GFX_Display, False);
slouken@1668
  1274
        SDL_stack_free(xcmap);
slouken@1662
  1275
    } else {
slouken@1662
  1276
        /*
slouken@1662
  1277
         * Shared colormap: We only allocate read-only cells, which
slouken@1662
  1278
         * increases the likelyhood of colour sharing with other
slouken@1662
  1279
         * clients. The pixel values will almost certainly be
slouken@1662
  1280
         * different from the requested ones, so the user has to
slouken@1662
  1281
         * walk the colormap and see which index got what colour.
slouken@1662
  1282
         *
slouken@1662
  1283
         * We can work directly with the logical palette since it
slouken@1662
  1284
         * has already been set when we get here.
slouken@1662
  1285
         */
slouken@1662
  1286
        SDL_Color *want, *reject;
slouken@1662
  1287
        unsigned long *freelist;
slouken@1662
  1288
        int i;
slouken@1662
  1289
        int nfree = 0;
slouken@1662
  1290
        int nc = SDL_VideoSurface->format->palette->ncolors;
slouken@1662
  1291
        colors = SDL_VideoSurface->format->palette->colors;
slouken@1668
  1292
        freelist = SDL_stack_alloc(unsigned long, nc);
slouken@1662
  1293
        /* make sure multiple allocations of the same cell are freed */
slouken@1662
  1294
        for (i = 0; i < ncolors; i++) {
slouken@1662
  1295
            int pixel = firstcolor + i;
slouken@1662
  1296
            while (SDL_XPixels[pixel]) {
slouken@1662
  1297
                freelist[nfree++] = pixel;
slouken@1662
  1298
                --SDL_XPixels[pixel];
slouken@1662
  1299
            }
slouken@1662
  1300
        }
slouken@1668
  1301
        XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0);
slouken@1668
  1302
        SDL_stack_free(freelist);
slouken@0
  1303
slouken@1668
  1304
        want = SDL_stack_alloc(SDL_Color, ncolors);
slouken@1668
  1305
        reject = SDL_stack_alloc(SDL_Color, ncolors);
slouken@1668
  1306
        SDL_memcpy(want, colors + firstcolor, ncolors * sizeof(SDL_Color));
slouken@1662
  1307
        /* make sure the user isn't fooled by her own wishes
slouken@1662
  1308
           (black is safe, always available in the default colormap) */
slouken@1668
  1309
        SDL_memset(colors + firstcolor, 0, ncolors * sizeof(SDL_Color));
slouken@0
  1310
slouken@1662
  1311
        /* now try to allocate the colours */
slouken@1662
  1312
        for (i = 0; i < ncolors; i++) {
slouken@1662
  1313
            XColor col;
slouken@1662
  1314
            col.red = want[i].r << 8;
slouken@1662
  1315
            col.green = want[i].g << 8;
slouken@1662
  1316
            col.blue = want[i].b << 8;
slouken@1662
  1317
            col.flags = DoRed | DoGreen | DoBlue;
slouken@1668
  1318
            if (XAllocColor(GFX_Display, SDL_XColorMap, &col)) {
slouken@1662
  1319
                /* We got the colour, or at least the nearest
slouken@1662
  1320
                   the hardware could get. */
slouken@1662
  1321
                colors[col.pixel].r = col.red >> 8;
slouken@1662
  1322
                colors[col.pixel].g = col.green >> 8;
slouken@1662
  1323
                colors[col.pixel].b = col.blue >> 8;
slouken@1662
  1324
                ++SDL_XPixels[col.pixel];
slouken@1662
  1325
            } else {
slouken@1662
  1326
                /*
slouken@1662
  1327
                 * no more free cells, add it to the list
slouken@1662
  1328
                 * of rejected colours
slouken@1662
  1329
                 */
slouken@1662
  1330
                reject[nrej++] = want[i];
slouken@1662
  1331
            }
slouken@1662
  1332
        }
slouken@1662
  1333
        if (nrej)
slouken@1668
  1334
            allocate_nearest(this, colors, reject, nrej);
slouken@1668
  1335
        SDL_stack_free(reject);
slouken@1668
  1336
        SDL_stack_free(want);
slouken@1662
  1337
    }
slouken@1662
  1338
    return nrej == 0;
slouken@0
  1339
}
slouken@0
  1340
slouken@1662
  1341
int
slouken@1668
  1342
X11_SetGammaRamp(_THIS, Uint16 * ramp)
slouken@0
  1343
{
slouken@1662
  1344
    int i, ncolors;
slouken@1662
  1345
    XColor xcmap[256];
slouken@0
  1346
slouken@1662
  1347
    /* See if actually setting the gamma is supported */
slouken@1662
  1348
    if (SDL_Visual->class != DirectColor) {
slouken@1668
  1349
        SDL_SetError("Gamma correction not supported on this visual");
slouken@1662
  1350
        return (-1);
slouken@1662
  1351
    }
slouken@0
  1352
slouken@1662
  1353
    /* Calculate the appropriate palette for the given gamma ramp */
slouken@1662
  1354
    ncolors = SDL_Visual->map_entries;
slouken@1662
  1355
    for (i = 0; i < ncolors; ++i) {
slouken@1662
  1356
        Uint8 c = (256 * i / ncolors);
slouken@1668
  1357
        xcmap[i].pixel = SDL_MapRGB(SDL_VideoSurface->format, c, c, c);
slouken@1662
  1358
        xcmap[i].red = ramp[0 * 256 + c];
slouken@1662
  1359
        xcmap[i].green = ramp[1 * 256 + c];
slouken@1662
  1360
        xcmap[i].blue = ramp[2 * 256 + c];
slouken@1662
  1361
        xcmap[i].flags = (DoRed | DoGreen | DoBlue);
slouken@1662
  1362
    }
slouken@1668
  1363
    XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
slouken@1668
  1364
    XSync(GFX_Display, False);
slouken@1662
  1365
    return (0);
slouken@0
  1366
}
slouken@0
  1367
slouken@0
  1368
/* Note:  If we are terminated, this could be called in the middle of
slouken@0
  1369
   another SDL video routine -- notably UpdateRects.
slouken@0
  1370
*/
slouken@1662
  1371
void
slouken@1668
  1372
X11_VideoQuit(_THIS)
slouken@0
  1373
{
slouken@1662
  1374
    /* Shutdown everything that's still up */
slouken@1662
  1375
    /* The event thread should be done, so we can touch SDL_Display */
slouken@1662
  1376
    if (SDL_Display != NULL) {
slouken@1662
  1377
        /* Flush any delayed updates */
slouken@1668
  1378
        XSync(GFX_Display, False);
slouken@0
  1379
slouken@1662
  1380
        /* Close the connection with the IM server */
slouken@1662
  1381
#ifdef X_HAVE_UTF8_STRING
slouken@1662
  1382
        if (SDL_IC != NULL) {
slouken@1668
  1383
            XDestroyIC(SDL_IC);
slouken@1662
  1384
            SDL_IC = NULL;
slouken@1662
  1385
        }
slouken@1662
  1386
        if (SDL_IM != NULL) {
slouken@1668
  1387
            XCloseIM(SDL_IM);
slouken@1662
  1388
            SDL_IM = NULL;
slouken@1662
  1389
        }
slouken@1662
  1390
#endif
icculus@1178
  1391
slouken@1662
  1392
        /* Start shutting down the windows */
slouken@1668
  1393
        X11_DestroyImage(this, SDL_VideoSurface);
slouken@1668
  1394
        X11_DestroyWindow(this, SDL_VideoSurface);
slouken@1668
  1395
        X11_FreeVideoModes(this);
slouken@1662
  1396
        if (SDL_XColorMap != SDL_DisplayColormap) {
slouken@1668
  1397
            XFreeColormap(SDL_Display, SDL_XColorMap);
slouken@1662
  1398
        }
slouken@1662
  1399
        if (SDL_iconcolors) {
slouken@1662
  1400
            unsigned long pixel;
slouken@1668
  1401
            Colormap dcmap = DefaultColormap(SDL_Display,
slouken@1668
  1402
                                             SDL_Screen);
slouken@1662
  1403
            for (pixel = 0; pixel < 256; ++pixel) {
slouken@1662
  1404
                while (SDL_iconcolors[pixel] > 0) {
slouken@1668
  1405
                    XFreeColors(GFX_Display, dcmap, &pixel, 1, 0);
slouken@1662
  1406
                    --SDL_iconcolors[pixel];
slouken@1662
  1407
                }
slouken@1662
  1408
            }
slouken@1668
  1409
            SDL_free(SDL_iconcolors);
slouken@1662
  1410
            SDL_iconcolors = NULL;
slouken@1662
  1411
        }
slouken@1662
  1412
        if (xinerama) {
slouken@1668
  1413
            XFree(xinerama);
slouken@1662
  1414
        }
slouken@1659
  1415
slouken@1662
  1416
        /* Restore gamma settings if they've changed */
slouken@1668
  1417
        if (SDL_GetAppState() & SDL_APPACTIVE) {
slouken@1668
  1418
            X11_SwapVidModeGamma(this);
slouken@1662
  1419
        }
slouken@0
  1420
slouken@1662
  1421
        /* Restore DPMS and screensaver settings */
slouken@1668
  1422
        X11_RestoreScreenSaver(SDL_Display, screensaver_timeout,
slouken@1668
  1423
                               dpms_enabled);
slouken@1659
  1424
slouken@1662
  1425
        /* Free that blank cursor */
slouken@1662
  1426
        if (SDL_BlankCursor != NULL) {
slouken@1668
  1427
            this->FreeWMCursor(this, SDL_BlankCursor);
slouken@1662
  1428
            SDL_BlankCursor = NULL;
slouken@1662
  1429
        }
slouken@0
  1430
slouken@1662
  1431
        /* Close the X11 graphics connection */
slouken@1662
  1432
        if (GFX_Display != NULL) {
slouken@1668
  1433
            XCloseDisplay(GFX_Display);
slouken@1662
  1434
            GFX_Display = NULL;
slouken@1662
  1435
        }
slouken@0
  1436
slouken@1662
  1437
        /* Close the X11 display connection */
slouken@1668
  1438
        XCloseDisplay(SDL_Display);
slouken@1662
  1439
        SDL_Display = NULL;
slouken@0
  1440
slouken@1662
  1441
        /* Reset the X11 error handlers */
slouken@1662
  1442
        if (XIO_handler) {
slouken@1668
  1443
            XSetIOErrorHandler(XIO_handler);
slouken@1662
  1444
        }
slouken@1662
  1445
        if (X_handler) {
slouken@1668
  1446
            XSetErrorHandler(X_handler);
slouken@1662
  1447
        }
slouken@0
  1448
slouken@1662
  1449
        /* Unload GL library after X11 shuts down */
slouken@1668
  1450
        X11_GL_UnloadLibrary(this);
slouken@1662
  1451
    }
slouken@1662
  1452
    if (SDL_VideoSurface && (SDL_VideoSurface->flags & SDL_HWSURFACE)) {
slouken@1662
  1453
        /* Direct screen access, no memory buffer */
slouken@1662
  1454
        SDL_VideoSurface->pixels = NULL;
slouken@1662
  1455
    }
slouken@0
  1456
}
slouken@0
  1457
slouken@1662
  1458
/* vi: set ts=4 sw=4 expandtab: */