src/video/x11/SDL_x11modes.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 22 Mar 2006 05:00:59 +0000
changeset 1575 3ba88cb7eb1b
parent 1545 8d9bb0cf2c2a
child 1589 34cca785be57
permissions -rw-r--r--
Updated dynamic X11 code. See details in Bugzilla #170.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* Utilities for getting and setting the X display mode */
slouken@0
    25
slouken@1338
    26
#include <stdio.h>
slouken@0
    27
slouken@0
    28
#include "SDL_timer.h"
slouken@0
    29
#include "SDL_events.h"
slouken@1361
    30
#include "../../events/SDL_events_c.h"
slouken@0
    31
#include "SDL_x11video.h"
slouken@0
    32
#include "SDL_x11wm_c.h"
slouken@0
    33
#include "SDL_x11modes_c.h"
slouken@88
    34
#include "SDL_x11image_c.h"
slouken@0
    35
slouken@1361
    36
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@1361
    37
#include "../Xext/extensions/Xinerama.h"
slouken@227
    38
#endif 
slouken@0
    39
slouken@499
    40
#define MAX(a, b)        (a > b ? a : b)
slouken@230
    41
slouken@1361
    42
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@292
    43
Bool SDL_NAME(XF86VidModeGetModeInfo)(Display *dpy, int scr, SDL_NAME(XF86VidModeModeInfo) *info)
slouken@0
    44
{
slouken@292
    45
    SDL_NAME(XF86VidModeModeLine) *l = (SDL_NAME(XF86VidModeModeLine)*)((char*)info + sizeof info->dotclock);
slouken@1196
    46
    return SDL_NAME(XF86VidModeGetModeLine)(dpy, scr, (int*)&info->dotclock, l);
slouken@0
    47
}
slouken@1361
    48
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@0
    49
slouken@1361
    50
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
    51
static void save_mode(_THIS)
slouken@0
    52
{
slouken@1336
    53
    SDL_memset(&saved_mode, 0, sizeof(saved_mode));
slouken@292
    54
    SDL_NAME(XF86VidModeGetModeInfo)(SDL_Display,SDL_Screen,&saved_mode);
slouken@292
    55
    SDL_NAME(XF86VidModeGetViewPort)(SDL_Display,SDL_Screen,&saved_view.x,&saved_view.y);
slouken@0
    56
}
slouken@0
    57
#endif
slouken@0
    58
slouken@1361
    59
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
    60
static void restore_mode(_THIS)
slouken@0
    61
{
slouken@292
    62
    SDL_NAME(XF86VidModeModeLine) mode;
slouken@0
    63
    int unused;
slouken@0
    64
slouken@292
    65
    if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
slouken@0
    66
        if ( (saved_mode.hdisplay != mode.hdisplay) ||
slouken@0
    67
             (saved_mode.vdisplay != mode.vdisplay) ) {
slouken@292
    68
            SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, &saved_mode);
slouken@0
    69
        }
slouken@0
    70
    }
slouken@0
    71
    if ( (saved_view.x != 0) || (saved_view.y != 0) ) {
slouken@292
    72
        SDL_NAME(XF86VidModeSetViewPort)(SDL_Display, SDL_Screen, saved_view.x, saved_view.y);
slouken@0
    73
    }
slouken@0
    74
}
slouken@0
    75
#endif
slouken@0
    76
slouken@1361
    77
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
    78
static int cmpmodes(const void *va, const void *vb)
slouken@0
    79
{
slouken@292
    80
    const SDL_NAME(XF86VidModeModeInfo) *a = *(const SDL_NAME(XF86VidModeModeInfo)**)va;
slouken@292
    81
    const SDL_NAME(XF86VidModeModeInfo) *b = *(const SDL_NAME(XF86VidModeModeInfo)**)vb;
slouken@966
    82
    if ( a->hdisplay == b->hdisplay )
slouken@966
    83
        return b->vdisplay - a->vdisplay;
slouken@966
    84
    else
slouken@966
    85
        return b->hdisplay - a->hdisplay;
slouken@0
    86
}
slouken@0
    87
#endif
slouken@0
    88
slouken@242
    89
static void get_real_resolution(_THIS, int* w, int* h);
slouken@242
    90
slouken@0
    91
static void set_best_resolution(_THIS, int width, int height)
slouken@0
    92
{
slouken@1361
    93
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
    94
    if ( use_vidmode ) {
slouken@292
    95
        SDL_NAME(XF86VidModeModeLine) mode;
slouken@292
    96
        SDL_NAME(XF86VidModeModeInfo) **modes;
slouken@0
    97
        int i;
slouken@637
    98
        int best_width = 0, best_height = 0;
slouken@0
    99
        int nmodes;
slouken@0
   100
slouken@292
   101
        if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &i, &mode) &&
slouken@637
   102
             SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display,SDL_Screen,&nmodes,&modes)){
slouken@0
   103
#ifdef XFREE86_DEBUG
slouken@641
   104
            printf("Available modes (unsorted):\n");
slouken@227
   105
            for ( i = 0; i < nmodes; ++i ) {
slouken@637
   106
                printf("Mode %d: %d x %d @ %d\n", i,
slouken@637
   107
                        modes[i]->hdisplay, modes[i]->vdisplay,
slouken@637
   108
                        1000 * modes[i]->dotclock / (modes[i]->htotal *
slouken@637
   109
                        modes[i]->vtotal) );
slouken@227
   110
            }
slouken@0
   111
#endif
slouken@637
   112
            for ( i = 0; i < nmodes ; i++ ) {
slouken@604
   113
                if ( (modes[i]->hdisplay == width) &&
slouken@637
   114
                     (modes[i]->vdisplay == height) )
slouken@604
   115
                    goto match;
slouken@604
   116
            }
slouken@641
   117
            qsort(modes, nmodes, sizeof *modes, cmpmodes);
slouken@713
   118
            for ( i = nmodes-1; i > 0 ; i-- ) {
slouken@637
   119
		if ( ! best_width ) {
slouken@637
   120
                    if ( (modes[i]->hdisplay >= width) &&
slouken@637
   121
                         (modes[i]->vdisplay >= height) ) {
slouken@637
   122
                        best_width = modes[i]->hdisplay;
slouken@637
   123
                        best_height = modes[i]->vdisplay;
slouken@637
   124
                    }
slouken@637
   125
                } else {
slouken@637
   126
                    if ( (modes[i]->hdisplay != best_width) ||
slouken@637
   127
                         (modes[i]->vdisplay != best_height) ) {
slouken@637
   128
                        i++;
slouken@637
   129
                        break;
slouken@637
   130
                    }
slouken@637
   131
                }
slouken@0
   132
            }
slouken@604
   133
       match:
slouken@0
   134
            if ( (modes[i]->hdisplay != mode.hdisplay) ||
slouken@0
   135
                 (modes[i]->vdisplay != mode.vdisplay) ) {
slouken@292
   136
                SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, modes[i]);
slouken@0
   137
            }
