src/video/x11/SDL_x11modes.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 07 Dec 2012 23:26:28 -0500
changeset 6724 6c5ed0c4cc6d
parent 6566 dd7e57847ea9
child 6796 424a12862805
permissions -rw-r--r--
X11 msgbox: try to protect the existing setlocale() state.
slouken@1950
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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@6472
    25
#include "SDL_hints.h"
slouken@1950
    26
#include "SDL_x11video.h"
slouken@1950
    27
slouken@6559
    28
/*#define X11MODES_DEBUG*/
slouken@6558
    29
slouken@6559
    30
/* I'm becoming more and more convinced that the application should never
slouken@6559
    31
 * use XRandR, and it's the window manager's responsibility to track and
slouken@6559
    32
 * manage display modes for fullscreen windows.  Right now XRandR is completely
slouken@6559
    33
 * broken with respect to window manager behavior on every window manager that
slouken@6559
    34
 * I can find.  For example, on Unity 3D if you show a fullscreen window while
slouken@6559
    35
 * the resolution is changing (within ~250 ms) your window will retain the
slouken@6559
    36
 * fullscreen state hint but be decorated and windowed.
slouken@6558
    37
*/
slouken@6558
    38
#define XRANDR_DISABLED_BY_DEFAULT
slouken@6558
    39
slouken@1950
    40
slouken@1950
    41
static int
slouken@1950
    42
get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
slouken@1950
    43
{
slouken@1950
    44
    const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
slouken@1950
    45
    int depth;
slouken@1950
    46
slouken@1950
    47
    /* Look for an exact visual, if requested */
slouken@1950
    48
    if (visual_id) {
slouken@3697
    49
        XVisualInfo *vi, template;
slouken@3697
    50
        int nvis;
slouken@1950
    51
slouken@1950
    52
        SDL_zero(template);
slouken@1950
    53
        template.visualid = SDL_strtol(visual_id, NULL, 0);
slouken@1950
    54
        vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
slouken@1950
    55
        if (vi) {
slouken@1950
    56
            *vinfo = *vi;
slouken@1950
    57
            XFree(vi);
slouken@1950
    58
            return 0;
slouken@1950
    59
        }
slouken@1950
    60
    }
slouken@3697
    61
slouken@1950
    62
    depth = DefaultDepth(display, screen);
slouken@5466
    63
    if ((X11_UseDirectColorVisuals() &&
slouken@5466
    64
         XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
slouken@5466
    65
        XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
slouken@1950
    66
        XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
slouken@1950
    67
        XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
slouken@1950
    68
        return 0;
slouken@1950
    69
    }
slouken@1950
    70
    return -1;
slouken@1950
    71
}
slouken@1950
    72
slouken@5182
    73
int
slouken@5182
    74
X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
slouken@5182
    75
{
slouken@5182
    76
    XVisualInfo *vi;
slouken@5182
    77
    int nvis;
slouken@5182
    78
slouken@5182
    79
    vinfo->visualid = XVisualIDFromVisual(visual);
slouken@5182
    80
    vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
slouken@5182
    81
    if (vi) {
slouken@5182
    82
        *vinfo = *vi;
slouken@5182
    83
        XFree(vi);
slouken@5182
    84
        return 0;
slouken@5182
    85
    }
slouken@5182
    86
    return -1;
slouken@5182
    87
}
slouken@5182
    88
slouken@5182
    89
Uint32
slouken@2874
    90
X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
slouken@2870
    91
{
slouken@2870
    92
    if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
slouken@2870
    93
        int bpp;
slouken@2870
    94
        Uint32 Rmask, Gmask, Bmask, Amask;
slouken@2870
    95
slouken@2870
    96
        Rmask = vinfo->visual->red_mask;
slouken@2870
    97
        Gmask = vinfo->visual->green_mask;
slouken@2870
    98
        Bmask = vinfo->visual->blue_mask;
slouken@2870
    99
        if (vinfo->depth == 32) {
slouken@2870
   100
            Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
slouken@2870
   101
        } else {
slouken@2870
   102
            Amask = 0;
slouken@2870
   103
        }
slouken@2870
   104
slouken@2870
   105
        bpp = vinfo->depth;
slouken@2870
   106
        if (bpp == 24) {
slouken@2870
   107
            int i, n;
slouken@2870
   108
            XPixmapFormatValues *p = XListPixmapFormats(display, &n);
slouken@2870
   109
            if (p) {
slouken@2870
   110
                for (i = 0; i < n; ++i) {
slouken@2870
   111
                    if (p[i].depth == 24) {
slouken@2870
   112
                        bpp = p[i].bits_per_pixel;
slouken@2870
   113
                        break;
slouken@2870
   114
                    }
slouken@2870
   115
                }
slouken@2870
   116
                XFree(p);
slouken@2870
   117
            }
slouken@2870
   118
        }
slouken@2870
   119
slouken@2870
   120
        return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
slouken@2870
   121
    }
slouken@2870
   122
slouken@2870
   123
    if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
slouken@2870
   124
        switch (vinfo->depth) {
slouken@2870
   125
        case 8:
slouken@2870
   126
            return SDL_PIXELTYPE_INDEX8;
slouken@2870
   127
        case 4:
slouken@2870
   128
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   129
                return SDL_PIXELFORMAT_INDEX4LSB;
slouken@2870
   130
            } else {
slouken@2870
   131
                return SDL_PIXELFORMAT_INDEX4MSB;
slouken@2870
   132
            }
slouken@2870
   133
            break;
slouken@2870
   134
        case 1:
slouken@2870
   135
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   136
                return SDL_PIXELFORMAT_INDEX1LSB;
slouken@2870
   137
            } else {
slouken@2870
   138
                return SDL_PIXELFORMAT_INDEX1MSB;
slouken@2870
   139
            }
