~brandontschaefer/libsdl/mir-support1.2

« back to all changes in this revision

Viewing changes to .pc/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch/src/video/x11/SDL_x11video.c

  • Committer: Package Import Robot
  • Author(s): Steve Langasek, Timo Jyrinki
  • Date: 2014-05-06 10:04:08 UTC
  • mfrom: (48.1.2 trunk)
  • Revision ID: package-import@ubuntu.com-20140506100408-56mh5f130j0gg1xg
Tags: 1.2.15-9ubuntu2
* Restore accidentally-clobbered changes from 1.2.15-8ubuntu2.

[ Timo Jyrinki ]
* debian/patches/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch:
  - Restore old backingstore behavior to prevent tearing
    (LP: #1280665)

Show diffs side-by-side

added added

removed removed

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