icculus@1575
   138
            XFree(modes);
slouken@0
   139
        }
slouken@0
   140
    }
slouken@1361
   141
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@242
   142
slouken@499
   143
                                /* XiG */
slouken@1361
   144
#if SDL_VIDEO_DRIVER_X11_XME
slouken@242
   145
#ifdef XIG_DEBUG
slouken@242
   146
    fprintf(stderr, "XME: set_best_resolution(): w = %d, h = %d\n",
slouken@499
   147
            width, height);
slouken@242
   148
#endif
slouken@242
   149
    if ( SDL_modelist ) {
slouken@499
   150
        int i;
slouken@242
   151
slouken@242
   152
        for ( i=0; SDL_modelist[i]; ++i ) {
slouken@499
   153
            if ( (SDL_modelist[i]->w >= width) &&
slouken@242
   154
                 (SDL_modelist[i]->h >= height) ) {
slouken@499
   155
                break;
slouken@499
   156
            }
slouken@242
   157
        }
slouken@499
   158
        
slouken@499
   159
        if ( SDL_modelist[i] ) { /* found one, lets try it */
slouken@499
   160
            int w, h;        
slouken@242
   161
slouken@242
   162
            /* check current mode so we can avoid uneccessary mode changes */
slouken@499
   163
            get_real_resolution(this, &w, &h);
slouken@242
   164
slouken@499
   165
            if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) {
slouken@242
   166
# ifdef XIG_DEBUG
slouken@499
   167
                fprintf(stderr, "XME: set_best_resolution: "
slouken@499
   168
                        "XiGMiscChangeResolution: %d %d\n",
slouken@499
   169
                        SDL_modelist[s]->w, SDL_modelist[s]->h);
slouken@242
   170
# endif
slouken@499
   171
                XiGMiscChangeResolution(SDL_Display, 
slouken@499
   172
                                        SDL_Screen,
slouken@499
   173
                                        0, /* view */
slouken@499
   174
                                        SDL_modelist[i]->w, 
slouken@499
   175
                                        SDL_modelist[i]->h, 
slouken@499
   176
                                        0);
icculus@1575
   177
                XSync(SDL_Display, False);
slouken@242
   178
            }
slouken@242
   179
        }
slouken@242
   180
    }
slouken@1361
   181
#endif /* SDL_VIDEO_DRIVER_X11_XME */
slouken@242
   182
slouken@0
   183
}
slouken@0
   184
slouken@0
   185
static void get_real_resolution(_THIS, int* w, int* h)
slouken@0
   186
{
slouken@1361
   187
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
   188
    if ( use_vidmode ) {
slouken@292
   189
        SDL_NAME(XF86VidModeModeLine) mode;
slouken@0
   190
        int unused;
slouken@0
   191
slouken@292
   192
        if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
slouken@0
   193
            *w = mode.hdisplay;
slouken@0
   194
            *h = mode.vdisplay;
slouken@0
   195
            return;
slouken@0
   196
        }
slouken@0
   197
    }
slouken@0
   198
#endif
slouken@242
   199
slouken@1361
   200
#if SDL_VIDEO_DRIVER_X11_XME
slouken@242
   201
    if ( use_xme ) {
slouken@242
   202
        int ractive;
slouken@242
   203
        XiGMiscResolutionInfo *modelist;
slouken@242
   204
slouken@242
   205
        XiGMiscQueryResolutions(SDL_Display, SDL_Screen,
slouken@499
   206
                                0, /* view */
slouken@499
   207
                                &ractive, &modelist);
slouken@242
   208
        *w = modelist[ractive].width;
slouken@242
   209
        *h = modelist[ractive].height;
slouken@242
   210
#ifdef XIG_DEBUG
slouken@242
   211
        fprintf(stderr, "XME: get_real_resolution: w = %d h = %d\n", *w, *h);
slouken@242
   212
#endif
slouken@242
   213
        XFree(modelist);
slouken@242
   214
        return;
slouken@242
   215
    }
slouken@242
   216
#endif /* XIG_XME */
slouken@242
   217
slouken@0
   218
    *w = DisplayWidth(SDL_Display, SDL_Screen);
slouken@0
   219
    *h = DisplayHeight(SDL_Display, SDL_Screen);
slouken@0
   220
}
slouken@0
   221
slouken@0
   222
/* Called after mapping a window - waits until the window is mapped */
slouken@0
   223