slouken@2870
   140
            break;
slouken@2870
   141
        }
slouken@2870
   142
    }
slouken@2870
   143
slouken@2870
   144
    return SDL_PIXELFORMAT_UNKNOWN;
slouken@2870
   145
}
slouken@1950
   146
slouken@2873
   147
/* Global for the error handler */
slouken@2873
   148
int vm_event, vm_error = -1;
slouken@2873
   149
slouken@2873
   150
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   151
static SDL_bool
slouken@2874
   152
CheckXinerama(Display * display, int *major, int *minor)
slouken@2873
   153
{
icculus@6027
   154
    int event_base = 0;
icculus@6027
   155
    int error_base = 0;
slouken@2873
   156
    const char *env;
slouken@2873
   157
slouken@2873
   158
    /* Default the extension not available */
slouken@2873
   159
    *major = *minor = 0;
slouken@2873
   160
slouken@2873
   161
    /* Allow environment override */
slouken@6472
   162
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA);
slouken@2873
   163
    if (env && !SDL_atoi(env)) {
slouken@6468
   164
#ifdef X11MODES_DEBUG
slouken@6472
   165
        printf("Xinerama disabled due to hint\n");
slouken@6468
   166
#endif
slouken@2873
   167
        return SDL_FALSE;
slouken@2873
   168
    }
slouken@2873
   169
slouken@5408
   170
    if (!SDL_X11_HAVE_XINERAMA) {
slouken@6468
   171
#ifdef X11MODES_DEBUG
slouken@6468
   172
        printf("Xinerama support not available\n");
slouken@6468
   173
#endif
slouken@5408
   174
        return SDL_FALSE;
slouken@5408
   175
    }
slouken@5408
   176
slouken@2873
   177
    /* Query the extension version */
icculus@6027
   178
    if (!XineramaQueryExtension(display, &event_base, &error_base) ||
icculus@6027
   179
        !XineramaQueryVersion(display, major, minor) ||
slouken@5408
   180
        !XineramaIsActive(display)) {
slouken@6468
   181
#ifdef X11MODES_DEBUG
slouken@6468
   182
        printf("Xinerama not active on the display\n");
slouken@6468
   183
#endif
slouken@2873
   184
        return SDL_FALSE;
slouken@2873
   185
    }
slouken@6468
   186
#ifdef X11MODES_DEBUG
slouken@6548
   187
    printf("Xinerama available at version %d.%d!\n", *major, *minor);
slouken@6468
   188
#endif
slouken@2873
   189
    return SDL_TRUE;
slouken@2873
   190
}
slouken@2873
   191
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   192
slouken@2873
   193
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   194
static SDL_bool
slouken@2874
   195
CheckXRandR(Display * display, int *major, int *minor)
slouken@2873
   196
{
slouken@2873
   197
    const char *env;
slouken@2873
   198
slouken@2873
   199
    /* Default the extension not available */
slouken@2873
   200
    *major = *minor = 0;
slouken@2873
   201
slouken@2873
   202
    /* Allow environment override */
slouken@6472
   203
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR);
slouken@6558
   204
#ifdef XRANDR_DISABLED_BY_DEFAULT
slouken@6558
   205
    if (!env || !SDL_atoi(env)) {
slouken@6558
   206
#ifdef X11MODES_DEBUG
slouken@6558
   207
        printf("XRandR disabled by default due to window manager issues\n");
slouken@6558
   208
#endif
slouken@6558
   209
        return SDL_FALSE;
slouken@6558
   210
    }
slouken@6558
   211
