src/video/x11/SDL_x11video.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 27 Aug 2017 19:03:15 -0700
branchSDL-1.2
changeset 11362 464908ca2d22
parent 7491 3665bc284271
child 12653 9b0e5c555c0f
permissions -rw-r--r--
Fixed bug 3770 - XStoreColor returns zero on failure

Thorsten Otto

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