void X11_WaitMapped(_THIS, Window win)
slouken@0
   224
{
slouken@0
   225
    XEvent event;
slouken@0
   226
    do {
icculus@1575
   227
        XMaskEvent(SDL_Display, StructureNotifyMask, &event);
slouken@0
   228
    } while ( (event.type != MapNotify) || (event.xmap.event != win) );
slouken@0
   229
}
slouken@0
   230
slouken@0
   231
/* Called after unmapping a window - waits until the window is unmapped */
slouken@0
   232
void X11_WaitUnmapped(_THIS, Window win)
slouken@0
   233
{
slouken@0
   234
    XEvent event;
slouken@0
   235
    do {
icculus@1575
   236
        XMaskEvent(SDL_Display, StructureNotifyMask, &event);
slouken@0
   237
    } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) );
slouken@0
   238
}
slouken@0
   239
slouken@0
   240
static void move_cursor_to(_THIS, int x, int y)
slouken@0
   241
{
icculus@1575
   242
    XWarpPointer(SDL_Display, None, SDL_Root, 0, 0, 0, 0, x, y);
slouken@0
   243
}
slouken@0
   244
slouken@0
   245
static int add_visual(_THIS, int depth, int class)
slouken@0
   246
{
slouken@0
   247
    XVisualInfo vi;
icculus@1575
   248
    if(XMatchVisualInfo(SDL_Display, SDL_Screen, depth, class, &vi)) {
slouken@499
   249
        int n = this->hidden->nvisuals;
slouken@499
   250
        this->hidden->visuals[n].depth = vi.depth;
slouken@499
   251
        this->hidden->visuals[n].visual = vi.visual;
slouken@499
   252
        this->hidden->nvisuals++;
slouken@0
   253
    }
slouken@0
   254
    return(this->hidden->nvisuals);
slouken@0
   255
}
slouken@0
   256
static int add_visual_byid(_THIS, const char *visual_id)
slouken@0
   257
{
slouken@0
   258
    XVisualInfo *vi, template;
slouken@0
   259
    int nvis;
slouken@0
   260
slouken@0
   261
    if ( visual_id ) {
slouken@1336
   262
        SDL_memset(&template, 0, (sizeof template));
slouken@1336
   263
        template.visualid = SDL_strtol(visual_id, NULL, 0);
icculus@1575
   264
        vi = XGetVisualInfo(SDL_Display, VisualIDMask, &template, &nvis);
slouken@0
   265
        if ( vi ) {
slouken@499
   266
            int n = this->hidden->nvisuals;
slouken@499
   267
            this->hidden->visuals[n].depth = vi->depth;
slouken@499
   268
            this->hidden->visuals[n].visual = vi->visual;
slouken@499
   269
            this->hidden->nvisuals++;
icculus@1575
   270
            XFree(vi);
slouken@0
   271
        }
slouken@0
   272
    }
slouken@0
   273
    return(this->hidden->nvisuals);
slouken@0
   274
}
slouken@0
   275
slouken@0
   276
/* Global for the error handler */
slouken@0
   277
int vm_event, vm_error = -1;
slouken@0
   278
slouken@0
   279
int X11_GetVideoModes(_THIS)
slouken@0
   280
{
slouken@1361
   281
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
   282
    int buggy_X11;
slouken@0
   283
    int vm_major, vm_minor;
slouken@0
   284
    int nmodes;
slouken@292
   285
    SDL_NAME(XF86VidModeModeInfo) **modes;
slouken@0
   286
#endif
slouken@1361
   287
#if SDL_VIDEO_DRIVER_X11_XME
slouken@242
   288
    int xme_major, xme_minor;
slouken@242
   289
    int ractive, nummodes;
slouken@242
   290
    XiGMiscResolutionInfo *modelist;
slouken@242
   291
#endif
slouken@230
   292
    int i, n;
slouken@230
   293
    int screen_w;
slouken@230
   294
    int screen_h;
slouken@0
   295
slouken@0
   296
    vm_error = -1;
slouken@0
   297
    use_vidmode = 0;
slouken@230
   298
    screen_w = DisplayWidth(SDL_Display, SDL_Screen);
slouken@230
   299
    screen_h = DisplayHeight(SDL_Display, SDL_Screen);
slouken@230
   300
slouken@1361
   301
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
   302
    /* Metro-X 4.3.0 and earlier has a broken implementation of
slouken@0
   303
       XF86VidModeGetAllModeLines() - it hangs the client.
slouken@0
   304
     */
slouken@0
   305
    buggy_X11 = 0;
slouken@1336
   306
    if ( SDL_strcmp(ServerVendor(SDL_Display), "Metro Link Incorporated") == 0 ) {
slouken@0
   307
        FILE *metro_fp;
slouken@0
   308
slouken@0
   309
        metro_fp = fopen("/usr/X11R6/lib/X11/Metro/.version", "r");
slouken@0
   310
        if ( metro_fp != NULL ) {
slouken@0
   311
            int major, minor, patch, version;
slouken@0
   312
            major = 0; minor = 0; patch = 0;
slouken@0
   313
            fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch);
slouken@0
   314
            version = major*100+minor*10+patch;
slouken@0
   315
            if ( version < 431 ) {
slouken@0
   316
                buggy_X11 = 1;
slouken@0
   317
            }
slouken@0
   318
            fclose(metro_fp);
slouken@0
   319
        }
slouken@0
   320
    }
slouken@1262
   321
#if 0 /* Let's try this again... hopefully X servers have improved... */
slouken@607
   322
#if defined(__alpha__) || defined(__sparc64__) || defined(__powerpc__)
slouken@607
   323
    /* The alpha, sparc64 and PPC XFree86 servers are also buggy */
slouken@0
   324
    buggy_X11 = 1;
slouken@0
   325
#endif
slouken@1262
   326