#else
slouken@2873
   212
    if (env && !SDL_atoi(env)) {
slouken@6468
   213
#ifdef X11MODES_DEBUG
slouken@6472
   214
        printf("XRandR disabled due to hint\n");
slouken@6468
   215
#endif
slouken@2873
   216
        return SDL_FALSE;
slouken@2873
   217
    }
slouken@6558
   218
#endif /* XRANDR_ENABLED_BY_DEFAULT */
slouken@2873
   219
slouken@2873
   220
    if (!SDL_X11_HAVE_XRANDR) {
slouken@6468
   221
#ifdef X11MODES_DEBUG
slouken@6468
   222
        printf("XRandR support not available\n");
slouken@6468
   223
#endif
slouken@2873
   224
        return SDL_FALSE;
slouken@2873
   225
    }
slouken@2873
   226
slouken@2873
   227
    /* Query the extension version */
slouken@2873
   228
    if (!XRRQueryVersion(display, major, minor)) {
slouken@6468
   229
#ifdef X11MODES_DEBUG
slouken@6468
   230
        printf("XRandR not active on the display\n");
slouken@6468
   231
#endif
slouken@2873
   232
        return SDL_FALSE;
slouken@2873
   233
    }
slouken@6468
   234
#ifdef X11MODES_DEBUG
slouken@6548
   235
    printf("XRandR available at version %d.%d!\n", *major, *minor);
slouken@6468
   236
#endif
slouken@2873
   237
    return SDL_TRUE;
slouken@2873
   238
}
slouken@6537
   239
slouken@6537
   240
#define XRANDR_ROTATION_LEFT    (1 << 1)
slouken@6537
   241
#define XRANDR_ROTATION_RIGHT   (1 << 3)
slouken@6537
   242
slouken@6548
   243
static int
slouken@6548
   244
CalculateXRandRRefreshRate(const XRRModeInfo *info)
slouken@6537
   245
{
slouken@6548
   246
    return (info->hTotal
slouken@6551
   247
            && info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0;
slouken@6548
   248
}
slouken@6548
   249
slouken@6548
   250
static SDL_bool
slouken@6548
   251
SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
slouken@6548
   252
                  RRMode modeID, SDL_DisplayMode *mode)
slouken@6548
   253
{
slouken@6548
   254
    int i;
slouken@6548
   255
    for (i = 0; i < res->nmode; ++i) {
slouken@6548
   256
        if (res->modes[i].id == modeID) {
slouken@6548
   257
            XRRCrtcInfo *crtc;
slouken@6548
   258
            Rotation rotation = 0;
slouken@6548
   259
            const XRRModeInfo *info = &res->modes[i];
slouken@6548
   260
slouken@6548
   261
            crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
slouken@6548
   262
            if (crtc) {
slouken@6548
   263
                rotation = crtc->rotation;
slouken@6548
   264
                XRRFreeCrtcInfo(crtc);
slouken@6548
   265
            }
slouken@6548
   266
slouken@6548
   267
            if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
slouken@6548
   268
                mode->w = info->height;
slouken@6548
   269
                mode->h = info->width;
slouken@6548
   270
            } else {
slouken@6548
   271
                mode->w = info->width;
slouken@6548
   272
                mode->h = info->height;
slouken@6548
   273
            }
slouken@6548
   274
            mode->refresh_rate = CalculateXRandRRefreshRate(info);
slouken@6548
   275
            ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
slouken@6548
   276
#ifdef X11MODES_DEBUG
icculus@6560
   277
            printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
slouken@6548
   278
#endif
slouken@6548
   279
            return SDL_TRUE;
slouken@6548
   280
        }
slouken@6537
   281
    }
slouken@6548
   282
    return SDL_FALSE;
slouken@6537
   283
}
slouken@2873
   284
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   285
slouken@5408
   286
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   287
static SDL_bool
slouken@2874
   288
CheckVidMode(Display * display, int *major, int *minor)
slouken@2873
   289
{
slouken@2873
   290
    const char *env;
slouken@2873
   291
slouken@2873
   292
    /* Default the extension not available */
slouken@2873
   293
    *major = *minor = 0;
slouken@2873
   294
slouken@2873
   295
    /* Allow environment override */
slouken@6472
   296
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
slouken@2873
   297
    if (env && !SDL_atoi(env)) {
slouken@6468
   298
#ifdef X11MODES_DEBUG
slouken@6472
   299
        printf("XVidMode disabled due to hint\n");
slouken@6468
   300
#endif
slouken@2873
   301
        return SDL_FALSE;
slouken@2873
   302
    }
slouken@2874
   303
slouken@5408
   304
    if (!SDL_X11_HAVE_XVIDMODE) {
slouken@6468
   305
#ifdef X11MODES_DEBUG
slouken@6468
   306
        printf("XVidMode support not available\n");
slouken@6468
   307
#endif
slouken@5408
   308
        return SDL_FALSE;
slouken@5408
   309
    }
slouken@5408
   310
slouken@2873
   311
    /* Query the extension version */
slouken@2873
   312
    vm_error = -1;
slouken@5408
   313
    if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
slouken@5408
   314
        || !XF86VidModeQueryVersion(display, major, minor)) {
slouken@6468
   315
#ifdef X11MODES_DEBUG
slouken@6468
   316
        printf("XVidMode not active on the display\n");
slouken@6468
   317
#endif
slouken@2873
   318
        return SDL_FALSE;
slouken@2873
   319
    }
