1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 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 /* Utilities for getting and setting the X display mode */
25
26 #include <stdio.h>
27
28 #include "SDL_timer.h"
29 #include "SDL_events.h"
30 #include "../../events/SDL_events_c.h"
31 #include "SDL_x11video.h"
32 #include "SDL_x11wm_c.h"
33 #include "SDL_x11modes_c.h"
34 #include "SDL_x11image_c.h"
35
36 /*#define X11MODES_DEBUG*/
37
38 #define MAX(a, b) (a > b ? a : b)
39
40 #if SDL_VIDEO_DRIVER_X11_XRANDR
cmpmodelist(const void * va,const void * vb)41 static int cmpmodelist(const void *va, const void *vb)
42 {
43 const SDL_Rect *a = *(const SDL_Rect **)va;
44 const SDL_Rect *b = *(const SDL_Rect **)vb;
45 if ( a->w == b->w )
46 return b->h - a->h;
47 else
48 return b->w - a->w;
49 }
50 #endif
51
52 #if SDL_VIDEO_DRIVER_X11_VIDMODE
SDL_NAME(XF86VidModeGetModeInfo)53 Bool SDL_NAME(XF86VidModeGetModeInfo)(Display *dpy, int scr, SDL_NAME(XF86VidModeModeInfo) *info)
54 {
55 SDL_NAME(XF86VidModeModeLine) *l = (SDL_NAME(XF86VidModeModeLine)*)((char*)info + sizeof info->dotclock);
56 return SDL_NAME(XF86VidModeGetModeLine)(dpy, scr, (int*)&info->dotclock, l);
57 }
58 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
59
60 #if SDL_VIDEO_DRIVER_X11_VIDMODE
save_mode(_THIS)61 static void save_mode(_THIS)
62 {
63 SDL_memset(&saved_mode, 0, sizeof(saved_mode));
64 SDL_NAME(XF86VidModeGetModeInfo)(SDL_Display,SDL_Screen,&saved_mode);
65 SDL_NAME(XF86VidModeGetViewPort)(SDL_Display,SDL_Screen,&saved_view.x,&saved_view.y);
66 }
67 #endif
68
69 #if SDL_VIDEO_DRIVER_X11_VIDMODE
restore_mode(_THIS)70 static void restore_mode(_THIS)
71 {
72 SDL_NAME(XF86VidModeModeLine) mode;
73 int unused;
74
75 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
76 if ( (saved_mode.hdisplay != mode.hdisplay) ||
77 (saved_mode.vdisplay != mode.vdisplay) ) {
78 SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, &saved_mode);
79 }
80 }
81 if ( (saved_view.x != 0) || (saved_view.y != 0) ) {
82 SDL_NAME(XF86VidModeSetViewPort)(SDL_Display, SDL_Screen, saved_view.x, saved_view.y);
83 }
84 }
85 #endif
86
87 #if SDL_VIDEO_DRIVER_X11_VIDMODE
cmpmodes(const void * va,const void * vb)88 static int cmpmodes(const void *va, const void *vb)
89 {
90 const SDL_NAME(XF86VidModeModeInfo) *a = *(const SDL_NAME(XF86VidModeModeInfo)**)va;
91 const SDL_NAME(XF86VidModeModeInfo) *b = *(const SDL_NAME(XF86VidModeModeInfo)**)vb;
92 if ( a->hdisplay == b->hdisplay )
93 return b->vdisplay - a->vdisplay;
94 else
95 return b->hdisplay - a->hdisplay;
96 }
97 #endif
98
99 static void get_real_resolution(_THIS, int* w, int* h);
100
set_best_resolution(_THIS,int width,int height)101 static void set_best_resolution(_THIS, int width, int height)
102 {
103 #if SDL_VIDEO_DRIVER_X11_VIDMODE
104 if ( use_vidmode ) {
105 SDL_NAME(XF86VidModeModeLine) mode;
106 SDL_NAME(XF86VidModeModeInfo) **modes;
107 int i;
108 int nmodes;
109 int best = -1;
110
111 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &i, &mode) &&
112 SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display,SDL_Screen,&nmodes,&modes) ) {
113 for ( i = 0; i < nmodes ; i++ ) {
114 if ( (modes[i]->hdisplay == width) &&
115 (modes[i]->vdisplay == height) ) {
116 best = i;
117 break;
118 }
119 if ( modes[i]->hdisplay >= width &&
120 modes[i]->vdisplay >= height ) {
121 if ( best < 0 ||
122 (modes[i]->hdisplay < modes[best]->hdisplay &&
123 modes[i]->vdisplay <= modes[best]->vdisplay) ||
124 (modes[i]->vdisplay < modes[best]->vdisplay &&
125 modes[i]->hdisplay <= modes[best]->hdisplay) ) {
126 best = i;
127 }
128 }
129 }
130 if ( best >= 0 &&
131 ((modes[best]->hdisplay != mode.hdisplay) ||
132 (modes[best]->vdisplay != mode.vdisplay)) ) {
133 #ifdef X11MODES_DEBUG
134 printf("Best Mode %d: %d x %d @ %d\n", best,
135 modes[best]->hdisplay, modes[best]->vdisplay,
136 (modes[best]->htotal && modes[best]->vtotal) ? (1000 * modes[best]->dotclock / (modes[best]->htotal * modes[best]->vtotal)) : 0 );
137 #endif
138 SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, modes[best]);
139 }
140 XFree(modes);
141 }
142 }
143 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
144
145 /* XiG */
146 #if SDL_VIDEO_DRIVER_X11_XME
147 if ( use_xme && SDL_modelist ) {
148 int i;
149
150 #ifdef X11MODES_DEBUG
151 fprintf(stderr, "XME: set_best_resolution(): w = %d, h = %d\n",
152 width, height);
153 #endif
154 for ( i=0; SDL_modelist[i]; ++i ) {
155 if ( (SDL_modelist[i]->w >= width) &&
156 (SDL_modelist[i]->h >= height) ) {
157 break;
158 }
159 }
160
161 if ( SDL_modelist[i] ) { /* found one, lets try it */
162 int w, h;
163
164 /* check current mode so we can avoid uneccessary mode changes */
165 get_real_resolution(this, &w, &h);
166
167 if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) {
168 #ifdef X11MODES_DEBUG
169 fprintf(stderr, "XME: set_best_resolution: "
170 "XiGMiscChangeResolution: %d %d\n",
171 SDL_modelist[i]->w, SDL_modelist[i]->h);
172 #endif
173 XiGMiscChangeResolution(SDL_Display,
174 SDL_Screen,
175 0, /* view */
176 SDL_modelist[i]->w,
177 SDL_modelist[i]->h,
178 0);
179 XSync(SDL_Display, False);
180 }
181 }
182 }
183 #endif /* SDL_VIDEO_DRIVER_X11_XME */
184
185 #if SDL_VIDEO_DRIVER_X11_XRANDR
186 if ( use_xrandr && SDL_modelist ) {
187 #ifdef X11MODES_DEBUG
188 fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n",
189 width, height);
190 #endif
191 int i, nsizes;
192 XRRScreenSize *sizes;
193
194 /* find the smallest resolution that is at least as big as the user requested */
195 sizes = XRRConfigSizes(screen_config, &nsizes);
196 for ( i = (nsizes-1); i >= 0; i-- ) {
197 if ( (SDL_modelist[i]->w >= width) &&
198 (SDL_modelist[i]->h >= height) ) {
199 break;
200 }
201 }
202
203 if ( i >= 0 && SDL_modelist[i] ) { /* found one, lets try it */
204 int w, h;
205
206 /* check current mode so we can avoid uneccessary mode changes */
207 get_real_resolution(this, &w, &h);
208
209 if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) {
210 int size_id;
211
212 #ifdef X11MODES_DEBUG
213 fprintf(stderr, "XRANDR: set_best_resolution: "
214 "XXRSetScreenConfig: %d %d\n",
215 SDL_modelist[i]->w, SDL_modelist[i]->h);
216 #endif
217
218 /* find the matching size entry index */
219 for ( size_id = 0; size_id < nsizes; ++size_id ) {
220 if ( (sizes[size_id].width == SDL_modelist[i]->w) &&
221 (sizes[size_id].height == SDL_modelist[i]->h) )
222 break;
223 }
224
225 XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root,
226 size_id, saved_rotation, CurrentTime);
227 }
228 }
229 }
230 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
231 }
232
get_real_resolution(_THIS,int * w,int * h)233 static void get_real_resolution(_THIS, int* w, int* h)
234 {
235 #if SDL_VIDEO_DRIVER_X11_XME
236 if ( use_xme ) {
237 int ractive;
238 XiGMiscResolutionInfo *modelist;
239
240 XiGMiscQueryResolutions(SDL_Display, SDL_Screen,
241 0, /* view */
242 &ractive, &modelist);
243 *w = modelist[ractive].width;
244 *h = modelist[ractive].height;
245 #ifdef X11MODES_DEBUG
246 fprintf(stderr, "XME: get_real_resolution: w = %d h = %d\n", *w, *h);
247 #endif
248 XFree(modelist);
249 return;
250 }
251 #endif /* SDL_VIDEO_DRIVER_X11_XME */
252
253 #if SDL_VIDEO_DRIVER_X11_VIDMODE
254 if ( use_vidmode ) {
255 SDL_NAME(XF86VidModeModeLine) mode;
256 int unused;
257
258 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
259 *w = mode.hdisplay;
260 *h = mode.vdisplay;
261 return;
262 }
263 }
264 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
265
266 #if SDL_VIDEO_DRIVER_X11_XRANDR
267 if ( use_xrandr ) {
268 int nsizes;
269 XRRScreenSize* sizes;
270
271 sizes = XRRConfigSizes(screen_config, &nsizes);
272 if ( nsizes > 0 ) {
273 int cur_size;
274 Rotation cur_rotation;
275
276 cur_size = XRRConfigCurrentConfiguration(screen_config, &cur_rotation);
277 if ( cur_size >= 0 && cur_size < nsizes ) {
278 *w = sizes[cur_size].width;
279 *h = sizes[cur_size].height;
280 }
281 #ifdef X11MODES_DEBUG
282 fprintf(stderr, "XRANDR: get_real_resolution: w = %d h = %d\n", *w, *h);
283 #endif
284 return;
285 }
286 }
287 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
288
289 #if SDL_VIDEO_DRIVER_X11_XINERAMA
290 if ( use_xinerama ) {
291 *w = xinerama_info.width;
292 *h = xinerama_info.height;
293 return;
294 }
295 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
296
297 *w = DisplayWidth(SDL_Display, SDL_Screen);
298 *h = DisplayHeight(SDL_Display, SDL_Screen);
299 }
300
301 /* Called after mapping a window - waits until the window is mapped */
X11_WaitMapped(_THIS,Window win)302 void X11_WaitMapped(_THIS, Window win)
303 {
304 XEvent event;
305 do {
306 XMaskEvent(SDL_Display, StructureNotifyMask, &event);
307 } while ( (event.type != MapNotify) || (event.xmap.event != win) );
308 }
309
310 /* Called after unmapping a window - waits until the window is unmapped */
X11_WaitUnmapped(_THIS,Window win)311 void X11_WaitUnmapped(_THIS, Window win)
312 {
313 XEvent event;
314 do {
315 XMaskEvent(SDL_Display, StructureNotifyMask, &event);
316 } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) );
317 }
318
move_cursor_to(_THIS,int x,int y)319 static void move_cursor_to(_THIS, int x, int y)
320 {
321 XWarpPointer(SDL_Display, None, SDL_Root, 0, 0, 0, 0, x, y);
322 }
323
add_visual(_THIS,int depth,int class)324 static int add_visual(_THIS, int depth, int class)
325 {
326 XVisualInfo vi;
327 if(XMatchVisualInfo(SDL_Display, SDL_Screen, depth, class, &vi)) {
328 int n = this->hidden->nvisuals;
329 this->hidden->visuals[n].depth = vi.depth;
330 this->hidden->visuals[n].visual = vi.visual;
331 this->hidden->nvisuals++;
332 }
333 return(this->hidden->nvisuals);
334 }
add_visual_byid(_THIS,const char * visual_id)335 static int add_visual_byid(_THIS, const char *visual_id)
336 {
337 XVisualInfo *vi, template;
338 int nvis;
339
340 if ( visual_id ) {
341 SDL_memset(&template, 0, (sizeof template));
342 template.visualid = SDL_strtol(visual_id, NULL, 0);
343 vi = XGetVisualInfo(SDL_Display, VisualIDMask, &template, &nvis);
344 if ( vi ) {
345 int n = this->hidden->nvisuals;
346 this->hidden->visuals[n].depth = vi->depth;
347 this->hidden->visuals[n].visual = vi->visual;
348 this->hidden->nvisuals++;
349 XFree(vi);
350 }
351 }
352 return(this->hidden->nvisuals);
353 }
354
355 /* Global for the error handler */
356 int vm_event, vm_error = -1;
357
358 #if SDL_VIDEO_DRIVER_X11_XINERAMA
CheckXinerama(_THIS,int * major,int * minor)359 static int CheckXinerama(_THIS, int *major, int *minor)
360 {
361 const char *env;
362
363 /* Default the extension not available */
364 *major = *minor = 0;
365
366 /* Allow environment override */
367 env = getenv("SDL_VIDEO_X11_XINERAMA");
368 if ( env && !SDL_atoi(env) ) {
369 return 0;
370 }
371
372 /* Query the extension version */
373 if ( !SDL_NAME(XineramaQueryExtension)(SDL_Display, major, minor) ||
374 !SDL_NAME(XineramaIsActive)(SDL_Display) ) {
375 return 0;
376 }
377 return 1;
378 }
379 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
380
381 #if SDL_VIDEO_DRIVER_X11_XRANDR
CheckXRandR(_THIS,int * major,int * minor)382 static int CheckXRandR(_THIS, int *major, int *minor)
383 {
384 const char *env;
385
386 /* Default the extension not available */
387 *major = *minor = 0;
388
389 /* Allow environment override */
390 env = getenv("SDL_VIDEO_X11_XRANDR");
391 if ( env && !SDL_atoi(env) ) {
392 return 0;
393 }
394
395 /* This defaults off now, due to KDE window maximize problems */
396 if ( !env ) {
397 return 0;
398 }
399
400 if ( !SDL_X11_HAVE_XRANDR ) {
401 return 0;
402 }
403
404 /* Query the extension version */
405 if ( !XRRQueryVersion(SDL_Display, major, minor) ) {
406 return 0;
407 }
408 return 1;
409 }
410 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
411
412 #if SDL_VIDEO_DRIVER_X11_VIDMODE
CheckVidMode(_THIS,int * major,int * minor)413 static int CheckVidMode(_THIS, int *major, int *minor)
414 {
415 const char *env;
416
417 /* Default the extension not available */
418 *major = *minor = 0;
419
420 /* Allow environment override */
421 env = getenv("SDL_VIDEO_X11_VIDMODE");
422 if ( env && !SDL_atoi(env) ) {
423 return 0;
424 }
425
426 /* Metro-X 4.3.0 and earlier has a broken implementation of
427 XF86VidModeGetAllModeLines() - it hangs the client.
428 */
429 if ( SDL_strcmp(ServerVendor(SDL_Display), "Metro Link Incorporated") == 0 ) {
430 FILE *metro_fp;
431
432 metro_fp = fopen("/usr/X11R6/lib/X11/Metro/.version", "r");
433 if ( metro_fp != NULL ) {
434 int major, minor, patch, version;
435 major = 0; minor = 0; patch = 0;
436 fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch);
437 fclose(metro_fp);
438 version = major*100+minor*10+patch;
439 if ( version < 431 ) {
440 return 0;
441 }
442 }
443 }
444
445 /* Query the extension version */
446 vm_error = -1;
447 if ( !SDL_NAME(XF86VidModeQueryExtension)(SDL_Display, &vm_event, &vm_error) ||
448 !SDL_NAME(XF86VidModeQueryVersion)(SDL_Display, major, minor) ) {
449 return 0;
450 }
451 return 1;
452 }
453 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
454
455 #if SDL_VIDEO_DRIVER_X11_XME
CheckXME(_THIS,int * major,int * minor)456 static int CheckXME(_THIS, int *major, int *minor)
457 {
458 const char *env;
459
460 /* Default the extension not available */
461 *major = *minor = 0;
462
463 /* Allow environment override */
464 env = getenv("SDL_VIDEO_X11_VIDMODE");
465 if ( env && !SDL_atoi(env) ) {
466 return 0;
467 }
468
469 /* Query the extension version */
470 if ( !XiGMiscQueryVersion(SDL_Display, major, minor) ) {
471 return 0;
472 }
473 return 1;
474 }
475 #endif /* SDL_VIDEO_DRIVER_X11_XME */
476
X11_GetVideoModes(_THIS)477 int X11_GetVideoModes(_THIS)
478 {
479 #if SDL_VIDEO_DRIVER_X11_XINERAMA
480 int xinerama_major, xinerama_minor;
481 #endif
482 #if SDL_VIDEO_DRIVER_X11_XRANDR
483 int xrandr_major, xrandr_minor;
484 int nsizes;
485 XRRScreenSize *sizes;
486 #endif
487 #if SDL_VIDEO_DRIVER_X11_VIDMODE
488 int vm_major, vm_minor;
489 int nmodes;
490 SDL_NAME(XF86VidModeModeInfo) **modes;
491 #endif
492 #if SDL_VIDEO_DRIVER_X11_XME
493 int xme_major, xme_minor;
494 int ractive, nummodes;
495 XiGMiscResolutionInfo *modelist;
496 #endif
497 int i, n;
498 int screen_w;
499 int screen_h;
500
501 use_xinerama = 0;
502 use_xrandr = 0;
503 use_vidmode = 0;
504 use_xme = 0;
505 screen_w = DisplayWidth(SDL_Display, SDL_Screen);
506 screen_h = DisplayHeight(SDL_Display, SDL_Screen);
507
508 #if SDL_VIDEO_DRIVER_X11_XINERAMA
509 /* Query Xinerama extention */
510 if ( CheckXinerama(this, &xinerama_major, &xinerama_minor) ) {
511 /* Find out which screen is the desired one */
512 int desired = 0;
513 int screens;
514 int w, h;
515 SDL_NAME(XineramaScreenInfo) *xinerama;
516
517 const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD");
518 if ( variable ) {
519 desired = SDL_atoi(variable);
520 }
521 #ifdef X11MODES_DEBUG
522 printf("X11 detected Xinerama:\n");
523 #endif
524 xinerama = SDL_NAME(XineramaQueryScreens)(SDL_Display, &screens);
525 for ( i = 0; i < screens; i++ ) {
526 #ifdef X11MODES_DEBUG
527 printf("xinerama %d: %dx%d+%d+%d\n",
528 xinerama[i].screen_number,
529 xinerama[i].width, xinerama[i].height,
530 xinerama[i].x_org, xinerama[i].y_org);
531 #endif
532 if ( xinerama[i].screen_number == desired ) {
533 use_xinerama = 1;
534 xinerama_info = xinerama[i];
535 }
536 }
537 XFree(xinerama);
538
539 if ( use_xinerama ) {
540 SDL_modelist = (SDL_Rect **)SDL_malloc(3*sizeof(SDL_Rect *));
541 if ( !SDL_modelist ) {
542 SDL_OutOfMemory();
543 return -1;
544 }
545
546 /* Add the full xinerama mode */
547 n = 0;
548 w = xinerama_info.width;
549 h = xinerama_info.height;
550 if ( screen_w > w || screen_h > h) {
551 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
552 if ( SDL_modelist[n] ) {
553 SDL_modelist[n]->x = 0;
554 SDL_modelist[n]->y = 0;
555 SDL_modelist[n]->w = screen_w;
556 SDL_modelist[n]->h = screen_h;
557 ++n;
558 }
559 }
560
561 /* Add the head xinerama mode */
562 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
563 if ( SDL_modelist[n] ) {
564 SDL_modelist[n]->x = 0;
565 SDL_modelist[n]->y = 0;
566 SDL_modelist[n]->w = w;
567 SDL_modelist[n]->h = h;
568 ++n;
569 }
570 SDL_modelist[n] = NULL;
571 }
572 }
573 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
574
575 #if SDL_VIDEO_DRIVER_X11_XRANDR
576 /* XRandR */
577 /* require at least XRandR v1.0 (arbitrary) */
578 if ( CheckXRandR(this, &xrandr_major, &xrandr_minor) && (xrandr_major >= 1) )
579 {
580 #ifdef X11MODES_DEBUG
581 fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n",
582 xrandr_major, xrandr_minor);
583 #endif
584
585 /* save the screen configuration since we must reference it
586 each time we toggle modes.
587 */
588 screen_config = XRRGetScreenInfo(SDL_Display, SDL_Root);
589
590 /* retrieve the list of resolution */
591 sizes = XRRConfigSizes(screen_config, &nsizes);
592 if (nsizes > 0) {
593 if ( SDL_modelist ) {
594 for ( i = 0; SDL_modelist[i]; ++i ) {
595 SDL_free(SDL_modelist[i]);
596 }
597 SDL_free(SDL_modelist);
598 }
599 SDL_modelist = (SDL_Rect **)malloc((nsizes+1)*sizeof(SDL_Rect *));
600 if ( !SDL_modelist ) {
601 SDL_OutOfMemory();
602 return -1;
603 }
604 for ( i=0; i < nsizes; i++ ) {
605 if ((SDL_modelist[i] =
606 (SDL_Rect *)malloc(sizeof(SDL_Rect))) == NULL)
607 break;
608 #ifdef X11MODES_DEBUG
609 fprintf(stderr, "XRANDR: mode = %4d, w = %4d, h = %4d\n",
610 i, sizes[i].width, sizes[i].height);
611 #endif
612
613 SDL_modelist[i]->x = 0;
614 SDL_modelist[i]->y = 0;
615 SDL_modelist[i]->w = sizes[i].width;
616 SDL_modelist[i]->h = sizes[i].height;
617
618 }
619 /* sort the mode list descending as SDL expects */
620 SDL_qsort(SDL_modelist, nsizes, sizeof *SDL_modelist, cmpmodelist);
621 SDL_modelist[i] = NULL; /* terminator */
622
623 use_xrandr = xrandr_major * 100 + xrandr_minor;
624 saved_size_id = XRRConfigCurrentConfiguration(screen_config, &saved_rotation);
625 }
626 }
627 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
628
629 #if SDL_VIDEO_DRIVER_X11_VIDMODE
630 /* XVidMode */
631 if ( !use_xrandr &&
632 #if SDL_VIDEO_DRIVER_X11_XINERAMA
633 (!use_xinerama || xinerama_info.screen_number == 0) &&
634 #endif
635 CheckVidMode(this, &vm_major, &vm_minor) &&
636 SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) )
637 {
638 #ifdef X11MODES_DEBUG
639 printf("VidMode modes: (unsorted)\n");
640 for ( i = 0; i < nmodes; ++i ) {
641 printf("Mode %d: %d x %d @ %d\n", i,
642 modes[i]->hdisplay, modes[i]->vdisplay,
643 (modes[i]->htotal && modes[i]->vtotal) ? (1000 * modes[i]->dotclock / (modes[i]->htotal * modes[i]->vtotal)) : 0 );
644 }
645 #endif
646 if ( SDL_modelist ) {
647 for ( i = 0; SDL_modelist[i]; ++i ) {
648 SDL_free(SDL_modelist[i]);
649 }
650 SDL_free(SDL_modelist);
651 }
652 SDL_modelist = (SDL_Rect **)SDL_malloc((nmodes+2)*sizeof(SDL_Rect *));
653 if ( !SDL_modelist ) {
654 SDL_OutOfMemory();
655 return -1;
656 }
657 SDL_qsort(modes, nmodes, sizeof *modes, cmpmodes);
658 n = 0;
659 for ( i=0; i<nmodes; ++i ) {
660 int w, h;
661
662 /* Eliminate duplicate modes with different refresh rates */
663 if ( i > 0 &&
664 modes[i]->hdisplay == modes[i-1]->hdisplay &&
665 modes[i]->vdisplay == modes[i-1]->vdisplay ) {
666 continue;
667 }
668
669 /* Check to see if we should add the screen size (Xinerama) */
670 w = modes[i]->hdisplay;
671 h = modes[i]->vdisplay;
672 if ( (screen_w * screen_h) >= (w * h) ) {
673 if ( (screen_w != w) || (screen_h != h) ) {
674 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
675 if ( SDL_modelist[n] ) {
676 SDL_modelist[n]->x = 0;
677 SDL_modelist[n]->y = 0;
678 SDL_modelist[n]->w = screen_w;
679 SDL_modelist[n]->h = screen_h;
680 ++n;
681 }
682 }
683 screen_w = 0;
684 screen_h = 0;
685 }
686
687 /* Add the size from the video mode list */
688 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
689 if ( SDL_modelist[n] == NULL ) {
690 break;
691 }
692 SDL_modelist[n]->x = 0;
693 SDL_modelist[n]->y = 0;
694 SDL_modelist[n]->w = w;
695 SDL_modelist[n]->h = h;
696 ++n;
697 }
698 SDL_modelist[n] = NULL;
699 XFree(modes);
700
701 use_vidmode = vm_major * 100 + vm_minor;
702 save_mode(this);
703 }
704 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
705
706 #if SDL_VIDEO_DRIVER_X11_XME
707 /* XiG */
708 modelist = NULL;
709 /* first lets make sure we have the extension, and it's at least v2.0 */
710 if ( CheckXME(this, &xme_major, &xme_minor) && xme_major >= 2 &&
711 (nummodes = XiGMiscQueryResolutions(SDL_Display, SDL_Screen,
712 0, /* view */
713 &ractive, &modelist)) > 1 )
714 { /* then we actually have some */
715 int j;
716
717 /* We get the list already sorted in descending order.
718 We'll copy it in reverse order so SDL is happy */
719 #ifdef X11MODES_DEBUG
720 fprintf(stderr, "XME: nummodes = %d, active mode = %d\n",
721 nummodes, ractive);
722 #endif
723 if ( SDL_modelist ) {
724 for ( i = 0; SDL_modelist[i]; ++i ) {
725 SDL_free(SDL_modelist[i]);
726 }
727 SDL_free(SDL_modelist);
728 }
729 SDL_modelist = (SDL_Rect **)SDL_malloc((nummodes+1)*sizeof(SDL_Rect *));
730 if ( !SDL_modelist ) {
731 SDL_OutOfMemory();
732 return -1;
733 }
734 for ( i=0, j=nummodes-1; j>=0; i++, j-- ) {
735 if ((SDL_modelist[i] =
736 (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect))) == NULL)
737 break;
738 #ifdef X11MODES_DEBUG
739 fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n",
740 i, modelist[i].width, modelist[i].height);
741 #endif
742
743 SDL_modelist[i]->x = 0;
744 SDL_modelist[i]->y = 0;
745 SDL_modelist[i]->w = modelist[j].width;
746 SDL_modelist[i]->h = modelist[j].height;
747
748 }
749 SDL_modelist[i] = NULL; /* terminator */
750
751 use_xme = xme_major * 100 + xme_minor;
752 saved_res = modelist[ractive]; /* save the current resolution */
753 }
754 if ( modelist ) {
755 XFree(modelist);
756 }
757 #endif /* SDL_VIDEO_DRIVER_X11_XME */
758
759 {
760 /* It's interesting to note that if we allow 32 bit depths,
761 we get a visual with an alpha mask on composite servers.
762 static int depth_list[] = { 32, 24, 16, 15, 8 };
763 */
764 static int depth_list[] = { 24, 16, 15, 8 };
765 int j, np;
766 int use_directcolor = 1;
767 XPixmapFormatValues *pf;
768
769 /* Search for the visuals in deepest-first order, so that the first
770 will be the richest one */
771 if ( SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) {
772 use_directcolor = 0;
773 }
774 this->hidden->nvisuals = 0;
775 if ( ! add_visual_byid(this, SDL_getenv("SDL_VIDEO_X11_VISUALID")) ) {
776 for ( i=0; i<SDL_arraysize(depth_list); ++i ) {
777 if ( depth_list[i] > 8 ) {
778 if ( use_directcolor ) {
779 add_visual(this, depth_list[i], DirectColor);
780 }
781 add_visual(this, depth_list[i], TrueColor);
782 } else {
783 add_visual(this, depth_list[i], PseudoColor);
784 add_visual(this, depth_list[i], StaticColor);
785 }
786 }
787 }
788 if ( this->hidden->nvisuals == 0 ) {
789 SDL_SetError("Found no sufficiently capable X11 visuals");
790 return -1;
791 }
792
793 /* look up the pixel quantum for each depth */
794 pf = XListPixmapFormats(SDL_Display, &np);
795 for(i = 0; i < this->hidden->nvisuals; i++) {
796 int d = this->hidden->visuals[i].depth;
797 for(j = 0; j < np; j++)
798 if(pf[j].depth == d)
799 break;
800 this->hidden->visuals[i].bpp = j < np ? pf[j].bits_per_pixel : d;
801 }
802
803 XFree(pf);
804 }
805
806 if ( SDL_modelist == NULL ) {
807 SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *));
808 if ( !SDL_modelist ) {
809 SDL_OutOfMemory();
810 return -1;
811 }
812 n = 0;
813 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
814 if ( SDL_modelist[n] ) {
815 SDL_modelist[n]->x = 0;
816 SDL_modelist[n]->y = 0;
817 SDL_modelist[n]->w = screen_w;
818 SDL_modelist[n]->h = screen_h;
819 ++n;
820 }
821 SDL_modelist[n] = NULL;
822 }
823
824 #ifdef X11MODES_DEBUG
825 if ( use_xinerama ) {
826 printf("Xinerama is enabled\n");
827 }
828
829 if ( use_xrandr ) {
830 printf("XRandR is enabled\n");
831 }
832
833 if ( use_vidmode ) {
834 printf("VidMode is enabled\n");
835 }
836
837 if ( use_xme ) {
838 printf("Xi Graphics XME fullscreen is enabled\n");
839 }
840
841 if ( SDL_modelist ) {
842 printf("X11 video mode list:\n");
843 for ( i=0; SDL_modelist[i]; ++i ) {
844 printf("\t%dx%d\n", SDL_modelist[i]->w, SDL_modelist[i]->h);
845 }
846 }
847 #endif /* X11MODES_DEBUG */
848
849 return 0;
850 }
851
X11_SupportedVisual(_THIS,SDL_PixelFormat * format)852 int X11_SupportedVisual(_THIS, SDL_PixelFormat *format)
853 {
854 int i;
855 for(i = 0; i < this->hidden->nvisuals; i++)
856 if(this->hidden->visuals[i].bpp == format->BitsPerPixel)
857 return 1;
858 return 0;
859 }
860
X11_ListModes(_THIS,SDL_PixelFormat * format,Uint32 flags)861 SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
862 {
863 if ( X11_SupportedVisual(this, format) ) {
864 if ( flags & SDL_FULLSCREEN ) {
865 return(SDL_modelist);
866 } else {
867 return((SDL_Rect **)-1);
868 }
869 } else {
870 return((SDL_Rect **)0);
871 }
872 }
873
X11_FreeVideoModes(_THIS)874 void X11_FreeVideoModes(_THIS)
875 {
876 int i;
877
878 if ( SDL_modelist ) {
879 for ( i=0; SDL_modelist[i]; ++i ) {
880 SDL_free(SDL_modelist[i]);
881 }
882 SDL_free(SDL_modelist);
883 SDL_modelist = NULL;
884 }
885
886 #if SDL_VIDEO_DRIVER_X11_XRANDR
887 /* Free the Xrandr screen configuration */
888 if ( screen_config ) {
889 XRRFreeScreenConfigInfo(screen_config);
890 screen_config = NULL;
891 }
892 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
893 }
894
X11_ResizeFullScreen(_THIS)895 int X11_ResizeFullScreen(_THIS)
896 {
897 int x = 0, y = 0;
898 int real_w, real_h;
899 int screen_w;
900 int screen_h;
901
902 screen_w = DisplayWidth(SDL_Display, SDL_Screen);
903 screen_h = DisplayHeight(SDL_Display, SDL_Screen);
904
905 #if SDL_VIDEO_DRIVER_X11_XINERAMA
906 if ( use_xinerama &&
907 window_w <= xinerama_info.width &&
908 window_h <= xinerama_info.height ) {
909 x = xinerama_info.x_org;
910 y = xinerama_info.y_org;
911 }
912 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
913
914 if ( currently_fullscreen ) {
915 /* Switch resolution and cover it with the FSwindow */
916 move_cursor_to(this, x, y);
917 set_best_resolution(this, window_w, window_h);
918 move_cursor_to(this, x, y);
919 get_real_resolution(this, &real_w, &real_h);
920 if ( window_w > real_w ) {
921 real_w = MAX(real_w, screen_w);
922 }
923 if ( window_h > real_h ) {
924 real_h = MAX(real_h, screen_h);
925 }
926 XMoveResizeWindow(SDL_Display, FSwindow, x, y, real_w, real_h);
927 move_cursor_to(this, real_w/2, real_h/2);
928
929 /* Center and reparent the drawing window */
930 x = (real_w - window_w)/2;
931 y = (real_h - window_h)/2;
932 XReparentWindow(SDL_Display, SDL_Window, FSwindow, x, y);
933 /* FIXME: move the mouse to the old relative location */
934 XSync(SDL_Display, True); /* Flush spurious mode change events */
935 }
936 return(1);
937 }
938
X11_QueueEnterFullScreen(_THIS)939 void X11_QueueEnterFullScreen(_THIS)
940 {
941 switch_waiting = 0x01 | SDL_FULLSCREEN;
942 switch_time = SDL_GetTicks() + 1500;
943 #if 0 /* This causes a BadMatch error if the window is iconified (not needed) */
944 XSetInputFocus(SDL_Display, WMwindow, RevertToNone, CurrentTime);
945 #endif
946 }
947
X11_EnterFullScreen(_THIS)948 int X11_EnterFullScreen(_THIS)
949 {
950 int okay;
951 #if 0
952 Window tmpwin, *windows;
953 int i, nwindows;
954 #endif
955 int x = 0, y = 0;
956 int real_w, real_h;
957 int screen_w;
958 int screen_h;
959
960 okay = 1;
961 if ( currently_fullscreen ) {
962 return(okay);
963 }
964
965 /* Ungrab the input so that we can move the mouse around */
966 X11_GrabInputNoLock(this, SDL_GRAB_OFF);
967
968 #if SDL_VIDEO_DRIVER_X11_XINERAMA
969 if ( use_xinerama &&
970 window_w <= xinerama_info.width &&
971 window_h <= xinerama_info.height ) {
972 x = xinerama_info.x_org;
973 y = xinerama_info.y_org;
974 }
975 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
976
977 /* Map the fullscreen window to blank the screen */
978 screen_w = DisplayWidth(SDL_Display, SDL_Screen);
979 screen_h = DisplayHeight(SDL_Display, SDL_Screen);
980 get_real_resolution(this, &real_w, &real_h);
981 if ( window_w > real_w ) {
982 real_w = MAX(real_w, screen_w);
983 }
984 if ( window_h > real_h ) {
985 real_h = MAX(real_h, screen_h);
986 }
987 XMoveResizeWindow(SDL_Display, FSwindow,
988 x, y, real_w, real_h);
989 XMapRaised(SDL_Display, FSwindow);
990 X11_WaitMapped(this, FSwindow);
991
992 #if 0 /* This seems to break WindowMaker in focus-follows-mouse mode */
993 /* Make sure we got to the top of the window stack */
994 if ( XQueryTree(SDL_Display, SDL_Root, &tmpwin, &tmpwin,
995 &windows, &nwindows) && windows ) {
996 /* If not, try to put us there - if fail... oh well */
997 if ( windows[nwindows-1] != FSwindow ) {
998 tmpwin = windows[nwindows-1];
999 for ( i=0; i<nwindows; ++i ) {
1000 if ( windows[i] == FSwindow ) {
1001 SDL_memcpy(&windows[i], &windows[i+1],
1002 (nwindows-i-1)*sizeof(windows[i]));
1003 break;
1004 }
1005 }
1006 windows[nwindows-1] = FSwindow;
1007 XRestackWindows(SDL_Display, windows, nwindows);
1008 XSync(SDL_Display, False);
1009 }
1010 XFree(windows);
1011 }
1012 #else
1013 XRaiseWindow(SDL_Display, FSwindow);
1014 #endif
1015
1016 #if SDL_VIDEO_DRIVER_X11_VIDMODE
1017 /* Save the current video mode */
1018 if ( use_vidmode ) {
1019 SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, True);
1020 }
1021 #endif
1022 currently_fullscreen = 1;
1023
1024 /* Set the new resolution */
1025 okay = X11_ResizeFullScreen(this);
1026 if ( ! okay ) {
1027 X11_LeaveFullScreen(this);
1028 }
1029 /* Set the colormap */
1030 if ( SDL_XColorMap ) {
1031 XInstallColormap(SDL_Display, SDL_XColorMap);
1032 }
1033 if ( okay ) {
1034 X11_GrabInputNoLock(this, this->input_grab | SDL_GRAB_FULLSCREEN);
1035 }
1036
1037 /* We may need to refresh the screen at this point (no backing store)
1038 We also don't get an event, which is why we explicitly refresh. */
1039 if ( this->screen ) {
1040 if ( this->screen->flags & SDL_OPENGL ) {
1041 SDL_PrivateExpose();
1042 } else {
1043 X11_RefreshDisplay(this);
1044 }
1045 }
1046
1047 return(okay);
1048 }
1049
X11_LeaveFullScreen(_THIS)1050 int X11_LeaveFullScreen(_THIS)
1051 {
1052 if ( currently_fullscreen ) {
1053 XReparentWindow(SDL_Display, SDL_Window, WMwindow, 0, 0);
1054 #if SDL_VIDEO_DRIVER_X11_VIDMODE
1055 if ( use_vidmode ) {
1056 restore_mode(this);
1057 SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False);
1058 }
1059 #endif
1060
1061 #if SDL_VIDEO_DRIVER_X11_XME
1062 if ( use_xme ) {
1063 int rw, rh;
1064
1065 /* check current mode so we can avoid uneccessary mode changes */
1066 get_real_resolution(this, &rw, &rh);
1067
1068 if (rw != saved_res.width || rh != saved_res.height) {
1069 XiGMiscChangeResolution(SDL_Display,
1070 SDL_Screen,
1071 0, /* view */
1072 saved_res.width,
1073 saved_res.height,
1074 0);
1075 XSync(SDL_Display, False);
1076 }
1077 }
1078 #endif
1079
1080 #if SDL_VIDEO_DRIVER_X11_XRANDR
1081 if ( use_xrandr ) {
1082 XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root,
1083 saved_size_id, saved_rotation, CurrentTime);
1084 }
1085 #endif
1086
1087 XUnmapWindow(SDL_Display, FSwindow);
1088 X11_WaitUnmapped(this, FSwindow);
1089 XSync(SDL_Display, True); /* Flush spurious mode change events */
1090 currently_fullscreen = 0;
1091 }
1092 /* If we get popped out of fullscreen mode for some reason, input_grab
1093 will still have the SDL_GRAB_FULLSCREEN flag set, since this is only
1094 temporary. In this case, release the grab unless the input has been
1095 explicitly grabbed.
1096 */
1097 X11_GrabInputNoLock(this, this->input_grab & ~SDL_GRAB_FULLSCREEN);
1098
1099 /* We may need to refresh the screen at this point (no backing store)
1100 We also don't get an event, which is why we explicitly refresh. */
1101 if ( this->screen ) {
1102 if ( this->screen->flags & SDL_OPENGL ) {
1103 SDL_PrivateExpose();
1104 } else {
1105 X11_RefreshDisplay(this);
1106 }
1107 }
1108
1109 return(0);
1110 }
1111