#endif
slouken@0
   327
    /* Enumerate the available fullscreen modes */
slouken@0
   328
    if ( ! buggy_X11 ) {
slouken@292
   329
        if ( SDL_NAME(XF86VidModeQueryExtension)(SDL_Display, &vm_event, &vm_error) &&
slouken@292
   330
              SDL_NAME(XF86VidModeQueryVersion)(SDL_Display, &vm_major, &vm_minor) ) {
slouken@0
   331
#ifdef BROKEN_XFREE86_4001
slouken@0
   332
#ifdef X_XF86VidModeGetDotClocks  /* Compiled under XFree86 4.0 */
slouken@0
   333
                /* Earlier X servers hang when doing vidmode */
slouken@499
   334
                if ( vm_major < 2 ) {
slouken@227
   335
#ifdef XFREE86_DEBUG
slouken@227
   336
                    printf("Compiled under XFree86 4.0, server is XFree86 3.X\n");
slouken@0
   337
#endif
slouken@0
   338
                    buggy_X11 = 1;
slouken@0
   339
                }
slouken@0
   340
#else
slouken@499
   341
                /* XFree86 3.X code works with XFree86 4.0 servers */;
slouken@0
   342
#endif /* XFree86 4.0 */
slouken@0
   343
#endif /* XFree86 4.02 and newer are fixed wrt backwards compatibility */
slouken@0
   344
        } else {
slouken@0
   345
            buggy_X11 = 1;
slouken@0
   346
        }
slouken@0
   347
    }
slouken@0
   348
    if ( ! buggy_X11 &&
slouken@637
   349
         SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) {
slouken@0
   350
slouken@637
   351
#ifdef XFREE86_DEBUG
slouken@641
   352
        printf("Available modes: (sorted)\n");
slouken@637
   353
        for ( i = 0; i < nmodes; ++i ) {
slouken@637
   354
            printf("Mode %d: %d x %d @ %d\n", i,
slouken@637
   355
                    modes[i]->hdisplay, modes[i]->vdisplay,
slouken@637
   356
                    1000 * modes[i]->dotclock / (modes[i]->htotal *
slouken@637
   357
                    modes[i]->vtotal) );
slouken@637
   358
        }
slouken@637
   359
#endif
slouken@637
   360
slouken@1338
   361
        SDL_qsort(modes, nmodes, sizeof *modes, cmpmodes);
slouken@1336
   362
        SDL_modelist = (SDL_Rect **)SDL_malloc((nmodes+2)*sizeof(SDL_Rect *));
slouken@0
   363
        if ( SDL_modelist ) {
slouken@230
   364
            n = 0;
slouken@0
   365
            for ( i=0; i<nmodes; ++i ) {
slouken@230
   366
                int w, h;
slouken@230
   367
slouken@1318
   368
		/* Eliminate duplicate modes with different refresh rates */
slouken@1318
   369
		if ( i > 0 &&
slouken@1318
   370
		     modes[i]->hdisplay == modes[i-1]->hdisplay &&
slouken@1318
   371
		     modes[i]->vdisplay == modes[i-1]->vdisplay ) {
slouken@1318
   372
			continue;
slouken@1318
   373
		}
slouken@1318
   374
slouken@230
   375
                /* Check to see if we should add the screen size (Xinerama) */
slouken@230
   376
                w = modes[i]->hdisplay;
slouken@230
   377
                h = modes[i]->vdisplay;
slouken@230
   378
                if ( (screen_w * screen_h) >= (w * h) ) {
slouken@230
   379
                    if ( (screen_w != w) || (screen_h != h) ) {
slouken@1336
   380
                        SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
slouken@230
   381
                        if ( SDL_modelist[n] ) {
slouken@230
   382
                            SDL_modelist[n]->x = 0;
slouken@230
   383
                            SDL_modelist[n]->y = 0;
slouken@230
   384
                            SDL_modelist[n]->w = screen_w;
slouken@230
   385
                            SDL_modelist[n]->h = screen_h;
slouken@230
   386
                            ++n;
slouken@230
   387
                        }
slouken@230
   388
                    }
slouken@230
   389
                    screen_w = 0;
slouken@230
   390
                    screen_h = 0;
slouken@230
   391
                }
slouken@230
   392
slouken@230
   393
                /* Add the size from the video mode list */
slouken@1336
   394
                SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
slouken@230
   395
                if ( SDL_modelist[n] == NULL ) {
slouken@0
   396
                    break;
slouken@0
   397
                }
slouken@230
   398
                SDL_modelist[n]->x = 0;
slouken@230
   399
                SDL_modelist[n]->y = 0;
slouken@230
   400
                SDL_modelist[n]->w = w;
slouken@230
   401
                SDL_modelist[n]->h = h;
slouken@230
   402
                ++n;
slouken@0
   403
            }
slouken@230
   404
            SDL_modelist[n] = NULL;
slouken@0
   405
        }
icculus@1575
   406
        XFree(modes);
slouken@0
   407
slouken@100
   408
        use_vidmode = vm_major * 100 + vm_minor;
slouken@0
   409
        save_mode(this);
slouken@0
   410
    }
slouken@1361
   411
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@0
   412
slouken@499
   413
                                /* XiG */
slouken@1361
   414
#if SDL_VIDEO_DRIVER_X11_XME
slouken@242
   415
    /* first lets make sure we have the extension, and it's at least v2.0 */
