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