slouken@6468
   320
#ifdef X11MODES_DEBUG
slouken@6548
   321
    printf("XVidMode available at version %d.%d!\n", *major, *minor);
slouken@6468
   322
#endif
slouken@2873
   323
    return SDL_TRUE;
slouken@2873
   324
}
slouken@2873
   325
slouken@4518
   326
static
slouken@5408
   327
Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
slouken@5408
   328
                                       XF86VidModeModeInfo* info)
slouken@2873
   329
{
slouken@2873
   330
    Bool retval;
slouken@2873
   331
    int dotclock;
slouken@5408
   332
    XF86VidModeModeLine l;
slouken@2873
   333
    SDL_zerop(info);
slouken@2873
   334
    SDL_zero(l);
slouken@5408
   335
    retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
slouken@2873
   336
    info->dotclock = dotclock;
slouken@2873
   337
    info->hdisplay = l.hdisplay;
slouken@2873
   338
    info->hsyncstart = l.hsyncstart;
slouken@2873
   339
    info->hsyncend = l.hsyncend;
slouken@2873
   340
    info->htotal = l.htotal;
slouken@2873
   341
    info->hskew = l.hskew;
slouken@2873
   342
    info->vdisplay = l.vdisplay;
slouken@2873
   343
    info->vsyncstart = l.vsyncstart;
slouken@2873
   344
    info->vsyncend = l.vsyncend;
slouken@2873
   345
    info->vtotal = l.vtotal;
slouken@2873
   346
    info->flags = l.flags;
slouken@2873
   347
    info->privsize = l.privsize;
slouken@2873
   348
    info->private = l.private;
slouken@2873
   349
    return retval;
slouken@2873
   350
}
slouken@2873
   351
slouken@2873
   352
static int
slouken@6548
   353
CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
slouken@2873
   354
{
slouken@2874
   355
    return (info->htotal
slouken@2874
   356
            && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
slouken@2874
   357
                                                         info->vtotal)) : 0;
slouken@2873
   358
}
slouken@2873
   359
slouken@6548
   360
SDL_bool
slouken@6548
   361
SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
slouken@2873
   362
{
slouken@6548
   363
    mode->w = info->hdisplay;
slouken@6548
   364
    mode->h = info->vdisplay;
slouken@6548
   365
    mode->refresh_rate = CalculateXVidModeRefreshRate(info);
slouken@6548
   366
    ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
slouken@6548
   367
    return SDL_TRUE;
slouken@2873
   368
}
slouken@6548
   369
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@2873
   370
slouken@6548
   371
int
slouken@6548
   372
X11_InitModes(_THIS)
slouken@2873
   373
{
slouken@6548
   374
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@6548
   375
    int screen, screencount;
slouken@6548
   376
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   377
    int xinerama_major, xinerama_minor;
slouken@6548
   378
    int use_xinerama = 0;
slouken@6548
   379
    XineramaScreenInfo *xinerama = NULL;
slouken@6548
   380
#endif
slouken@6548
   381
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   382
    int xrandr_major, xrandr_minor;
slouken@6548
   383
    int use_xrandr = 0;
slouken@6548
   384
    XRRScreenResources *res = NULL;
slouken@6548
   385
#endif
slouken@6548
   386
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   387
    int vm_major, vm_minor;
slouken@6548
   388
    int use_vidmode = 0;
slouken@6548
   389
#endif
slouken@2873
   390
slouken@6548
   391
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   392
    /* Query Xinerama extention
slouken@6548
   393
     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
slouken@6548
   394
     *       or newer of the Nvidia binary drivers
slouken@6548
   395
     */
slouken@6548
   396
    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
slouken@6548
   397
        xinerama = XineramaQueryScreens(data->display, &screencount);
slouken@6548
   398
        if (xinerama) {
slouken@6548
   399
            use_xinerama = xinerama_major * 100 + xinerama_minor;
slouken@2873
   400
        }
slouken@2873
   401
    }
slouken@6548
   402
    if (!xinerama) {
slouken@6548
   403
        screencount = ScreenCount(data->display);
slouken@2873
   404
    }