slouken@242
   416
    if (XiGMiscQueryVersion(SDL_Display, &xme_major, &xme_minor)) {
slouken@242
   417
#ifdef XIG_DEBUG
slouken@499
   418
        fprintf(stderr, "XME: XiGMiscQueryVersion: V%d.%d\n",
slouken@499
   419
                xme_major, xme_minor);
slouken@242
   420
#endif
slouken@499
   421
        /* work around a XiGMisc bogosity in our version of libXext */
slouken@499
   422
        if (xme_major == 0 && xme_major == 0) {
slouken@499
   423
            /* Ideally libxme would spit this out, but the problem is that
slouken@499
   424
               the right Query func will never be called if using the bogus
slouken@499
   425
               libXext version.
slouken@499
   426
             */
slouken@499
   427
            fprintf(stderr, 
slouken@242
   428
"XME: If you are using Xi Graphics CDE and a Summit server, you need to\n"
slouken@242
   429
"XME: get the libXext update from our ftp site before fullscreen switching\n"
slouken@242
   430
"XME: will work.  Fullscreen switching is only supported on Summit Servers\n");
slouken@499
   431
          }
slouken@242
   432
    } else {
slouken@242
   433
        /* not there. Bummer. */
slouken@499
   434
        xme_major = xme_minor = 0;
slouken@242
   435
    }
slouken@242
   436
slouken@242
   437
    modelist = NULL;
slouken@242
   438
    if (xme_major >= 2 && (nummodes = XiGMiscQueryResolutions(SDL_Display, 
slouken@499
   439
                                            SDL_Screen,
slouken@499
   440
                                            0, /* view */
slouken@499
   441
                                            &ractive, 
slouken@499
   442
                                            &modelist)) > 1)
slouken@499
   443
    {                                /* then we actually have some */
slouken@499
   444
        int j;
slouken@242
   445
slouken@242
   446
#ifdef XIG_DEBUG
slouken@499
   447
        fprintf(stderr, "XME: nummodes = %d, active mode = %d\n",
slouken@499
   448
                nummodes, ractive);
slouken@242
   449
#endif
slouken@242
   450
slouken@1336
   451
        SDL_modelist = (SDL_Rect **)SDL_malloc((nummodes+1)*sizeof(SDL_Rect *));
slouken@242
   452
slouken@499
   453
                                /* we get the list already sorted in */
slouken@499
   454
                                /* descending order.  We'll copy it in */
slouken@499
   455
                                /* reverse order so SDL is happy */
slouken@499
   456
        if (SDL_modelist) {
slouken@499
   457
            for ( i=0, j=nummodes-1; j>=0; i++, j-- ) {
slouken@499
   458
                if ((SDL_modelist[i] = 
slouken@1336
   459
                     (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect))) == NULL)
slouken@499
   460
                  break;
slouken@242
   461
#ifdef XIG_DEBUG
slouken@499
   462
                fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n",
slouken@499
   463
                       i, modelist[i].width, modelist[i].height);
slouken@242
   464
#endif
slouken@499
   465
                
slouken@499
   466
                SDL_modelist[i]->x = 0;
slouken@499
   467
                SDL_modelist[i]->y = 0;
slouken@499
   468
                SDL_modelist[i]->w = modelist[j].width;
slouken@499
   469
                SDL_modelist[i]->h = modelist[j].height;
slouken@499
   470
                
slouken@499
   471
            }
slouken@242
   472
            SDL_modelist[i] = NULL; /* terminator */
slouken@499
   473
        }
slouken@499
   474
        use_xme = 1;
slouken@499
   475
        saved_res = modelist[ractive]; /* save the current resolution */
slouken@242
   476
    } else {
slouken@242
   477
        use_xme = 0;
slouken@242
   478
    }
slouken@242
   479
    if ( modelist ) {
icculus@1575
   480
        XFree(modelist);
slouken@242
   481
    }
slouken@1361
   482
#endif /* SDL_VIDEO_DRIVER_X11_XME */
slouken@242
   483
slouken@0
   484
    {
slouken@499
   485
        static int depth_list[] = { 32, 24, 16, 15, 8 };
slouken@499
   486
        int j, np;
slouken@499
   487
        int use_directcolor = 1;
slouken@499
   488
        XPixmapFormatValues *pf;
slouken@0
   489
slouken@499
   490
        /* Search for the visuals in deepest-first order, so that the first
slouken@499
   491
           will be the richest one */
slouken@1336
   492
        if ( SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) {
slouken@499
   493
                use_directcolor = 0;
slouken@499
   494
        }
slouken@499
   495
        this->hidden->nvisuals = 0;
slouken@1336
   496
        if ( ! add_visual_byid(this, SDL_getenv("SDL_VIDEO_X11_VISUALID")) ) {
slouken@1379
   497
                for ( i=0; i<SDL_arraysize(depth_list); ++i ) {
slouken@499
   498
                        if ( depth_list[i] > 8 ) {
slouken@499
   499
                                if ( use_directcolor ) {
slouken@499
   500
                                        add_visual(this, depth_list[i], DirectColor);
slouken@499
   501
                                }
slouken@499
   502
                                add_visual(this, depth_list[i], TrueColor);
slouken@499
   503
                        } else {
slouken@499
   504
                                add_visual(this, depth_list[i], PseudoColor);
slouken@499
   505
                                add_visual(this, depth_list[i], StaticColor);
slouken@499
   506
                        }
slouken@499
   507
                }
slouken@499
   508
        }
slouken@499
   509
        if ( this->hidden->nvisuals == 0 ) {
slouken@499
   510
            SDL_SetError("Found no sufficiently capable X11 visuals");
slouken@499
   511
            return -1;
slouken@499
   512
        }
slouken@499
   513
            
slouken@499
   514
        /* look up the pixel quantum for each depth */
icculus@1575
   515
        pf = XListPixmapFormats(SDL_Display, &np);
slouken@499
   516
        for(i = 0; i < this->hidden->nvisuals; i++) {
slouken@499
   517
            int d = this->hidden->visuals[i].depth;
slouken@499
   518
            for(j = 0; j < np; j++)
slouken@499
   519
                if(pf[j].depth == d)
slouken@499
   520
                    break;
slouken@499
   521
            this->hidden->visuals[i].bpp = j < np ? pf[j].bits_per_pixel : d;
slouken@499
   522
        }
slouken@0
   523
icculus@1575
   524
        XFree(pf);
slouken@0
   525
    }
