src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Dec 2008 04:42:28 +0000
changeset 2916 ffdd533f7add
parent 2906 c4150600b3ae
child 2920 cdb01906cb7e
permissions -rw-r--r--
Fixed pitch alignment problem causing MITSHM error on 16-bit displays
slouken@1950
     1
/*
slouken@1950
     2
    SDL - Simple DirectMedia Layer
slouken@2859
     3
    Copyright (C) 1997-2009 Sam Lantinga
slouken@1950
     4
slouken@1950
     5
    This library is free software; you can redistribute it and/or
slouken@1950
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1950
     7
    License as published by the Free Software Foundation; either
slouken@1950
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1950
     9
slouken@1950
    10
    This library is distributed in the hope that it will be useful,
slouken@1950
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1950
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1950
    13
    Lesser General Public License for more details.
slouken@1950
    14
slouken@1950
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1950
    16
    License along with this library; if not, write to the Free Software
slouken@1950
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1950
    18
slouken@1950
    19
    Sam Lantinga
slouken@1950
    20
    slouken@libsdl.org
slouken@1950
    21
*/
slouken@1950
    22
#include "SDL_config.h"
slouken@1950
    23
slouken@1950
    24
#include "SDL_x11video.h"
slouken@1950
    25
slouken@2873
    26
//#define X11MODES_DEBUG
slouken@2873
    27
#undef SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
    28
#undef SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
    29
#undef SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@1950
    30
slouken@1950
    31
static int
slouken@1950
    32
get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
slouken@1950
    33
{
slouken@1950
    34
    const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
slouken@2906
    35
    /* FIXME FIXME FIXME
slouken@2906
    36
     * Window creation fails in the colormap code on DirectColor visuals:
slouken@2906
    37
     *      XA_RGB_BEST_MAP not found and could not be created
slouken@2906
    38
     * I'm disabling this for now until Bob can look at it.  We don't need
slouken@2906
    39
     * it until we implement the gamma fading using DirectColor RGB ramps
slouken@2906
    40
     */
slouken@2906
    41
    int use_directcolor = 0;
slouken@1950
    42
    int depth;
slouken@1950
    43
slouken@1950
    44
    /* Look for an exact visual, if requested */
slouken@1950
    45
    if (visual_id) {
slouken@1950
    46
        XVisualInfo *vi, template;
slouken@1950
    47
        int nvis;
slouken@1950
    48
slouken@1950
    49
        SDL_zero(template);
slouken@1950
    50
        template.visualid = SDL_strtol(visual_id, NULL, 0);
slouken@1950
    51
        vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
slouken@1950
    52
        if (vi) {
slouken@1950
    53
            *vinfo = *vi;
slouken@1950
    54
            XFree(vi);
slouken@1950
    55
            return 0;
slouken@1950
    56
        }
slouken@1950
    57
    }
slouken@1950
    58
slouken@1950
    59
    depth = DefaultDepth(display, screen);
slouken@1950
    60
    if ((use_directcolor &&
slouken@1950
    61
         XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
slouken@1950
    62
        XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
slouken@1950
    63
        XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
slouken@1950
    64
        XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
slouken@1950
    65
        return 0;
slouken@1950
    66
    }
slouken@1950
    67
    return -1;
slouken@1950
    68
}
slouken@1950
    69
slouken@2870
    70
static Uint32
slouken@2874
    71
X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
slouken@2870
    72
{
slouken@2870
    73
    if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
slouken@2870
    74
        int bpp;
slouken@2870
    75
        Uint32 Rmask, Gmask, Bmask, Amask;
slouken@2870
    76
slouken@2870
    77
        Rmask = vinfo->visual->red_mask;
slouken@2870
    78
        Gmask = vinfo->visual->green_mask;
slouken@2870
    79
        Bmask = vinfo->visual->blue_mask;
slouken@2870
    80
        if (vinfo->depth == 32) {
slouken@2870
    81
            Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
slouken@2870
    82
        } else {
slouken@2870
    83
            Amask = 0;
slouken@2870
    84
        }
slouken@2870
    85
slouken@2870
    86
        bpp = vinfo->depth;
slouken@2870
    87
        if (bpp == 24) {
slouken@2870
    88
            int i, n;
slouken@2870
    89
            XPixmapFormatValues *p = XListPixmapFormats(display, &n);
slouken@2870
    90
            if (p) {
slouken@2870
    91
                for (i = 0; i < n; ++i) {
slouken@2870
    92
                    if (p[i].depth == 24) {
slouken@2870
    93
                        bpp = p[i].bits_per_pixel;
slouken@2870
    94
                        break;
slouken@2870
    95
                    }
slouken@2870
    96
                }
slouken@2870
    97
                XFree(p);
slouken@2870
    98
            }
slouken@2870
    99
        }
slouken@2870
   100
slouken@2870
   101
        return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
slouken@2870
   102
    }
slouken@2870
   103
slouken@2870
   104
    if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
slouken@2870
   105
        switch (vinfo->depth) {
slouken@2870
   106
        case 8:
slouken@2870
   107
            return SDL_PIXELTYPE_INDEX8;
slouken@2870
   108
        case 4:
slouken@2870
   109
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   110
                return SDL_PIXELFORMAT_INDEX4LSB;
slouken@2870
   111
            } else {
slouken@2870
   112
                return SDL_PIXELFORMAT_INDEX4MSB;
slouken@2870
   113
            }
slouken@2870
   114
            break;
slouken@2870
   115
        case 1:
slouken@2870
   116
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   117
                return SDL_PIXELFORMAT_INDEX1LSB;
slouken@2870
   118
            } else {
slouken@2870
   119
                return SDL_PIXELFORMAT_INDEX1MSB;
slouken@2870
   120
            }