slouken@6548
   405
#else
slouken@6548
   406
    screencount = ScreenCount(data->display);
slouken@6548
   407
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@6548
   408
slouken@6548
   409
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   410
    /* require at least XRandR v1.2 */
slouken@6548
   411
    if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
slouken@6548
   412
        (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
slouken@6548
   413
        use_xrandr = xrandr_major * 100 + xrandr_minor;
slouken@6548
   414
    }
slouken@6548
   415
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@6548
   416
slouken@6548
   417
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   418
    if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
slouken@6548
   419
        use_vidmode = vm_major * 100 + vm_minor;
slouken@6548
   420
    }
slouken@6548
   421
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   422
slouken@6548
   423
    for (screen = 0; screen < screencount; ++screen) {
slouken@6548
   424
        XVisualInfo vinfo;
slouken@6548
   425
        SDL_VideoDisplay display;
slouken@6548
   426
        SDL_DisplayData *displaydata;
slouken@6548
   427
        SDL_DisplayMode mode;
slouken@6548
   428
        SDL_DisplayModeData *modedata;
slouken@6548
   429
        XPixmapFormatValues *pixmapFormats;
slouken@6548
   430
        int i, n;
slouken@6548
   431
slouken@6548
   432
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   433
        if (xinerama) {
slouken@6548
   434
            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
slouken@6548
   435
                continue;
slouken@6548
   436
            }
slouken@6548
   437
        } else {
slouken@6548
   438
            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   439
                continue;
slouken@6548
   440
            }
slouken@6548
   441
        }
slouken@6548
   442
#else
slouken@6548
   443
        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   444
            continue;
slouken@6548
   445
        }
slouken@6548
   446
#endif
slouken@6548
   447
slouken@6548
   448
        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
slouken@6548
   449
        if (!displaydata) {
slouken@6548
   450
            continue;
slouken@6548
   451
        }
slouken@6548
   452
slouken@6548
   453
        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
slouken@6548
   454
        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
slouken@6548
   455
            /* We don't support palettized modes now */
slouken@6548
   456
            SDL_free(displaydata);
slouken@6548
   457
            continue;
slouken@6548
   458
        }
slouken@6548
   459
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   460
        if (xinerama) {
slouken@6548
   461
            mode.w = xinerama[screen].width;
slouken@6548
   462
            mode.h = xinerama[screen].height;
slouken@6548
   463
        } else {
slouken@6548
   464
            mode.w = DisplayWidth(data->display, screen);
slouken@6548
   465
            mode.h = DisplayHeight(data->display, screen);
slouken@6548
   466
        }
slouken@6548
   467
#else
slouken@6548
   468
        mode.w = DisplayWidth(data->display, screen);
slouken@6548
   469
        mode.h = DisplayHeight(data->display, screen);
slouken@6548
   470
#endif
slouken@6548
   471
        mode.refresh_rate = 0;
slouken@6548
   472
slouken@6548
   473
        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   474
        if (!modedata) {
slouken@6548
   475
            SDL_free(displaydata);
slouken@6548
   476
            continue;
slouken@6548
   477
        }
slouken@6548
   478
        mode.driverdata = modedata;
slouken@6548
   479
slouken@6548
   480
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   481
        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
slouken@6548
   482
         * there's only one screen available. So we force the screen number to zero and
slouken@6548
   483
         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
slouken@6548
   484
         */
slouken@6548
   485
        if (use_xinerama) {
slouken@6548
   486
            displaydata->screen = 0;
slouken@6548
   487
            displaydata->use_xinerama = use_xinerama;
slouken@6548
   488
            displaydata->xinerama_info = xinerama[screen];
slouken@6548
   489
            displaydata->xinerama_screen = screen;
slouken@6548
   490
        }
slouken@6548
   491
        else displaydata->screen = screen;
slouken@6548
   492
#else
slouken@6548
   493
        displaydata->screen = screen;
slouken@6548
   494
#endif
slouken@6548
   495
        displaydata->visual = vinfo.visual;
slouken@6548
   496
        displaydata->depth = vinfo.depth;
slouken@6548
   497
slouken@6548
   498
        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
slouken@6548
   499
        pixmapFormats = XListPixmapFormats(data->display, &n);
slouken@6548
   500
        if (pixmapFormats) {
slouken@6548
   501
            for (i = 0; i < n; ++i) {
slouken@6548
   502
                if (pixmapFormats[i].depth == displaydata->depth) {
slouken@6548
   503
                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
slouken@6548
   504
                    break;
slouken@6548
   505
                }
slouken@6548
   506
            }
slouken@6548
   507
            XFree(pixmapFormats);
slouken@6548
   508
        }
slouken@6548
   509