slouken@0
   526
slouken@0
   527
    if ( SDL_modelist == NULL ) {
slouken@1336
   528
        SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *));
slouken@0
   529
        if ( SDL_modelist ) {
slouken@230
   530
            n = 0;
slouken@1336
   531
            SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
slouken@230
   532
            if ( SDL_modelist[n] ) {
slouken@230
   533
                SDL_modelist[n]->x = 0;
slouken@230
   534
                SDL_modelist[n]->y = 0;
slouken@230
   535
                SDL_modelist[n]->w = screen_w;
slouken@230
   536
                SDL_modelist[n]->h = screen_h;
slouken@230
   537
                ++n;
slouken@0
   538
            }
slouken@230
   539
            SDL_modelist[n] = NULL;
slouken@0
   540
        }
slouken@0
   541
    }
slouken@0
   542
slouken@242
   543
#if defined(XFREE86_DEBUG) || defined(XIG_DEBUG)
slouken@0
   544
    if ( use_vidmode ) {
slouken@227
   545
        printf("XFree86 VidMode is enabled\n");
slouken@0
   546
    }
slouken@242
   547
slouken@1361
   548
#if SDL_VIDEO_DRIVER_X11_XME
slouken@242
   549
    if ( use_xme )
slouken@242
   550
      printf("Xi Graphics XME fullscreen is enabled\n");
slouken@242
   551
    else
slouken@242
   552
      printf("Xi Graphics XME fullscreen is not available\n");
slouken@242
   553
#endif 
slouken@242
   554
slouken@0
   555
    if ( SDL_modelist ) {
slouken@227
   556
        printf("X11 video mode list:\n");
slouken@0
   557
        for ( i=0; SDL_modelist[i]; ++i ) {
slouken@227
   558
            printf("\t%dx%d\n", SDL_modelist[i]->w, SDL_modelist[i]->h);
slouken@0
   559
        }
slouken@0
   560
    }
slouken@242
   561
#endif /* XFREE86_DEBUG || XIG_DEBUG */
slouken@227
   562
slouken@227
   563
    /* The default X/Y fullscreen offset is 0/0 */
slouken@227
   564
    xinerama_x = 0;
slouken@227
   565
    xinerama_y = 0;
slouken@227
   566
slouken@1361
   567
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@227
   568
    /* Query Xinerama extention */
slouken@292
   569
    if ( SDL_NAME(XineramaQueryExtension)(SDL_Display, &i, &i) &&
slouken@292
   570
         SDL_NAME(XineramaIsActive)(SDL_Display) ) {
slouken@499
   571
        /* Find out which screen is the desired one */
slouken@499
   572
        int desired = 0;
slouken@227
   573
        int screens;
slouken@292
   574
        SDL_NAME(XineramaScreenInfo) *xinerama;
slouken@227
   575
slouken@227
   576
#ifdef XINERAMA_DEBUG
slouken@227
   577
        printf("X11 detected Xinerama:\n");
slouken@227
   578
#endif
slouken@499
   579
#if 0 /* Apparently the vidmode extension doesn't work with Xinerama */
slouken@1336
   580
        const char *variable = SDL_getenv("SDL_VIDEO_X11_XINERAMA_SCREEN");
slouken@499
   581
        if ( variable ) {
slouken@499
   582
                desired = atoi(variable);
slouken@499
   583
        }
slouken@499
   584
#endif
slouken@292
   585
        xinerama = SDL_NAME(XineramaQueryScreens)(SDL_Display, &screens);
slouken@227
   586
        for ( i = 0; i < screens; i++ ) {
slouken@227
   587
#ifdef XINERAMA_DEBUG
slouken@227
   588
            printf("xinerama %d: %dx%d+%d+%d\n",
slouken@227
   589
                xinerama[i].screen_number,
slouken@227
   590
                xinerama[i].width, xinerama[i].height,
slouken@227
   591
                xinerama[i].x_org, xinerama[i].y_org);
slouken@227
   592
#endif
slouken@499
   593
            if ( xinerama[i].screen_number == desired ) {
slouken@227
   594
                xinerama_x = xinerama[i].x_org;
slouken@227
   595
                xinerama_y = xinerama[i].y_org;
slouken@227
   596
            }
slouken@227
   597
        }
icculus@1575
   598
        XFree(xinerama);
slouken@227
   599
    }
slouken@1361
   600
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@227
   601
slouken@0
   602
    return 0;
slouken@0
   603
}
slouken@0
   604
slouken@0
   605
int X11_SupportedVisual(_THIS, SDL_PixelFormat *format)
slouken@0
   606
{
slouken@0
   607
    int i;
slouken@0
   608
    for(i = 0; i < this->hidden->nvisuals; i++)
slouken@499
   609
        if(this->hidden->visuals[i].bpp == format->BitsPerPixel)
slouken@499
   610
            return 1;
slouken@0
   611
    return 0;
slouken@0
   612
}
slouken@0
   613
slouken@0
   614
SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
slouken@0
   615
{
slouken@0
   616
    if ( X11_SupportedVisual(this, format) ) {
slouken@0
   617
        if ( flags & SDL_FULLSCREEN ) {
slouken@0
   618
            return(SDL_modelist);
slouken@0
   619
        } else {
slouken@0
   620
            return((SDL_Rect **)-1);
slouken@0
   621
        }
slouken@0
   622
    } else {
slouken@0
   623
        return((SDL_Rect **)0);
slouken@0
   624
    }
slouken@0
   625
}
slouken@0
   626