slouken@2870
   121
            break;
slouken@2870
   122
        }
slouken@2870
   123
    }
slouken@2870
   124
slouken@2870
   125
    return SDL_PIXELFORMAT_UNKNOWN;
slouken@2870
   126
}
slouken@2870
   127
slouken@1950
   128
void
slouken@1950
   129
X11_InitModes(_THIS)
slouken@1950
   130
{
slouken@1950
   131
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@1950
   132
    int screen;
slouken@1950
   133
slouken@1950
   134
    for (screen = 0; screen < ScreenCount(data->display); ++screen) {
slouken@1950
   135
        XVisualInfo vinfo;
slouken@1950
   136
        SDL_VideoDisplay display;
slouken@1950
   137
        SDL_DisplayData *displaydata;
slouken@1950
   138
        SDL_DisplayMode mode;
slouken@2916
   139
        XPixmapFormatValues *pixmapFormats;
slouken@2916
   140
        int i, n;
slouken@1950
   141
slouken@1950
   142
        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@1950
   143
            continue;
slouken@1950
   144
        }
slouken@1950
   145
slouken@2870
   146
        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
slouken@1950
   147
        mode.w = DisplayWidth(data->display, screen);
slouken@1950
   148
        mode.h = DisplayHeight(data->display, screen);
slouken@1950
   149
        mode.refresh_rate = 0;
slouken@1950
   150
        mode.driverdata = NULL;
slouken@1950
   151
slouken@1950
   152
        displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
slouken@1950
   153
        if (!displaydata) {
slouken@1950
   154
            continue;
slouken@1950
   155
        }
slouken@1950
   156
        displaydata->screen = screen;
slouken@1950
   157
        displaydata->visual = vinfo.visual;
slouken@1951
   158
        displaydata->depth = vinfo.depth;
slouken@1950
   159
slouken@2916
   160
        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format)*8;
slouken@2916
   161
        pixmapFormats = XListPixmapFormats(data->display, &n);
slouken@2916
   162
        if (pixmapFormats) {
slouken@2916
   163
            for (i = 0; i < n; ++i) {
slouken@2916
   164
                if (pixmapFormats[i].depth == displaydata->depth) {
slouken@2916
   165
                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
slouken@2916
   166
                    break;
slouken@2916
   167
                }
slouken@2916
   168
            }
slouken@2916
   169
            XFree(pixmapFormats);
slouken@2916
   170
        }
slouken@2916
   171
slouken@1950
   172
        SDL_zero(display);
slouken@1950
   173
        display.desktop_mode = mode;
slouken@1950
   174
        display.current_mode = mode;
slouken@1950
   175
        display.driverdata = displaydata;
slouken@1950
   176
        SDL_AddVideoDisplay(&display);
slouken@1950
   177
    }
slouken@1950
   178
}
slouken@1950
   179
slouken@2873
   180
/* Global for the error handler */
slouken@2873
   181
int vm_event, vm_error = -1;
slouken@2873
   182
slouken@2873
   183
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   184
static SDL_bool
slouken@2874
   185