slouken@6548
   510
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   511
        if (use_xinerama) {
slouken@6548
   512
            displaydata->x = xinerama[screen].x_org;
slouken@6548
   513
            displaydata->y = xinerama[screen].y_org;
slouken@6548
   514
        }
slouken@6548
   515
        else
slouken@6548
   516
#endif
slouken@6548
   517
        {
slouken@6548
   518
            displaydata->x = 0;
slouken@6548
   519
            displaydata->y = 0;
slouken@6548
   520
        }
slouken@6548
   521
slouken@6548
   522
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   523
        if (use_xrandr) {
slouken@6548
   524
            res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
slouken@6548
   525
        }
slouken@6548
   526
        if (res) {
slouken@6548
   527
            XRROutputInfo *output_info;
slouken@6548
   528
            XRRCrtcInfo *crtc;
slouken@6548
   529
            int output;
slouken@6548
   530
slouken@6548
   531
            for (output = 0; output < res->noutput; output++) {
slouken@6548
   532
                output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
slouken@6550
   533
                if (!output_info || !output_info->crtc ||
slouken@6550
   534
                    output_info->connection == RR_Disconnected) {
slouken@6548
   535
                    XRRFreeOutputInfo(output_info);
slouken@6548
   536
                    continue;
slouken@6548
   537
                }
slouken@6548
   538
slouken@6548
   539
                /* Is this the output that corresponds to the current screen?
slouken@6548
   540
                   We're checking the crtc position, but that may not be a valid test
slouken@6548
   541
                   in all cases.  Anybody want to give this some love?
slouken@6548
   542
                 */
slouken@6548
   543
                crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
slouken@6548
   544
                if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
slouken@6548
   545
                    XRRFreeOutputInfo(output_info);
slouken@6548
   546
                    XRRFreeCrtcInfo(crtc);
slouken@6548
   547
                    continue;
slouken@6548
   548
                }
slouken@6548
   549
slouken@6548
   550
                displaydata->use_xrandr = use_xrandr;
slouken@6548
   551
                displaydata->xrandr_output = res->outputs[output];
slouken@6548
   552
                SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
slouken@6548
   553
slouken@6548
   554
                XRRFreeOutputInfo(output_info);
slouken@6548
   555
                XRRFreeCrtcInfo(crtc);
slouken@6548
   556
                break;
slouken@6548
   557
            }
slouken@6548
   558
#ifdef X11MODES_DEBUG
slouken@6548
   559
            if (output == res->noutput) {
slouken@6548
   560
                printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
slouken@6548
   561
            }
slouken@6548
   562
#endif
slouken@6548
   563
            XRRFreeScreenResources(res);
slouken@6548
   564
        }
slouken@6548
   565
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@6548
   566
slouken@6548
   567
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   568
        if (!displaydata->use_xrandr &&
slouken@6548
   569
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6564
   570
            /* XVidMode only works on the screen at the origin */
slouken@6564
   571
            (!displaydata->use_xinerama ||
slouken@6564
   572
             (displaydata->x == 0 && displaydata->y == 0)) &&
slouken@6548
   573
#endif
slouken@6548
   574
            use_vidmode) {
slouken@6548
   575
            displaydata->use_vidmode = use_vidmode;
slouken@6565
   576
            if (displaydata->use_xinerama) {
slouken@6565
   577
                displaydata->vidmode_screen = 0;
slouken@6565
   578
            } else {
slouken@6565
   579
                displaydata->vidmode_screen = screen;
slouken@6565
   580
            }
slouken@6565
   581
            XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
slouken@6548
   582
        }
slouken@6548
   583
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   584
slouken@6548
   585
        SDL_zero(display);
slouken@6548
   586
        display.desktop_mode = mode;
slouken@6548
   587
        display.current_mode = mode;
slouken@6548
   588
        display.driverdata = displaydata;
slouken@6548
   589
        SDL_AddVideoDisplay(&display);
slouken@6548
   590
    }
slouken@6548
   591
slouken@6548
   592
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   593
    if (xinerama) XFree(xinerama);
slouken@6548
   594
#endif
slouken@6548
   595
slouken@6548
   596
    if (_this->num_displays == 0) {
slouken@6548
   597
        SDL_SetError("No available displays");
slouken@6548
   598
        return -1;
slouken@6548
   599
    }
slouken@6548
   600
    return 0;
slouken@2873
   601
}
slouken@2873
   602
slouken@1950
   603
void
slouken@3500
   604