slouken@0
   627
void X11_FreeVideoModes(_THIS)
slouken@0
   628
{
slouken@0
   629
    int i;
slouken@0
   630
slouken@0
   631
    if ( SDL_modelist ) {
slouken@0
   632
        for ( i=0; SDL_modelist[i]; ++i ) {
slouken@1336
   633
            SDL_free(SDL_modelist[i]);
slouken@0
   634
        }
slouken@1336
   635
        SDL_free(SDL_modelist);
slouken@0
   636
        SDL_modelist = NULL;
slouken@0
   637
    }
slouken@0
   638
}
slouken@0
   639
slouken@0
   640
int X11_ResizeFullScreen(_THIS)
slouken@0
   641
{
slouken@0
   642
    int x, y;
slouken@0
   643
    int real_w, real_h;
slouken@230
   644
    int screen_w;
slouken@230
   645
    int screen_h;
slouken@230
   646
slouken@230
   647
    screen_w = DisplayWidth(SDL_Display, SDL_Screen);
slouken@230
   648
    screen_h = DisplayHeight(SDL_Display, SDL_Screen);
slouken@0
   649
slouken@227
   650
    x = xinerama_x;
slouken@227
   651
    y = xinerama_y;
slouken@0
   652
    if ( currently_fullscreen ) {
slouken@0
   653
        /* Switch resolution and cover it with the FSwindow */
slouken@227
   654
        move_cursor_to(this, x, y);
slouken@1545
   655
        set_best_resolution(this, window_w, window_h);
slouken@227
   656
        move_cursor_to(this, x, y);
slouken@0
   657
        get_real_resolution(this, &real_w, &real_h);
slouken@1545
   658
        if ( window_w > real_w ) {
slouken@230
   659
            real_w = MAX(real_w, screen_w);
slouken@230
   660
        }
slouken@1545
   661
        if ( window_h > real_h ) {
slouken@230
   662
            real_h = MAX(real_h, screen_h);
slouken@230
   663
        }
icculus@1575
   664
        XMoveResizeWindow(SDL_Display, FSwindow, x, y, real_w, real_h);
slouken@0
   665
        move_cursor_to(this, real_w/2, real_h/2);
slouken@0
   666
slouken@0
   667
        /* Center and reparent the drawing window */
slouken@1545
   668
        x = (real_w - window_w)/2;
slouken@1545
   669
        y = (real_h - window_h)/2;
icculus@1575
   670
        XReparentWindow(SDL_Display, SDL_Window, FSwindow, x, y);
slouken@0
   671
        /* FIXME: move the mouse to the old relative location */
icculus@1575
   672
        XSync(SDL_Display, True);   /* Flush spurious mode change events */
slouken@0
   673
    }
slouken@0
   674
    return(1);
slouken@0
   675
}
slouken@0
   676
slouken@0
   677
void X11_QueueEnterFullScreen(_THIS)
slouken@0
   678
{
slouken@0
   679
    switch_waiting = 0x01 | SDL_FULLSCREEN;
slouken@0
   680
    switch_time = SDL_GetTicks() + 1500;
slouken@0
   681
#if 0 /* This causes a BadMatch error if the window is iconified (not needed) */
icculus@1575
   682
    XSetInputFocus(SDL_Display, WMwindow, RevertToNone, CurrentTime);
slouken@0
   683
#endif
slouken@0
   684
}
slouken@0
   685
slouken@0
   686
int X11_EnterFullScreen(_THIS)
slouken@0
   687
{
slouken@0
   688
    int okay;
slouken@0
   689
#if 0
slouken@0
   690
    Window tmpwin, *windows;
slouken@0
   691
    int i, nwindows;
slouken@0
   692
#endif
slouken@98
   693
    int real_w, real_h;
slouken@230
   694
    int screen_w;
slouken@230
   695
    int screen_h;
slouken@0
   696
slouken@0
   697
    okay = 1;
slouken@98
   698
    if ( currently_fullscreen ) {
slouken@98
   699
        return(okay);
slouken@98
   700
    }
slouken@0
   701
slouken@98
   702
    /* Ungrab the input so that we can move the mouse around */
slouken@98
   703
    X11_GrabInputNoLock(this, SDL_GRAB_OFF);
slouken@98
   704
slouken@98
   705
    /* Map the fullscreen window to blank the screen */
slouken@230
   706
    screen_w = DisplayWidth(SDL_Display, SDL_Screen);
slouken@230
   707
    screen_h = DisplayHeight(SDL_Display, SDL_Screen);
slouken@98
   708
    get_real_resolution(this, &real_w, &real_h);
slouken@1545
   709
    if ( window_w > real_w ) {
slouken@230
   710
        real_w = MAX(real_w, screen_w);
slouken@230
   711
    }
slouken@1545
   712
    if ( window_h > real_h ) {
slouken@230
   713
        real_h = MAX(real_h, screen_h);
slouken@230
   714
    }
icculus@1575
   715
    XMoveResizeWindow(SDL_Display, FSwindow,
slouken@499
   716
                      xinerama_x, xinerama_y, real_w, real_h);
icculus@1575
   717
    XMapRaised(SDL_Display, FSwindow);
slouken@98
   718
    X11_WaitMapped(this, FSwindow);
slouken@0
   719
slouken@0
   720
#if 0 /* This seems to break WindowMaker in focus-follows-mouse mode */
slouken@98
   721
    /* Make sure we got to the top of the window stack */
icculus@1575
   722
    if ( XQueryTree(SDL_Display, SDL_Root, &tmpwin, &tmpwin,
slouken@98
   723
                            &windows, &nwindows) && windows ) {
slouken@98
   724
        /* If not, try to put us there - if fail... oh well */
slouken@98
   725
        if ( windows[nwindows-1] != FSwindow ) {
slouken@98
   726
            tmpwin = windows[nwindows-1];
slouken@98
   727
            for ( i=0; i<nwindows; ++i ) {
slouken@98
   728
                if ( windows[i] == FSwindow ) {
slouken@1336
   729
                    SDL_memcpy(&windows[i], &windows[i+1],
slouken@98
   730
                           (nwindows-i-1)*sizeof(windows[i]));
slouken@98
   731
                    break;
slouken@0
   732
                }
slouken@0
   733
            }
slouken@98
   734
            windows[nwindows-1] = FSwindow;
icculus@1575
   735
            XRestackWindows(SDL_Display, windows, nwindows);
icculus@1575
   736
            XSync(SDL_Display, False);
slouken@0
   737
        }
icculus@1575
   738
        XFree(windows);
slouken@98
   739
    }
slouken@0
   740
#else
icculus@1575
   741
    XRaiseWindow(SDL_Display, FSwindow);
slouken@0
   742
#endif
slouken@0
   743
slouken@1361
   744
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@98
   745
    /* Save the current video mode */
slouken@98
   746
    if ( use_vidmode ) {
slouken@292
   747
        SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, True);
slouken@98
   748
    }