CheckXinerama(Display * display, int *major, int *minor)
slouken@2873
   186
{
slouken@2873
   187
    const char *env;
slouken@2873
   188
slouken@2873
   189
    /* Default the extension not available */
slouken@2873
   190
    *major = *minor = 0;
slouken@2873
   191
slouken@2873
   192
    /* Allow environment override */
slouken@2873
   193
    env = getenv("SDL_VIDEO_X11_XINERAMA");
slouken@2873
   194
    if (env && !SDL_atoi(env)) {
slouken@2873
   195
        return SDL_FALSE;
slouken@2873
   196
    }
slouken@2873
   197
slouken@2873
   198
    /* Query the extension version */
slouken@2874
   199
    if (!SDL_NAME(XineramaQueryExtension) (display, major, minor) ||
slouken@2874
   200
        !SDL_NAME(XineramaIsActive) (display)) {
slouken@2873
   201
        return SDL_FALSE;
slouken@2873
   202
    }
slouken@2873
   203
    return SDL_TRUE;
slouken@2873
   204
}
slouken@2873
   205
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   206
slouken@2873
   207
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   208
static SDL_bool
slouken@2874
   209
CheckXRandR(Display * display, int *major, int *minor)
slouken@2873
   210
{
slouken@2873
   211
    const char *env;
slouken@2873
   212
slouken@2873
   213
    /* Default the extension not available */
slouken@2873
   214
    *major = *minor = 0;
slouken@2873
   215
slouken@2873
   216
    /* Allow environment override */
slouken@2873
   217
    env = getenv("SDL_VIDEO_X11_XRANDR");
slouken@2873
   218
    if (env && !SDL_atoi(env)) {
slouken@2873
   219
        return SDL_FALSE;
slouken@2873
   220
    }
slouken@2873
   221
slouken@2873
   222
    if (!SDL_X11_HAVE_XRANDR) {
slouken@2873
   223
        return SDL_FALSE;
slouken@2873
   224
    }
slouken@2873
   225
slouken@2873
   226
    /* Query the extension version */
slouken@2873
   227
    if (!XRRQueryVersion(display, major, minor)) {
slouken@2873
   228
        return SDL_FALSE;
slouken@2873
   229
    }
slouken@2873
   230
    return SDL_TRUE;
slouken@2873
   231
}
slouken@2873
   232
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   233
slouken@2873
   234
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@2873
   235
static SDL_bool
slouken@2874
   236
CheckVidMode(Display * display, int *major, int *minor)
slouken@2873
   237
{
slouken@2873
   238
    const char *env;
slouken@2873
   239
slouken@2873
   240
    /* Default the extension not available */
slouken@2873
   241
    *major = *minor = 0;
slouken@2873
   242
slouken@2873
   243
    /* Allow environment override */
slouken@2873
   244
    env = getenv("SDL_VIDEO_X11_VIDMODE");
slouken@2873
   245
    if (env && !SDL_atoi(env)) {
slouken@2873
   246
        return SDL_FALSE;
slouken@2873
   247
    }
slouken@2874
   248
slouken@2873
   249
    /* Query the extension version */
slouken@2873
   250
    vm_error = -1;
slouken@2874
   251
    if (!SDL_NAME(XF86VidModeQueryExtension) (display, &vm_event, &vm_error)
slouken@2874
   252
        || !SDL_NAME(XF86VidModeQueryVersion) (display, major, minor)) {
slouken@2873
   253
        return SDL_FALSE;
slouken@2873
   254
    }
slouken@2873
   255
    return SDL_TRUE;
slouken@2873
   256
}
slouken@2873
   257
slouken@2874
   258
Bool SDL_NAME(XF86VidModeGetModeInfo) (Display * dpy, int scr,
slouken@2874
   259
                                       SDL_NAME(XF86VidModeModeInfo) * info)
slouken@2873
   260
{
slouken@2873
   261
    Bool retval;
slouken@2873
   262
    int dotclock;
slouken@2873
   263
    SDL_NAME(XF86VidModeModeLine) l;
slouken@2873
   264
    SDL_zerop(info);
slouken@2873
   265
    SDL_zero(l);
slouken@2874
   266
    retval = SDL_NAME(XF86VidModeGetModeLine) (dpy, scr, &dotclock, &l);
slouken@2873
   267
    info->dotclock = dotclock;
slouken@2873
   268
    info->hdisplay = l.hdisplay;
slouken@2873
   269
    info->hsyncstart = l.hsyncstart;
slouken@2873
   270
    info->hsyncend = l.hsyncend;
slouken@2873
   271
    info->htotal = l.htotal;
slouken@2873
   272
    info->hskew = l.hskew;
slouken@2873
   273
    info->vdisplay = l.vdisplay;
slouken@2873
   274
    info->vsyncstart = l.vsyncstart;
slouken@2873
   275
    info->vsyncend = l.vsyncend;
slouken@2873
   276
    info->vtotal = l.vtotal;
slouken@2873
   277
    info->flags = l.flags;
slouken@2873
   278
    info->privsize = l.privsize;
slouken@2873
   279
    info->private = l.private;
slouken@2873
   280
    return retval;
slouken@2873
   281
}
slouken@2873
   282
