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