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