slouken@2873
   283
static int
slouken@2874
   284
calculate_rate(SDL_NAME(XF86VidModeModeInfo) * info)
slouken@2873
   285
{
slouken@2874
   286
    return (info->htotal
slouken@2874
   287
            && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
slouken@2874
   288
                                                         info->vtotal)) : 0;
slouken@2873
   289
}
slouken@2873
   290
slouken@2873
   291
static void
slouken@2874
   292
save_mode(Display * display, SDL_DisplayData * data)
slouken@2873
   293
{
slouken@2874
   294
    SDL_NAME(XF86VidModeGetModeInfo) (display, data->screen,
slouken@2874
   295
                                      &data->saved_mode);
slouken@2874
   296
    SDL_NAME(XF86VidModeGetViewPort) (display, data->screen,
slouken@2874
   297
                                      &data->saved_view.x,
slouken@2874
   298
                                      &data->saved_view.y);
slouken@2873
   299
}
slouken@2873
   300
slouken@2873
   301
static void
slouken@2874
   302
restore_mode(Display * display, SDL_DisplayData * data)
slouken@2873
   303
{
slouken@2873
   304
    SDL_NAME(XF86VidModeModeInfo) mode;
slouken@2873
   305
slouken@2874
   306
    if (SDL_NAME(XF86VidModeGetModeInfo) (display, data->screen, &mode)) {
slouken@2873
   307
        if (SDL_memcmp(&mode, &data->saved_mode, sizeof(mode)) != 0) {
slouken@2874
   308
            SDL_NAME(XF86VidModeSwitchToMode) (display, data->screen,
slouken@2874
   309
                                               &data->saved_mode);
slouken@2873
   310
        }
slouken@2873
   311
    }
slouken@2873
   312
    if ((data->saved_view.x != 0) || (data->saved_view.y != 0)) {
slouken@2874
   313
        SDL_NAME(XF86VidModeSetViewPort) (display, data->screen,
slouken@2874
   314
                                          data->saved_view.x,
slouken@2874
   315
                                          data->saved_view.y);
slouken@2873
   316
    }
slouken@2873
   317
}
slouken@2873
   318
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@2873
   319
slouken@1950
   320
void
slouken@1950
   321
