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