slouken@0
   749
#endif
slouken@98
   750
    currently_fullscreen = 1;
slouken@0
   751
slouken@98
   752
    /* Set the new resolution */
slouken@98
   753
    okay = X11_ResizeFullScreen(this);
slouken@98
   754
    if ( ! okay ) {
slouken@98
   755
        X11_LeaveFullScreen(this);
slouken@98
   756
    }
slouken@98
   757
    /* Set the colormap */
slouken@98
   758
    if ( SDL_XColorMap ) {
icculus@1575
   759
        XInstallColormap(SDL_Display, SDL_XColorMap);
slouken@0
   760
    }
slouken@88
   761
    if ( okay )
slouken@88
   762
        X11_GrabInputNoLock(this, this->input_grab | SDL_GRAB_FULLSCREEN);
slouken@88
   763
slouken@88
   764
    /* We may need to refresh the screen at this point (no backing store)
slouken@88
   765
       We also don't get an event, which is why we explicitly refresh. */
slouken@88
   766
    if ( this->screen ) {
slouken@88
   767
        if ( this->screen->flags & SDL_OPENGL ) {
slouken@88
   768
            SDL_PrivateExpose();
slouken@88
   769
        } else {
slouken@88
   770
            X11_RefreshDisplay(this);
slouken@88
   771
        }
slouken@88
   772
    }
slouken@88
   773
slouken@0
   774
    return(okay);
slouken@0
   775
}
slouken@0
   776
slouken@0
   777
int X11_LeaveFullScreen(_THIS)
slouken@0
   778
{
slouken@0
   779
    if ( currently_fullscreen ) {
icculus@1575
   780
        XReparentWindow(SDL_Display, SDL_Window, WMwindow, 0, 0);
slouken@1361
   781
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@0
   782
        if ( use_vidmode ) {
slouken@0
   783
            restore_mode(this);
slouken@292
   784
            SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False);
slouken@0
   785
        }
slouken@0
   786
#endif
slouken@242
   787
slouken@1361
   788
#if SDL_VIDEO_DRIVER_X11_XME
slouken@499
   789
        if ( use_xme ) {
slouken@499
   790
            int rw, rh;        
slouken@499
   791
            
slouken@242
   792
            /* check current mode so we can avoid uneccessary mode changes */
slouken@499
   793
            get_real_resolution(this, &rw, &rh);
slouken@242
   794
slouken@499
   795
            if (rw != saved_res.width || rh != saved_res.height) {
slouken@499
   796
                XiGMiscChangeResolution(SDL_Display, 
slouken@499
   797
                                        SDL_Screen,
slouken@499
   798
                                        0, /* view */
slouken@499
   799
                                        saved_res.width, 
slouken@499
   800
                                        saved_res.height,
slouken@499
   801
                                        0);
icculus@1575
   802
                XSync(SDL_Display, False);
slouken@499
   803
            }
slouken@499
   804
        }
slouken@242
   805
#endif
slouken@242
   806
icculus@1575
   807
        XUnmapWindow(SDL_Display, FSwindow);
slouken@0
   808
        X11_WaitUnmapped(this, FSwindow);
icculus@1575
   809
        XSync(SDL_Display, True);   /* Flush spurious mode change events */
slouken@0
   810
        currently_fullscreen = 0;
slouken@0
   811
    }
slouken@0
   812
    /* If we get popped out of fullscreen mode for some reason, input_grab
slouken@0
   813
       will still have the SDL_GRAB_FULLSCREEN flag set, since this is only
slouken@0
   814
       temporary.  In this case, release the grab unless the input has been
slouken@0
   815
       explicitly grabbed.
slouken@0
   816
     */
slouken@0
   817
    X11_GrabInputNoLock(this, this->input_grab & ~SDL_GRAB_FULLSCREEN);
slouken@88
   818
slouken@88
   819
    /* We may need to refresh the screen at this point (no backing store)
slouken@88
   820
       We also don't get an event, which is why we explicitly refresh. */
slouken@88
   821
    if ( this->screen ) {
slouken@88
   822
        if ( this->screen->flags & SDL_OPENGL ) {
slouken@88
   823
            SDL_PrivateExpose();
slouken@88
   824
        } else {
slouken@88
   825
            X11_RefreshDisplay(this);
slouken@88
   826
        }
slouken@88
   827
    }
slouken@88
   828
slouken@0
   829
    return(0);
slouken@0
   830
}