X11_GetDisplayModes(_THIS)
slouken@1950
   322
{
slouken@2870
   323
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@1950
   324
    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
slouken@2873
   325
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   326
    int xinerama_major, xinerama_minor;
slouken@2873
   327
    int screens;
slouken@2874
   328
    SDL_NAME(XineramaScreenInfo) * xinerama;
slouken@2873
   329
#endif
slouken@2873
   330
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   331
    int xrandr_major, xrandr_minor;
slouken@2873
   332
    int nsizes, nrates;
slouken@2873
   333
    XRRScreenSize *sizes;
slouken@2873
   334
    short *rates;
slouken@2873
   335
#endif
slouken@2873
   336
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@2873
   337
    int vm_major, vm_minor;
slouken@2873
   338
    int nmodes;
slouken@2874
   339
    SDL_NAME(XF86VidModeModeInfo) ** modes;
slouken@2873
   340
#endif
slouken@2873
   341
    int screen_w;
slouken@2873
   342
    int screen_h;
slouken@1950
   343
    SDL_DisplayMode mode;
slouken@2870
   344
slouken@2873
   345
    /* Unfortunately X11 requires the window to be created with the correct
slouken@2873
   346
     * visual and depth ahead of time, but the SDL API allows you to create
slouken@2873
   347
     * a window before setting the fullscreen display mode.  This means that
slouken@2873
   348
     * we have to use the same format for all windows and all display modes.
slouken@2873
   349
     * (or support recreating the window with a new visual behind the scenes)
slouken@2873
   350
     */
slouken@2873
   351
    mode.format = SDL_CurrentDisplay.current_mode.format;
slouken@2873
   352
    mode.driverdata = NULL;
slouken@2873
   353
slouken@2873
   354
    data->use_xinerama = 0;
slouken@2873
   355
    data->use_xrandr = 0;
slouken@2873
   356
    data->use_vidmode = 0;
slouken@2873
   357
    screen_w = DisplayWidth(display, data->screen);
slouken@2873
   358
    screen_h = DisplayHeight(display, data->screen);
slouken@2873
   359
slouken@2873
   360
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   361
    /* Query Xinerama extention */
slouken@2873
   362
    if (CheckXinerama(display, &xinerama_major, &xinerama_minor)) {
slouken@2873
   363
#ifdef X11MODES_DEBUG
slouken@2873
   364
        printf("X11 detected Xinerama:\n");
slouken@2873
   365
#endif
slouken@2874
   366
        xinerama = SDL_NAME(XineramaQueryScreens) (display, &screens);
slouken@2873
   367
        if (xinerama) {
slouken@2873
   368
            int i;
slouken@2873
   369
            for (i = 0; i < screens; i++) {
slouken@2873
   370
#ifdef X11MODES_DEBUG
slouken@2873
   371
                printf("xinerama %d: %dx%d+%d+%d\n",
slouken@2874
   372
                       xinerama[i].screen_number,
slouken@2874
   373
                       xinerama[i].width, xinerama[i].height,
slouken@2874
   374
                       xinerama[i].x_org, xinerama[i].y_org);
slouken@2873
   375
#endif
slouken@2873
   376
                if (xinerama[i].screen_number == data->screen) {
slouken@2874
   377
                    data->use_xinerama =
slouken@2874
   378
                        xinerama_major * 100 + xinerama_minor;
slouken@2873
   379
                    data->xinerama_info = xinerama[i];
slouken@2873
   380
                }
slouken@2873
   381
            }
slouken@2873
   382
            XFree(xinerama);
slouken@2873
   383
        }
slouken@2873
   384
slouken@2873
   385
        if (data->use_xinerama) {
slouken@2873
   386
            /* Add the full xinerama mode */
slouken@2873
   387
            if (screen_w > data->xinerama_info.width ||
slouken@2873
   388
                screen_h > data->xinerama_info.height) {
slouken@2873
   389
                mode.w = screen_w;
slouken@2873
   390
                mode.h = screen_h;
slouken@2873
   391
                mode.refresh_rate = 0;
slouken@2873
   392
                SDL_AddDisplayMode(_this->current_display, &mode);
slouken@2873
   393
            }
slouken@2873
   394
slouken@2873
   395
            /* Add the head xinerama mode */
slouken@2873
   396
            mode.w = data->xinerama_info.width;
slouken@2873
   397
            mode.h = data->xinerama_info.height;
slouken@2873
   398
            mode.refresh_rate = 0;
slouken@2873
   399
            SDL_AddDisplayMode(_this->current_display, &mode);
slouken@2873
   400
        }
slouken@2873
   401
    }
slouken@2873
   402
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   403
slouken@2873
   404
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   405
    /* XRandR */
slouken@2873
   406
    /* require at least XRandR v1.0 (arbitrary) */
slouken@2874
   407
    if (CheckXRandR(display, &xrandr_major, &xrandr_minor)
slouken@2874
   408
        && xrandr_major >= 1) {
slouken@2873
   409
#ifdef X11MODES_DEBUG
slouken@2873
   410
        fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n",
slouken@2873
   411
                xrandr_major, xrandr_minor);
slouken@2873
   412
#endif
slouken@2873
   413
slouken@2873
   414
        /* save the screen configuration since we must reference it
slouken@2873
   415
           each time we toggle modes.
slouken@2874
   416
         */
slouken@2874
   417
        data->screen_config =
slouken@2874
   418
            XRRGetScreenInfo(display, RootWindow(display, data->screen));
slouken@2873
   419
slouken@2873
   420
        /* retrieve the list of resolution */
slouken@2873
   421
        sizes = XRRConfigSizes(data->screen_config, &nsizes);
slouken@2873
   422
        if (nsizes > 0) {
slouken@2873
   423
            int i, j;
slouken@2874
   424
            for (i = 0; i < nsizes; i++) {
slouken@2873
   425
                mode.w = sizes[i].width;
slouken@2873
   426
                mode.h = sizes[i].height;
slouken@2873
   427
slouken@2873
   428
                rates = XRRConfigRates(data->screen_config, i, &nrates);
slouken@2873
   429
                for (j = 0; j < nrates; ++j) {
slouken@2873
   430
                    mode.refresh_rate = rates[j];
slouken@2873
   431
#ifdef X11MODES_DEBUG
slouken@2874
   432
                    fprintf(stderr,
slouken@2874
   433
                            "XRANDR: mode = %4d[%d], w = %4d, h = %4d, rate = %4d\n",
slouken@2873
   434
                            i, j, mode.w, mode.h, mode.refresh_rate);
slouken@2873
   435
#endif
slouken@2873
   436
                    SDL_AddDisplayMode(_this->current_display, &mode);
slouken@2873
   437
                }
slouken@2873
   438
            }
slouken@2873
   439
slouken@2873
   440
            data->use_xrandr = xrandr_major * 100 + xrandr_minor;
slouken@2874
   441
            data->saved_size =
slouken@2874
   442
                XRRConfigCurrentConfiguration(data->screen_config,
slouken@2874
   443
                                              &data->saved_rotation);
slouken@2873
   444
            data->saved_rate = XRRConfigCurrentRate(data->screen_config);
slouken@2873
   445
        }
slouken@2873
   446
    }
