src/video/x11/SDL_x11video.c
author Ryan C. Gordon
Tue, 29 Sep 2009 13:50:33 +0000
branchSDL-1.2
changeset 4268 d48035d857d3
parent 4266 62849663f20a
child 4278 010efca83dfc
permissions -rw-r--r--
Make SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL) work with GLX_SGI_swap_control.

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