src/video/x11/SDL_x11modes.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 24 Oct 2011 15:33:58 -0400
changeset 6027 56185b574d61
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Use correct Xinerama APIs for querying version and availability.

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