slouken@2873
   447
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   448
slouken@2873
   449
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@2873
   450
    /* XVidMode */
slouken@2873
   451
    if (!data->use_xrandr &&
slouken@2873
   452
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   453
        (!data->use_xinerama || data->xinerama_info.screen_number == 0) &&
slouken@2873
   454
#endif
slouken@2873
   455
        CheckVidMode(display, &vm_major, &vm_minor) &&
slouken@2874
   456
        SDL_NAME(XF86VidModeGetAllModeLines) (display, data->screen, &nmodes,
slouken@2874
   457
                                              &modes)) {
slouken@2873
   458
        int i;
slouken@2873
   459
slouken@2873
   460
#ifdef X11MODES_DEBUG
slouken@2873
   461
        printf("VidMode modes: (unsorted)\n");
slouken@2873
   462
        for (i = 0; i < nmodes; ++i) {
slouken@2873
   463
            printf("Mode %d: %d x %d @ %d\n", i,
slouken@2874
   464
                   modes[i]->hdisplay, modes[i]->vdisplay,
slouken@2874
   465
                   calculate_rate(modes[i]));
slouken@2873
   466
        }
slouken@2873
   467
#endif
slouken@2873
   468
        for (i = 0; i < nmodes; ++i) {
slouken@2873
   469
            mode.w = modes[i]->hdisplay;
slouken@2873
   470
            mode.h = modes[i]->vdisplay;
slouken@2873
   471
            mode.refresh_rate = calculate_rate(modes[i]);
slouken@2873
   472
            SDL_AddDisplayMode(_this->current_display, &mode);
slouken@2873
   473
        }
slouken@2873
   474
        XFree(modes);
slouken@2873
   475
slouken@2873
   476
        data->use_vidmode = vm_major * 100 + vm_minor;
slouken@2873
   477
        save_mode(display, data);
slouken@2873
   478
    }
slouken@2873
   479
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@2873
   480
slouken@2873
   481
    if (!data->use_xrandr && !data->use_vidmode) {
slouken@2873
   482
        mode.w = screen_w;
slouken@2873
   483
        mode.h = screen_h;
slouken@2873
   484
        mode.refresh_rate = 0;
slouken@2873
   485
        SDL_AddDisplayMode(_this->current_display, &mode);
slouken@2874
   486
    }
slouken@2873
   487
#ifdef X11MODES_DEBUG
slouken@2873
   488
    if (data->use_xinerama) {
slouken@2873
   489
        printf("Xinerama is enabled\n");
slouken@2873
   490
    }
slouken@2873
   491
slouken@2873
   492
    if (data->use_xrandr) {
slouken@2873
   493
        printf("XRandR is enabled\n");
slouken@2873
   494
    }
slouken@2873
   495
slouken@2873
   496
    if (data->use_vidmode) {
slouken@2873
   497
        printf("VidMode is enabled\n");
slouken@2873
   498
    }
slouken@2873
   499
#endif /* X11MODES_DEBUG */
slouken@2873
   500
}
slouken@2873
   501
slouken@2873
   502
static void
slouken@2874
   503
get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h,
slouken@2874
   504
                    int *rate)
