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, ¤t_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