X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
slouken@1950
   605
{
slouken@2870
   606
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@3500
   607
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@5408
   608
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   609
    int nmodes;
slouken@5408
   610
    XF86VidModeModeInfo ** modes;
slouken@2873
   611
#endif
slouken@2873
   612
    int screen_w;
slouken@2873
   613
    int screen_h;
slouken@1950
   614
    SDL_DisplayMode mode;
slouken@6548
   615
    SDL_DisplayModeData *modedata;
slouken@2870
   616
slouken@2873
   617
    /* Unfortunately X11 requires the window to be created with the correct
slouken@2873
   618
     * visual and depth ahead of time, but the SDL API allows you to create
slouken@2873
   619
     * a window before setting the fullscreen display mode.  This means that
slouken@2873
   620
     * we have to use the same format for all windows and all display modes.
slouken@2873
   621
     * (or support recreating the window with a new visual behind the scenes)
slouken@2873
   622
     */
slouken@3500
   623
    mode.format = sdl_display->current_mode.format;
slouken@2873
   624
    mode.driverdata = NULL;
slouken@2873
   625
slouken@2873
   626
    screen_w = DisplayWidth(display, data->screen);
slouken@2873
   627
    screen_h = DisplayHeight(display, data->screen);
slouken@2873
   628
slouken@2873
   629
#if SDL_VIDEO_DRIVER_X11_XINERAMA
gabomdq@6331
   630
    if (data->use_xinerama) {
gabomdq@6331
   631
        /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
gabomdq@6331
   632
        if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
gabomdq@6331
   633
           (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
gabomdq@6331
   634
            mode.w = screen_w;
gabomdq@6331
   635
            mode.h = screen_h;
slouken@2873
   636
            mode.refresh_rate = 0;
slouken@6548
   637
            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   638
            if (modedata) {
slouken@6548
   639
                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
slouken@6548
   640
            }
slouken@6548
   641
            mode.driverdata = modedata;
slouken@3500
   642
            SDL_AddDisplayMode(sdl_display, &mode);
slouken@2873
   643
        }
slouken@2873
   644
    }
slouken@2873
   645
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   646
slouken@2873
   647
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   648
    if (data->use_xrandr) {
slouken@6548
   649
        XRRScreenResources *res;
slouken@2873
   650
slouken@6548
   651
        res = XRRGetScreenResources (display, RootWindow(display, data->screen));
slouken@6548
   652
        if (res) {
slouken@6548
   653
            SDL_DisplayModeData *modedata;
slouken@6548
   654
            XRROutputInfo *output_info;
slouken@6548
   655
            int i;
slouken@2873
   656
slouken@6548
   657
            output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
slouken@6548
   658
            if (output_info && output_info->connection != RR_Disconnected) {
slouken@6548
   659
                for (i = 0; i < output_info->nmode; ++i) {
slouken@6548
   660
                    modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   661
                    if (!modedata) {
slouken@6548
   662
                        continue;
slouken@6548
   663
                    }
slouken@6548
   664
                    mode.driverdata = modedata;
slouken@2873
   665
slouken@6548
   666
                    if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
slouken@6548
   667
                        SDL_AddDisplayMode(sdl_display, &mode);
slouken@6548
   668
                    } else {
slouken@6548
   669
                        SDL_free(modedata);
slouken@6548
   670
                    }
slouken@2873
   671
                }
slouken@2873
   672
            }
slouken@6548
   673
            XRRFreeOutputInfo(output_info);
slouken@6548
   674
            XRRFreeScreenResources(res);
slouken@2873
   675
        }
slouken@6548
   676
        return;
slouken@2873
   677
    }
slouken@2873
   678
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   679
slouken@5408
   680
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   681
    if (data->use_vidmode &&
slouken@6565
   682
        XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
slouken@2873
   683
        int i;
slouken@2873
   684
slouken@2873
   685
#ifdef X11MODES_DEBUG
slouken@2873
   686
        printf("VidMode modes: (unsorted)\n");
slouken@2873
   687
        for (i = 0; i < nmodes; ++i) {
slouken@6566
   688
            printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
slouken@2874
   689
                   modes[i]->hdisplay, modes[i]->vdisplay,
slouken@6566
   690
                   CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
slouken@2873
   691
        }
slouken@2873
   692
#endif
slouken@2873
   693
        for (i = 0; i < nmodes; ++i) {
slouken@6548
   694
            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   695
            if (!modedata) {
slouken@6548
   696
                continue;
slouken@6548
   697
            }
slouken@6548
   698
            mode.driverdata = modedata;
slouken@6548
   699
slouken@6548
   700
            if (SetXVidModeModeInfo(modes[i], &mode)) {
slouken@6548
   701
                SDL_AddDisplayMode(sdl_display, &mode);
slouken@6548
   702
            } else {
slouken@6548
   703
                SDL_free(modedata);
slouken@6548
   704
            }
slouken@2873
   705
        }
slouken@2873
   706
        XFree(modes);
slouken@6548
   707
        return;
slouken@2873
   708
    }
