• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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