slouken@2873
   505
{
slouken@2873
   506
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   507
    if (data->use_xrandr) {
slouken@2873
   508
        int nsizes;
slouken@2873
   509
        XRRScreenSize *sizes;
slouken@2874
   510
slouken@2873
   511
        sizes = XRRConfigSizes(data->screen_config, &nsizes);
slouken@2873
   512
        if (nsizes > 0) {
slouken@2873
   513
            int cur_size;
slouken@2873
   514
            Rotation cur_rotation;
slouken@2873
   515
slouken@2874
   516
            cur_size =
slouken@2874
   517
                XRRConfigCurrentConfiguration(data->screen_config,
slouken@2874
   518
                                              &cur_rotation);
slouken@2873
   519
            *w = sizes[cur_size].width;
slouken@2873
   520
            *h = sizes[cur_size].height;
slouken@2873
   521
            *rate = XRRConfigCurrentRate(data->screen_config);
slouken@2873
   522
#ifdef X11MODES_DEBUG
slouken@2874
   523
            fprintf(stderr,
slouken@2874
   524
                    "XRANDR: get_real_resolution: w = %d, h = %d, rate = %d\n",
slouken@2874
   525
                    *w, *h, *rate);
slouken@2873
   526
#endif
slouken@2873
   527
            return;
slouken@2873
   528
        }
slouken@2873
   529
    }
slouken@2873
   530
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   531
slouken@2873
   532
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@2873
   533
    if (data->use_vidmode) {
slouken@2873
   534
        SDL_NAME(XF86VidModeModeInfo) mode;
slouken@2873
   535
slouken@2874
   536
        if (SDL_NAME(XF86VidModeGetModeInfo) (display, data->screen, &mode)) {
slouken@2873
   537
            *w = mode.hdisplay;
slouken@2873
   538
            *h = mode.vdisplay;
slouken@2873
   539
            *rate = calculate_rate(&mode);
slouken@2873
   540
            return;
slouken@2873
   541
        }
slouken@2873
   542
    }
slouken@2873
   543
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@2873
   544
slouken@2873
   545
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   546
    if (data->use_xinerama) {
slouken@2873
   547
        *w = data->xinerama_info.width;
slouken@2873
   548
        *h = data->xinerama_info.height;
slouken@2873
   549
        *rate = 0;
slouken@2873
   550
        return;
slouken@2873
   551
    }
slouken@2873
   552
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   553
slouken@2873
   554
    *w = DisplayWidth(display, data->screen);
slouken@2873
   555
    *h = DisplayHeight(display, data->screen);
slouken@2873
   556
    *rate = 0;
slouken@2873
   557
}
slouken@2873
   558
slouken@2873
   559
static void
slouken@2874
   560
set_best_resolution(Display * display, SDL_DisplayData * data, int w, int h,
slouken@2874
   561
                    int rate)
slouken@2873
   562
{
slouken@2873
   563
    int real_w, real_h, real_rate;
slouken@2873
   564
slouken@2873
   565
    /* check current mode so we can avoid uneccessary mode changes */
slouken@2873
   566
    get_real_resolution(display, data, &real_w, &real_h, &real_rate);
slouken@2873
   567
    if (w == real_w && h == real_h && (!rate || rate == real_rate)) {
slouken@2873
   568
        return;
slouken@2873
   569
    }
slouken@2873
   570
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   571
    if (data->use_xrandr) {
slouken@2873
   572
#ifdef X11MODES_DEBUG
slouken@2873
   573
        fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n",
slouken@2873
   574
                w, h);
slouken@2873
   575
#endif
slouken@2873
   576
        int i, nsizes, nrates;
slouken@2873
   577
        int best;
slouken@2873
   578
        int best_rate;
slouken@2873
   579
        XRRScreenSize *sizes;
slouken@2873
   580
        short *rates;
slouken@2873
   581
slouken@2873
   582
        /* find the smallest resolution that is at least as big as the user requested */
slouken@2873
   583
        best = -1;
slouken@2873
   584
        sizes = XRRConfigSizes(data->screen_config, &nsizes);
slouken@2873
   585
        for (i = 0; i < nsizes; ++i) {
slouken@2873
   586
            if (sizes[i].width < w || sizes[i].height < h) {
slouken@2873
   587
                continue;
slouken@2873
   588
            }
slouken@2873
   589
            if (sizes[i].width == w && sizes[i].height == h) {
slouken@2873
   590
                best = i;
slouken@2873
   591
                break;
slouken@2873
   592
            }
slouken@2873
   593
            if (best == -1 ||
slouken@2873
   594
                (sizes[i].width < sizes[best].width) ||
slouken@2874
   595
                (sizes[i].width == sizes[best].width
slouken@2874
   596
                 && sizes[i].height < sizes[best].height)) {
slouken@2873
   597
                best = i;
slouken@2873
   598
            }
slouken@2873
   599
        }
slouken@2873
   600
slouken@2873
   601
        if (best >= 0) {
slouken@2873
   602
            best_rate = 0;
slouken@2873
   603
            rates = XRRConfigRates(data->screen_config, best, &nrates);
slouken@2873
   604
            for (i = 0; i < nrates; ++i) {
slouken@2873
   605
                if (rates[i] == rate) {
slouken@2873
   606
                    best_rate = rate;
slouken@2873
   607
                    break;
slouken@2873
   608
                }
slouken@2873
   609
                if (!rate) {
slouken@2873
   610
                    /* Higher is better, right? */
slouken@2873
   611
                    if (rates[i] > best_rate) {
slouken@2873
   612
                        best_rate = rates[i];
slouken@2873
   613
                    }
slouken@2873
   614
                } else {
slouken@2874
   615
                    if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) {
slouken@2873
   616
                        best_rate = rates[i];
slouken@2873
   617
                    }
slouken@2873
   618
                }
slouken@2873
   619
            }
slouken@2874
   620
            XRRSetScreenConfigAndRate(display, data->screen_config,
slouken@2874
   621
                                      RootWindow(display, data->screen), best,
slouken@2874
   622
                                      data->saved_rotation, best_rate,
slouken@2874
   623
                                      CurrentTime);
slouken@2873
   624
        }
