2
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2012 Sam Lantinga
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.
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.
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
22
#include "SDL_config.h"
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().
32
#include <sys/ioctl.h>
35
#include <sys/fcntl.h>
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"
57
#ifdef X_HAVE_UTF8_STRING
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,
68
static int X11_SetGammaRamp(_THIS, Uint16 *ramp);
69
static void X11_VideoQuit(_THIS);
72
/* X11 driver bootstrap functions */
74
static int X11_Available(void)
76
Display *display = NULL;
77
if ( SDL_X11_LoadSymbols() ) {
78
display = XOpenDisplay(NULL);
79
if ( display != NULL ) {
80
XCloseDisplay(display);
82
SDL_X11_UnloadSymbols();
84
return(display != NULL);
87
static void X11_DeleteDevice(SDL_VideoDevice *device)
90
if ( device->hidden ) {
91
SDL_free(device->hidden);
93
if ( device->gl_data ) {
94
SDL_free(device->gl_data);
97
SDL_X11_UnloadSymbols();
101
static SDL_VideoDevice *X11_CreateDevice(int devindex)
103
SDL_VideoDevice *device = NULL;
105
if ( SDL_X11_LoadSymbols() ) {
106
/* Initialize all variables that we clean on shutdown */
107
device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
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));
115
if ( (device == NULL) || (device->hidden == NULL) ||
116
(device->gl_data == NULL) ) {
118
X11_DeleteDevice(device); /* calls SDL_X11_UnloadSymbols(). */
121
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
122
SDL_memset(device->gl_data, 0, (sizeof *device->gl_data));
124
#if SDL_VIDEO_OPENGL_GLX
125
device->gl_data->swap_interval = -1;
128
/* Set the driver flags */
129
device->handles_any_size = 1;
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;
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;
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;
176
device->free = X11_DeleteDevice;
182
VideoBootStrap X11_bootstrap = {
183
"x11", "X Window System",
184
X11_Available, X11_CreateDevice
187
/* Normal X11 error handler routine */
188
static int (*X_handler)(Display *, XErrorEvent *) = NULL;
189
static int x_errhandler(Display *d, XErrorEvent *e)
191
#if SDL_VIDEO_DRIVER_X11_VIDMODE
194
#if SDL_VIDEO_DRIVER_X11_DGAMOUSE
195
extern int dga_error;
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) ?
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)))) ) {
210
XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
211
printf("VidMode error: %s\n", errmsg);
216
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
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))) ) {
225
XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg));
226
printf("DGA error: %s\n", errmsg);
231
#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */
233
return(X_handler(d,e));
236
/* X11 I/O error handler routine */
237
static int (*XIO_handler)(Display *) = NULL;
238
static int xio_errhandler(Display *d)
240
/* Ack! Lost X11 connection! */
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;
246
current_video->hidden->X11_Display = NULL;
248
/* Continue with the standard X11 error handler */
249
return(XIO_handler(d));
252
static int (*Xext_handler)(Display *, _Xconst char *, _Xconst char *) = NULL;
253
static int xext_errhandler(Display *d, _Xconst char *ext, _Xconst char *reason)
256
printf("Xext error inside SDL (may be harmless):\n");
257
printf(" Extension \"%s\" %s on display \"%s\".\n",
258
ext, reason, XDisplayString(d));
261
if (SDL_strcmp(reason, "missing") == 0) {
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.
270
/* Everything else goes to the default handler... */
271
return Xext_handler(d, ext, reason);
274
/* Find out what class name we should use */
275
static char *get_classname(char *classname, int maxlen)
278
#if defined(__LINUX__) || defined(__FREEBSD__)
284
/* First allow environment variable override */
285
spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
287
SDL_strlcpy(classname, spot, maxlen);
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());
298
#error Where can we find the executable name?
300
linksize = readlink(procfile, linkfile, sizeof(linkfile)-1);
301
if ( linksize > 0 ) {
302
linkfile[linksize] = '\0';
303
spot = SDL_strrchr(linkfile, '/');
305
SDL_strlcpy(classname, spot+1, maxlen);
307
SDL_strlcpy(classname, linkfile, maxlen);
311
#endif /* __LINUX__ */
313
/* Finally use the default we've used forever */
314
SDL_strlcpy(classname, "SDL_App", maxlen);
318
/* Create auxiliary (toplevel) windows with the current visual */
319
static void create_aux_windows(_THIS)
322
char classname[1024];
323
XSetWindowAttributes xattr;
325
unsigned long app_event_mask;
326
int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen));
328
/* Look up some useful Atoms */
329
WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False);
331
/* Don't create any extra windows if we are being managed */
332
if ( SDL_windowid ) {
334
WMwindow = SDL_strtol(SDL_windowid, NULL, 0);
339
XDestroyWindow(SDL_Display, FSwindow);
341
#if SDL_VIDEO_DRIVER_X11_XINERAMA
342
if ( use_xinerama ) {
343
x = xinerama_info.x_org;
344
y = xinerama_info.y_org;
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;
352
FSwindow = XCreateWindow(SDL_Display, SDL_Root,
354
this->hidden->depth, InputOutput, SDL_Visual,
355
CWOverrideRedirect | CWBackPixel | CWBorderPixel
359
XSelectInput(SDL_Display, FSwindow, StructureNotifyMask);
361
/* Tell KDE to keep the fullscreen window on top */
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);
380
/* All window attributes must survive the recreation */
381
hints = XGetWMHints(SDL_Display, WMwindow);
382
XDestroyWindow(SDL_Display, WMwindow);
385
/* Create the window for windowed management */
386
/* (reusing the xattr structure above) */
387
WMwindow = XCreateWindow(SDL_Display, SDL_Root,
389
this->hidden->depth, InputOutput, SDL_Visual,
390
CWBackPixel | CWBorderPixel | CWColormap,
393
/* Set the input hints so we get keyboard input */
395
hints = XAllocWMHints();
397
hints->flags = InputHint;
399
XSetWMHints(SDL_Display, WMwindow, hints);
401
X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon);
403
app_event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
404
| PropertyChangeMask | StructureNotifyMask | KeymapStateMask;
405
XSelectInput(SDL_Display, WMwindow, app_event_mask);
407
/* Set the class hints so we can get an icon (AfterStep) */
408
get_classname(classname, sizeof(classname));
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);
421
pid_t pid = getpid();
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);
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));
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. */
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");
449
XUnsetICFocus(SDL_IC);
457
/* Open an input method. */
458
if (SDL_IM == NULL) {
459
char *old_locale = NULL, *old_modifiers = NULL;
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
476
/* Save the current (application program's)
478
p = setlocale(LC_ALL, NULL);
481
old_locale = SDL_stack_alloc(char, n);
483
SDL_strlcpy(old_locale, p, n);
486
p = XSetLocaleModifiers(NULL);
489
old_modifiers = SDL_stack_alloc(char, n);
490
if ( old_modifiers ) {
491
SDL_strlcpy(old_modifiers, p, n);
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);
501
/* Restore the application's locale settings
502
so that we don't break the application's
503
expected behaviour. */
505
/* We need to restore the C library
506
locale first, since the
507
interpretation of the X modifier
509
setlocale(LC_ALL, old_locale);
510
SDL_stack_free(old_locale);
512
if ( old_modifiers ) {
513
XSetLocaleModifiers(old_modifiers);
514
SDL_stack_free(old_modifiers);
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");
522
if (SDL_IC != NULL) {
523
/* Discard the old IC before creating new one. */
524
XUnsetICFocus(SDL_IC);
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,
541
if (SDL_IC == NULL) {
542
SDL_SetError("no input context could be created");
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);
556
XUnsetICFocus(SDL_IC);
559
SDL_SetError("no input context could be created");
563
XSelectInput(SDL_Display, WMwindow, app_event_mask | mask);
571
/* Allow the window to be deleted by the window manager */
572
XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1);
575
static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat)
581
/* Open the X11 display */
582
display = NULL; /* Get it from DISPLAY environment variable */
584
if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
585
(SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
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!
596
* It succeeds if retrying 1 second later
597
* or if running xhost +localhost on shell.
600
if ( SDL_Display == NULL ) {
602
SDL_Display = XOpenDisplay(display);
605
if ( SDL_Display == NULL ) {
606
SDL_SetError("Couldn't open X11 display");
610
XSynchronize(SDL_Display, True);
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.
617
GFX_Display = XOpenDisplay(display);
618
if ( GFX_Display == NULL ) {
619
XCloseDisplay(SDL_Display);
621
SDL_SetError("Couldn't open X11 display");
625
/* Set the normal X error handler */
626
X_handler = XSetErrorHandler(x_errhandler);
628
/* Set the error handler if we lose the X display */
629
XIO_handler = XSetIOErrorHandler(xio_errhandler);
631
/* Set the X extension error handler */
632
Xext_handler = XSetExtensionErrorHandler(xext_errhandler);
634
/* use default screen (from $DISPLAY) */
635
SDL_Screen = DefaultScreen(SDL_Display);
637
#ifndef NO_SHARED_MEMORY
638
/* Check for MIT shared memory extension */
641
use_mitshm = XShmQueryExtension(SDL_Display);
643
#endif /* NO_SHARED_MEMORY */
645
/* Get the available video modes */
646
if(X11_GetVideoModes(this) < 0) {
647
XCloseDisplay(GFX_Display);
649
XCloseDisplay(SDL_Display);
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);
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,
665
if(i == this->hidden->nvisuals) {
666
/* default visual was useless, take the deepest one instead */
669
SDL_Visual = this->hidden->visuals[i].visual;
670
if ( SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen) ) {
671
SDL_XColorMap = SDL_DisplayColormap;
673
SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
674
SDL_Visual, AllocNone);
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;
683
if ( this->hidden->depth == 32 ) {
684
vformat->Amask = (0xFFFFFFFF & ~(vformat->Rmask|vformat->Gmask|vformat->Bmask));
686
X11_SaveVidModeGamma(this);
688
/* Allow environment override of screensaver disable. */
689
env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
691
allow_screensaver = SDL_atoi(env);
693
#ifdef SDL_VIDEO_DISABLE_SCREENSAVER
694
allow_screensaver = 0;
696
allow_screensaver = 1;
700
/* See if we have been passed a window to use */
701
SDL_windowid = SDL_getenv("SDL_WINDOWID");
703
/* Create the fullscreen and managed windows */
704
create_aux_windows(this);
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);
711
/* Fill in some window manager capabilities */
712
this->info.wm_available = 1;
719
static void X11_DestroyWindow(_THIS, SDL_Surface *screen)
721
/* Clean up OpenGL */
723
screen->flags &= ~(SDL_OPENGL|SDL_OPENGLBLIT);
725
X11_GL_Shutdown(this);
727
if ( ! SDL_windowid ) {
728
/* Hide the managed window */
730
XUnmapWindow(SDL_Display, WMwindow);
732
if ( screen && (screen->flags & SDL_FULLSCREEN) ) {
733
screen->flags &= ~SDL_FULLSCREEN;
734
X11_LeaveFullScreen(this);
737
/* Destroy the output window */
739
XDestroyWindow(SDL_Display, SDL_Window);
742
/* Free the colormap entries */
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];
754
SDL_free(SDL_XPixels);
758
/* Free the graphics context */
760
XFreeGC(SDL_Display, SDL_GC);
766
static SDL_bool X11_WindowPosition(_THIS, int *x, int *y, int w, int h)
768
const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
769
const char *center = SDL_getenv("SDL_VIDEO_CENTERED");
771
if ( SDL_sscanf(window, "%d,%d", x, y) == 2 ) {
774
if ( SDL_strcmp(window, "center") == 0 ) {
779
*x = (DisplayWidth(SDL_Display, SDL_Screen) - w)/2;
780
*y = (DisplayHeight(SDL_Display, SDL_Screen) - h)/2;
786
static void X11_SetSizeHints(_THIS, int w, int h, Uint32 flags)
790
hints = XAllocSizeHints();
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;
797
if ( flags & SDL_FULLSCREEN ) {
800
hints->flags |= USPosition;
802
/* Center it, if desired */
803
if ( X11_WindowPosition(this, &hints->x, &hints->y, w, h) ) {
804
hints->flags |= USPosition;
806
/* Hints must be set before moving the window, otherwise an
807
unwanted ConfigureNotify event will be issued */
808
XSetWMNormalHints(SDL_Display, WMwindow, hints);
810
XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y);
812
/* Flush the resize event so we don't catch it later */
813
XSync(SDL_Display, True);
815
XSetWMNormalHints(SDL_Display, WMwindow, hints);
819
/* Respect the window caption style */
820
if ( flags & SDL_NOFRAME ) {
824
/* We haven't modified the window manager hints yet */
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 */
833
unsigned long functions;
834
unsigned long decorations;
836
unsigned long status;
837
} MWMHints = { (1L << 1), 0, 0, 0, 0 };
839
XChangeProperty(SDL_Display, WMwindow,
840
WM_HINTS, WM_HINTS, 32,
842
(unsigned char *)&MWMHints,
843
sizeof(MWMHints)/sizeof(long));
846
/* Now try to set KWM hints */
847
WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True);
848
if ( WM_HINTS != None ) {
851
XChangeProperty(SDL_Display, WMwindow,
852
WM_HINTS, WM_HINTS, 32,
854
(unsigned char *)&KWMHints,
855
sizeof(KWMHints)/sizeof(long));
858
/* Now try to set GNOME hints */
859
WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True);
860
if ( WM_HINTS != None ) {
863
XChangeProperty(SDL_Display, WMwindow,
864
WM_HINTS, WM_HINTS, 32,
866
(unsigned char *)&GNOMEHints,
867
sizeof(GNOMEHints)/sizeof(long));
870
/* Finally set the transient hints if necessary */
872
XSetTransientForHint(SDL_Display, WMwindow, SDL_Root);
878
/* We haven't modified the window manager hints yet */
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);
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);
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);
899
/* Finally unset the transient hints if necessary */
901
XDeleteProperty(SDL_Display, WMwindow, XA_WM_TRANSIENT_FOR);
906
static int X11_CreateWindow(_THIS, SDL_Surface *screen,
907
int w, int h, int bpp, Uint32 flags)
914
/* If a window is already present, destroy it and start fresh */
916
X11_DestroyWindow(this, screen);
917
switch_waiting = 0; /* Prevent jump back to now-meaningless state. */
920
/* See if we have been given a window id */
921
if ( SDL_windowid ) {
922
SDL_Window = SDL_strtol(SDL_windowid, NULL, 0);
927
/* find out which visual we are going to use */
928
if ( flags & SDL_OPENGL ) {
931
vi = X11_GL_GetVisual(this);
937
} else if ( SDL_windowid ) {
940
XGetWindowAttributes(SDL_Display, SDL_Window, &a);
944
for ( i = 0; i < this->hidden->nvisuals; i++ ) {
945
if ( this->hidden->visuals[i].bpp == bpp )
948
if ( i == this->hidden->nvisuals ) {
949
SDL_SetError("No matching visual for requested depth");
950
return -1; /* should never happen */
952
vis = this->hidden->visuals[i].visual;
953
depth = this->hidden->visuals[i].depth;
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);
958
vis_change = (vis != SDL_Visual);
960
this->hidden->depth = depth;
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));
968
if ( ! SDL_ReallocFormat(screen, bpp,
969
vis->red_mask, vis->green_mask, vis->blue_mask, Amask) ) {
973
/* Create the appropriate colormap */
974
if ( SDL_XColorMap != SDL_DisplayColormap ) {
975
XFreeColormap(SDL_Display, SDL_XColorMap);
977
if ( SDL_Visual->class == PseudoColor ) {
980
/* Allocate the pixel flags */
981
ncolors = SDL_Visual->map_entries;
982
SDL_XPixels = SDL_malloc(ncolors * sizeof(int));
983
if(SDL_XPixels == NULL) {
987
SDL_memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels));
989
/* always allocate a private colormap on non-default visuals */
990
if ( SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen) ) {
991
flags |= SDL_HWPALETTE;
993
if ( flags & SDL_HWPALETTE ) {
994
screen->flags |= SDL_HWPALETTE;
995
SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
996
SDL_Visual, AllocAll);
998
SDL_XColorMap = SDL_DisplayColormap;
1000
} else if ( SDL_Visual->class == DirectColor ) {
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);
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;
1013
/* Create a read-only colormap for our window */
1014
SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root,
1015
SDL_Visual, AllocNone);
1018
/* Recreate the auxiliary windows, if needed (required for GL) */
1020
create_aux_windows(this);
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);
1031
/* resize the (possibly new) window manager window */
1032
if( !SDL_windowid ) {
1033
X11_SetSizeHints(this, w, h, flags);
1036
XResizeWindow(SDL_Display, WMwindow, w, h);
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 ) {
1046
XSetWindowAttributes swa;
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);
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 ));
1063
/* Create the graphics context here, once we have a window */
1064
if ( flags & SDL_OPENGL ) {
1065
if ( X11_GL_CreateContext(this) < 0 ) {
1068
screen->flags |= SDL_OPENGL;
1073
gcv.graphics_exposures = False;
1074
SDL_GC = XCreateGC(SDL_Display, SDL_Window,
1075
GCGraphicsExposures, &gcv);
1077
SDL_SetError("Couldn't create graphics context");
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);
1091
#if 0 /* This is an experiment - are the graphics faster now? - nope. */
1092
if ( SDL_getenv("SDL_VIDEO_X11_BACKINGSTORE") )
1094
/* Cache the window in the server, when possible */
1097
XSetWindowAttributes a;
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);
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);
1116
screen->flags &= ~SDL_FULLSCREEN;
1123
static int X11_ResizeWindow(_THIS,
1124
SDL_Surface *screen, int w, int h, Uint32 flags)
1126
if ( ! SDL_windowid ) {
1127
/* Resize the window manager window */
1128
X11_SetSizeHints(this, w, h, flags);
1131
XResizeWindow(SDL_Display, WMwindow, w, h);
1133
/* Resize the fullscreen and display windows */
1134
if ( flags & SDL_FULLSCREEN ) {
1135
if ( screen->flags & SDL_FULLSCREEN ) {
1136
X11_ResizeFullScreen(this);
1138
screen->flags |= SDL_FULLSCREEN;
1139
X11_EnterFullScreen(this);
1142
if ( screen->flags & SDL_FULLSCREEN ) {
1143
screen->flags &= ~SDL_FULLSCREEN;
1144
X11_LeaveFullScreen(this);
1147
XResizeWindow(SDL_Display, SDL_Window, w, h);
1152
SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current,
1153
int width, int height, int bpp, Uint32 flags)
1157
/* Lock the event thread, in multi-threading environments */
1158
SDL_Lock_EventThread();
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;
1168
/* Flush any delayed updates */
1169
XSync(GFX_Display, False);
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) {
1181
if (X11_CreateWindow(this,current,width,height,bpp,flags) < 0) {
1187
/* Update the internal keyboard state */
1188
X11_SetKeyboardState(SDL_Display, NULL);
1190
/* When the window is first mapped, ignore non-modifier keys */
1191
if ( !current->w && !current->h ) {
1192
Uint8 *keys = SDL_GetKeyState(NULL);
1194
for ( i = 0; i < SDLK_LAST; ++i ) {
1209
keys[i] = SDL_RELEASED;
1215
/* Set up the new mode framebuffer */
1216
if ( ((current->w != width) || (current->h != height)) ||
1217
((saved_flags&SDL_OPENGL) != (flags&SDL_OPENGL)) ) {
1219
current->h = height;
1220
current->pitch = SDL_CalculatePitch(current);
1221
if (X11_ResizeImage(this, current, flags) < 0) {
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));
1232
/* Release the event thread */
1233
XSync(SDL_Display, False);
1234
SDL_Unlock_EventThread();
1240
static int X11_ToggleFullScreen(_THIS, int on)
1242
Uint32 event_thread;
1244
/* Don't switch if we don't own the window */
1245
if ( SDL_windowid ) {
1249
/* Don't lock if we are the event thread */
1250
event_thread = SDL_EventThreadID();
1251
if ( event_thread && (SDL_ThreadID() == event_thread) ) {
1254
if ( event_thread ) {
1255
SDL_Lock_EventThread();
1258
this->screen->flags |= SDL_FULLSCREEN;
1259
X11_EnterFullScreen(this);
1261
this->screen->flags &= ~SDL_FULLSCREEN;
1262
X11_LeaveFullScreen(this);
1264
X11_RefreshDisplay(this);
1265
if ( event_thread ) {
1266
SDL_Unlock_EventThread();
1268
SDL_ResetKeyboard();
1272
/* Update the current mouse state and position */
1273
static void X11_UpdateMouse(_THIS)
1280
/* Lock the event thread, in multi-threading environments */
1281
SDL_Lock_EventThread();
1282
if ( XQueryPointer(SDL_Display, SDL_Window, &u1, ¤t_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);
1289
SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
1292
SDL_Unlock_EventThread();
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)))
1303
static void allocate_nearest(_THIS, SDL_Color *colors,
1304
SDL_Color *want, int nwant)
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
1313
for(i = 0; i < 256; i++)
1316
* XQueryColors sets the flags in the XColor struct, so we use
1317
* that to keep track of which colours are available
1319
XQueryColors(GFX_Display, SDL_XColorMap, all, 256);
1321
for(i = 0; i < nwant; i++) {
1325
int mindist = 0x7fffffff;
1329
for(j = 0; j < 256; j++) {
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);
1342
if(SDL_XPixels[best])
1343
continue; /* already allocated, waste no more time */
1345
if(XAllocColor(GFX_Display, SDL_XColorMap, c)) {
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];
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
1365
int X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1369
/* Check to make sure we have a colormap allocated */
1370
if ( SDL_XPixels == NULL ) {
1373
if ( (this->screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) {
1374
/* private writable colormap: just set the colours we need */
1377
xcmap = SDL_stack_alloc(XColor, ncolors);
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);
1387
XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
1388
XSync(GFX_Display, False);
1389
SDL_stack_free(xcmap);
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.
1398
* We can work directly with the logical palette since it
1399
* has already been set when we get here.
1401
SDL_Color *want, *reject;
1402
unsigned long *freelist;
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];
1416
XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0);
1417
SDL_stack_free(freelist);
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));
1426
/* now try to allocate the colours */
1427
for(i = 0; i < ncolors; i++) {
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];
1442
* no more free cells, add it to the list
1443
* of rejected colours
1445
reject[nrej++] = want[i];
1449
allocate_nearest(this, colors, reject, nrej);
1450
SDL_stack_free(reject);
1451
SDL_stack_free(want);
1456
int X11_SetGammaRamp(_THIS, Uint16 *ramp)
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");
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);
1477
XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
1478
XSync(GFX_Display, False);
1482
/* Note: If we are terminated, this could be called in the middle of
1483
another SDL video routine -- notably UpdateRects.
1485
void X11_VideoQuit(_THIS)
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);
1493
/* Close the connection with the IM server */
1494
#ifdef X_HAVE_UTF8_STRING
1495
if (SDL_IC != NULL) {
1496
XUnsetICFocus(SDL_IC);
1500
if (SDL_IM != NULL) {
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);
1513
if ( SDL_iconcolors ) {
1514
unsigned long pixel;
1515
Colormap dcmap = DefaultColormap(SDL_Display,
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];
1524
SDL_free(SDL_iconcolors);
1525
SDL_iconcolors = NULL;
1528
/* Restore gamma settings if they've changed */
1529
if ( SDL_GetAppState() & SDL_APPACTIVE ) {
1530
X11_SwapVidModeGamma(this);
1533
/* Free that blank cursor */
1534
if ( SDL_BlankCursor != NULL ) {
1535
this->FreeWMCursor(this, SDL_BlankCursor);
1536
SDL_BlankCursor = NULL;
1539
/* Close the X11 graphics connection */
1540
if ( GFX_Display != NULL ) {
1541
XCloseDisplay(GFX_Display);
1545
/* Close the X11 display connection */
1546
XCloseDisplay(SDL_Display);
1549
/* Reset the X11 error handlers */
1550
if ( XIO_handler ) {
1551
XSetIOErrorHandler(XIO_handler);
1554
XSetErrorHandler(X_handler);
1557
/* Unload GL library after X11 shuts down */
1558
X11_GL_UnloadLibrary(this);
1560
if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) {
1561
/* Direct screen access, no memory buffer */
1562
this->screen->pixels = NULL;
1565
#if SDL_VIDEO_DRIVER_X11_XME