slouken@5408
   709
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@2873
   710
slouken@2873
   711
    if (!data->use_xrandr && !data->use_vidmode) {
slouken@6548
   712
        /* Add the desktop mode */
slouken@6548
   713
        mode = sdl_display->desktop_mode;
slouken@6548
   714
        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   715
        if (modedata) {
slouken@6548
   716
            *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
slouken@6548
   717
        }
slouken@6548
   718
        mode.driverdata = modedata;
slouken@3500
   719
        SDL_AddDisplayMode(sdl_display, &mode);
slouken@2874
   720
    }
slouken@1950
   721
}
slouken@1950
   722
slouken@1950
   723
int
slouken@3500
   724
X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
slouken@1950
   725
{
slouken@2873
   726
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@3500
   727
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@6548
   728
    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
slouken@2873
   729
slouken@6548
   730
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   731
    if (data->use_xrandr) {
slouken@6548
   732
        XRRScreenResources *res;
slouken@6548
   733
        XRROutputInfo *output_info;
slouken@6548
   734
        XRRCrtcInfo *crtc;
slouken@6548
   735
        Status status;
slouken@6548
   736
slouken@6548
   737
        res = XRRGetScreenResources (display, RootWindow(display, data->screen));
slouken@6548
   738
        if (!res) {
slouken@6548
   739
            SDL_SetError("Couldn't get XRandR screen resources");
slouken@6548
   740
            return -1;
slouken@6548
   741
        }
slouken@6548
   742
slouken@6548
   743
        output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
slouken@6548
   744
        if (!output_info || output_info->connection == RR_Disconnected) {
slouken@6548
   745
            SDL_SetError("Couldn't get XRandR output info");
slouken@6548
   746
            XRRFreeScreenResources(res);
slouken@6548
   747
            return -1;
slouken@6548
   748
        }
slouken@6548
   749
slouken@6548
   750
        crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
slouken@6548
   751
        if (!crtc) {
slouken@6548
   752
            SDL_SetError("Couldn't get XRandR crtc info");
slouken@6548
   753
            XRRFreeOutputInfo(output_info);
slouken@6548
   754
            XRRFreeScreenResources(res);
slouken@6548
   755
            return -1;
slouken@6548
   756
        }
slouken@6548
   757
slouken@6548
   758
        status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
slouken@6548
   759
          crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
slouken@6548
   760
          &data->xrandr_output, 1);
slouken@6548
   761
slouken@6548
   762
        XRRFreeCrtcInfo(crtc);
slouken@6548
   763
        XRRFreeOutputInfo(output_info);
slouken@6548
   764
        XRRFreeScreenResources(res);
slouken@6548
   765
slouken@6548
   766
        if (status != Success) {
slouken@6548
   767
            SDL_SetError("XRRSetCrtcConfig failed");
slouken@6548
   768
            return -1;
slouken@6548
   769
        }
slouken@6548
   770
    }
slouken@6548
   771
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@6548
   772
slouken@6548
   773
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   774
    if (data->use_vidmode) {
slouken@6565
   775
        XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
slouken@6548
   776
    }
slouken@6548
   777
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   778
slouken@2873
   779
    return 0;
slouken@1950
   780
}
slouken@1950
   781
slouken@1950
   782
void
slouken@1950
   783
X11_QuitModes(_THIS)
slouken@1950
   784
{
slouken@1950
   785
}
slouken@1950
   786
gabomdq@6331
   787
int
gabomdq@6331
   788
X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
gabomdq@6331
   789
{
slouken@6502
   790
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
gabomdq@6331
   791
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@6502
   792
slouken@6548
   793
    rect->x = data->x;
slouken@6548
   794
    rect->y = data->y;
slouken@6548
   795
    rect->w = sdl_display->current_mode.w;
slouken@6548
   796
    rect->h = sdl_display->current_mode.h;
gabomdq@6331
   797
gabomdq@6331
   798
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   799
    /* Get the real current bounds of the display */
slouken@6502
   800
    if (data->use_xinerama) {
slouken@6548
   801
        int screencount;
slouken@6548
   802
        XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
slouken@6548
   803
        if (xinerama) {
slouken@6548
   804
            rect->x = xinerama[data->xinerama_screen].x_org;
slouken@6548
   805
            rect->y = xinerama[data->xinerama_screen].y_org;
slouken@6548
   806
        }
gabomdq@6331
   807
    }
slouken@6548
   808
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@6475
   809
    return 0;
gabomdq@6331
   810
}
gabomdq@6331
   811
slouken@5481
   812
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
   813
slouken@1950
   814
/* vi: set ts=4 sw=4 expandtab: */