slouken@2873
   625
        return;
slouken@2873
   626
    }
slouken@2873
   627
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   628
slouken@2873
   629
#if SDL_VIDEO_DRIVER_X11_VIDMODE
slouken@2873
   630
    if (data->use_vidmode) {
slouken@2874
   631
        SDL_NAME(XF86VidModeModeInfo) ** modes;
slouken@2873
   632
        int i, nmodes;
slouken@2873
   633
        int best;
slouken@2873
   634
slouken@2874
   635
        if (SDL_NAME(XF86VidModeGetAllModeLines)
slouken@2874
   636
            (display, data->screen, &nmodes, &modes)) {
slouken@2873
   637
            best = -1;
slouken@2873
   638
            for (i = 0; i < nmodes; ++i) {
slouken@2873
   639
                if (modes[i]->hdisplay < w || modes[i]->vdisplay < h) {
slouken@2873
   640
                    continue;
slouken@2873
   641
                }
slouken@2873
   642
                if (best == -1 ||
slouken@2873
   643
                    (modes[i]->hdisplay < modes[best]->hdisplay) ||
slouken@2874
   644
                    (modes[i]->hdisplay == modes[best]->hdisplay
slouken@2874
   645
                     && modes[i]->vdisplay < modes[best]->vdisplay)) {
slouken@2873
   646
                    best = i;
slouken@2873
   647
                    continue;
slouken@2873
   648
                }
slouken@2873
   649
                if ((modes[i]->hdisplay == modes[best]->hdisplay) &&
slouken@2873
   650
                    (modes[i]->vdisplay == modes[best]->vdisplay)) {
slouken@2873
   651
                    if (!rate) {
slouken@2873
   652
                        /* Higher is better, right? */
slouken@2874
   653
                        if (calculate_rate(modes[i]) >
slouken@2874
   654
                            calculate_rate(modes[best])) {
slouken@2873
   655
                            best = i;
slouken@2873
   656
                        }
slouken@2873
   657
                    } else {
slouken@2874
   658
                        if (SDL_abs(calculate_rate(modes[i]) - rate) <
slouken@2874
   659
                            SDL_abs(calculate_rate(modes[best]) - rate)) {
slouken@2873
   660
                            best = i;
slouken@2873
   661
                        }
slouken@2873
   662
                    }
slouken@2873
   663
                }
slouken@2873
   664
            }
slouken@2873
   665
            if (best >= 0) {
slouken@2873
   666
#ifdef X11MODES_DEBUG
slouken@2873
   667
                printf("Best Mode %d: %d x %d @ %d\n", best,
slouken@2874
   668
                       modes[best]->hdisplay, modes[best]->vdisplay,
slouken@2874
   669
                       calculate_rate(modes[best]));
slouken@2873
   670
#endif
slouken@2874
   671
                SDL_NAME(XF86VidModeSwitchToMode) (display, data->screen,
slouken@2874
   672
                                                   modes[best]);
slouken@2873
   673
            }
slouken@2873
   674
            XFree(modes);
slouken@2873
   675
        }
slouken@2873
   676
        return;
slouken@2873
   677
    }
slouken@2873
   678
#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
slouken@1950
   679
}
slouken@1950
   680
slouken@1950
   681
int
slouken@1950
   682
X11_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
slouken@1950
   683
{
slouken@2873
   684
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@2873
   685
    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
slouken@2873
   686
slouken@2873
   687
    set_best_resolution(display, data, mode->w, mode->h, mode->refresh_rate);
slouken@2873
   688
    return 0;
slouken@1950
   689
}
slouken@1950
   690
slouken@1950
   691
void
slouken@1950
   692
X11_QuitModes(_THIS)
slouken@1950
   693
{
slouken@1950
   694
}
slouken@1950
   695
slouken@1950
   696
/* vi: set ts=4 sw=4 expandtab: */