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 
X11_Available(void)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 
X11_DeleteDevice(SDL_VideoDevice * device)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 
X11_CreateDevice(int devindex)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;
x_errhandler(Display * d,XErrorEvent * e)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;
xio_errhandler(Display * d)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;
xext_errhandler(Display * d,_Xconst char * ext,_Xconst char * reason)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 */
get_classname(char * classname,int maxlen)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 */
create_aux_windows(_THIS)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 
X11_VideoInit(_THIS,SDL_PixelFormat * vformat)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 
X11_DestroyWindow(_THIS,SDL_Surface * screen)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 
X11_WindowPosition(_THIS,int * x,int * y,int w,int h)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 
X11_SetSizeHints(_THIS,int w,int h,Uint32 flags)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 
X11_CreateWindow(_THIS,SDL_Surface * screen,int w,int h,int bpp,Uint32 flags)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 
X11_ResizeWindow(_THIS,SDL_Surface * screen,int w,int h,Uint32 flags)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 
X11_SetVideoMode(_THIS,SDL_Surface * current,int width,int height,int bpp,Uint32 flags)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 
X11_ToggleFullScreen(_THIS,int on)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 */
X11_UpdateMouse(_THIS)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 
allocate_nearest(_THIS,SDL_Color * colors,SDL_Color * want,int nwant)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 
X11_SetColors(_THIS,int firstcolor,int ncolors,SDL_Color * colors)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 
X11_SetGammaRamp(_THIS,Uint16 * ramp)1463 int X11_SetGammaRamp(_THIS, Uint16 *ramp)
1464 {
1465 	int i, 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 	XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
1485 	XSync(GFX_Display, False);
1486 	return(0);
1487 }
1488 
1489 /* Note:  If we are terminated, this could be called in the middle of
1490    another SDL video routine -- notably UpdateRects.
1491 */
X11_VideoQuit(_THIS)1492 void X11_VideoQuit(_THIS)
1493 {
1494 	/* Shutdown everything that's still up */
1495 	/* The event thread should be done, so we can touch SDL_Display */
1496 	if ( SDL_Display != NULL ) {
1497 		/* Flush any delayed updates */
1498 		XSync(GFX_Display, False);
1499 
1500 		/* Close the connection with the IM server */
1501 		#ifdef X_HAVE_UTF8_STRING
1502 		if (SDL_IC != NULL) {
1503 			XUnsetICFocus(SDL_IC);
1504 			XDestroyIC(SDL_IC);
1505 			SDL_IC = NULL;
1506 		}
1507 		if (SDL_IM != NULL) {
1508 			XCloseIM(SDL_IM);
1509 			SDL_IM = NULL;
1510 		}
1511 		#endif
1512 
1513 		/* Start shutting down the windows */
1514 		X11_DestroyImage(this, this->screen);
1515 		X11_DestroyWindow(this, this->screen);
1516 		X11_FreeVideoModes(this);
1517 		if ( SDL_XColorMap != SDL_DisplayColormap ) {
1518 			XFreeColormap(SDL_Display, SDL_XColorMap);
1519 		}
1520 		if ( SDL_iconcolors ) {
1521 			unsigned long pixel;
1522 			Colormap dcmap = DefaultColormap(SDL_Display,
1523 							 SDL_Screen);
1524 			for(pixel = 0; pixel < 256; ++pixel) {
1525 				while(SDL_iconcolors[pixel] > 0) {
1526 					XFreeColors(GFX_Display,
1527 						    dcmap, &pixel, 1, 0);
1528 					--SDL_iconcolors[pixel];
1529 				}
1530 			}
1531 			SDL_free(SDL_iconcolors);
1532 			SDL_iconcolors = NULL;
1533 		}
1534 
1535 		/* Restore gamma settings if they've changed */
1536 		if ( SDL_GetAppState() & SDL_APPACTIVE ) {
1537 			X11_SwapVidModeGamma(this);
1538 		}
1539 
1540 		/* Free that blank cursor */
1541 		if ( SDL_BlankCursor != NULL ) {
1542 			this->FreeWMCursor(this, SDL_BlankCursor);
1543 			SDL_BlankCursor = NULL;
1544 		}
1545 
1546 		/* Close the X11 graphics connection */
1547 		if ( GFX_Display != NULL ) {
1548 			XCloseDisplay(GFX_Display);
1549 			GFX_Display = NULL;
1550 		}
1551 
1552 		/* Close the X11 display connection */
1553 		XCloseDisplay(SDL_Display);
1554 		SDL_Display = NULL;
1555 
1556 		/* Reset the X11 error handlers */
1557 		if ( XIO_handler ) {
1558 			XSetIOErrorHandler(XIO_handler);
1559 		}
1560 		if ( X_handler ) {
1561 			XSetErrorHandler(X_handler);
1562 		}
1563 
1564 		/* Unload GL library after X11 shuts down */
1565 		X11_GL_UnloadLibrary(this);
1566 	}
1567 	if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) {
1568 		/* Direct screen access, no memory buffer */
1569 		this->screen->pixels = NULL;
1570 	}
1571 
1572 #if SDL_VIDEO_DRIVER_X11_XME
1573     XiGMiscDestroy();
1574 #endif
1575 }
1576 
1577