src/video/x11/SDL_x11modes.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Fri, 20 May 2016 22:14:40 +0200
changeset 10172 b4316ed0c72c
parent 10031 2b3baddd9afa
child 10437 d62c4978fffa
permissions -rw-r--r--
X11: Fixed missing error message if SDL_GetDisplayDPI() failed.
slouken@1950
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 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
*/
icculus@8093
    21
#include "../../SDL_internal.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"
icculus@9319
    27
#include "SDL_timer.h"
slouken@6796
    28
#include "edid.h"
slouken@1950
    29
gabomdq@7678
    30
/* #define X11MODES_DEBUG */
slouken@6558
    31
slouken@6559
    32
/* I'm becoming more and more convinced that the application should never
slouken@6559
    33
 * use XRandR, and it's the window manager's responsibility to track and
slouken@6559
    34
 * manage display modes for fullscreen windows.  Right now XRandR is completely
slouken@6559
    35
 * broken with respect to window manager behavior on every window manager that
slouken@6559
    36
 * I can find.  For example, on Unity 3D if you show a fullscreen window while
slouken@6559
    37
 * the resolution is changing (within ~250 ms) your window will retain the
slouken@6559
    38
 * fullscreen state hint but be decorated and windowed.
slouken@6796
    39
 *
slouken@6796
    40
 * However, many people swear by it, so let them swear at it. :)
slouken@6558
    41
*/
gabomdq@7678
    42
/* #define XRANDR_DISABLED_BY_DEFAULT */
slouken@6558
    43
slouken@1950
    44
slouken@1950
    45
static int
slouken@1950
    46
get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
slouken@1950
    47
{
slouken@1950
    48
    const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
slouken@1950
    49
    int depth;
slouken@1950
    50
slouken@1950
    51
    /* Look for an exact visual, if requested */
slouken@1950
    52
    if (visual_id) {
slouken@3697
    53
        XVisualInfo *vi, template;
slouken@3697
    54
        int nvis;
slouken@1950
    55
slouken@1950
    56
        SDL_zero(template);
slouken@1950
    57
        template.visualid = SDL_strtol(visual_id, NULL, 0);
icculus@7827
    58
        vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis);
slouken@1950
    59
        if (vi) {
slouken@1950
    60
            *vinfo = *vi;
icculus@7827
    61
            X11_XFree(vi);
slouken@1950
    62
            return 0;
slouken@1950
    63
        }
slouken@1950
    64
    }
slouken@3697
    65
slouken@1950
    66
    depth = DefaultDepth(display, screen);
slouken@5466
    67
    if ((X11_UseDirectColorVisuals() &&
icculus@7827
    68
         X11_XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
icculus@7827
    69
        X11_XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
icculus@7827
    70
        X11_XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
icculus@7827
    71
        X11_XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
slouken@1950
    72
        return 0;
slouken@1950
    73
    }
slouken@1950
    74
    return -1;
slouken@1950
    75
}
slouken@1950
    76
slouken@5182
    77
int
slouken@5182
    78
X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
slouken@5182
    79
{
slouken@5182
    80
    XVisualInfo *vi;
slouken@5182
    81
    int nvis;
slouken@5182
    82
icculus@7827
    83
    vinfo->visualid = X11_XVisualIDFromVisual(visual);
icculus@7827
    84
    vi = X11_XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
slouken@5182
    85
    if (vi) {
slouken@5182
    86
        *vinfo = *vi;
icculus@7827
    87
        X11_XFree(vi);
slouken@5182
    88
        return 0;
slouken@5182
    89
    }
slouken@5182
    90
    return -1;
slouken@5182
    91
}
slouken@5182
    92
slouken@5182
    93
Uint32
slouken@2874
    94
X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
slouken@2870
    95
{
slouken@2870
    96
    if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
slouken@2870
    97
        int bpp;
slouken@2870
    98
        Uint32 Rmask, Gmask, Bmask, Amask;
slouken@2870
    99
slouken@2870
   100
        Rmask = vinfo->visual->red_mask;
slouken@2870
   101
        Gmask = vinfo->visual->green_mask;
slouken@2870
   102
        Bmask = vinfo->visual->blue_mask;
slouken@2870
   103
        if (vinfo->depth == 32) {
slouken@2870
   104
            Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
slouken@2870
   105
        } else {
slouken@2870
   106
            Amask = 0;
slouken@2870
   107
        }
slouken@2870
   108
slouken@2870
   109
        bpp = vinfo->depth;
slouken@2870
   110
        if (bpp == 24) {
slouken@2870
   111
            int i, n;
icculus@7827
   112
            XPixmapFormatValues *p = X11_XListPixmapFormats(display, &n);
slouken@2870
   113
            if (p) {
slouken@2870
   114
                for (i = 0; i < n; ++i) {
slouken@2870
   115
                    if (p[i].depth == 24) {
slouken@2870
   116
                        bpp = p[i].bits_per_pixel;
slouken@2870
   117
                        break;
slouken@2870
   118
                    }
slouken@2870
   119
                }
icculus@7827
   120
                X11_XFree(p);
slouken@2870
   121
            }
slouken@2870
   122
        }
slouken@2870
   123
slouken@2870
   124
        return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
slouken@2870
   125
    }
slouken@2870
   126
slouken@2870
   127
    if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
slouken@2870
   128
        switch (vinfo->depth) {
slouken@2870
   129
        case 8:
slouken@2870
   130
            return SDL_PIXELTYPE_INDEX8;
slouken@2870
   131
        case 4:
slouken@2870
   132
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   133
                return SDL_PIXELFORMAT_INDEX4LSB;
slouken@2870
   134
            } else {
slouken@2870
   135
                return SDL_PIXELFORMAT_INDEX4MSB;
slouken@2870
   136
            }
slouken@2870
   137
            break;
slouken@2870
   138
        case 1:
slouken@2870
   139
            if (BitmapBitOrder(display) == LSBFirst) {
slouken@2870
   140
                return SDL_PIXELFORMAT_INDEX1LSB;
slouken@2870
   141
            } else {
slouken@2870
   142
                return SDL_PIXELFORMAT_INDEX1MSB;
slouken@2870
   143
            }
slouken@2870
   144
            break;
slouken@2870
   145
        }
slouken@2870
   146
    }
slouken@2870
   147
slouken@2870
   148
    return SDL_PIXELFORMAT_UNKNOWN;
slouken@2870
   149
}
slouken@1950
   150
slouken@2873
   151
/* Global for the error handler */
slouken@2873
   152
int vm_event, vm_error = -1;
slouken@2873
   153
slouken@2873
   154
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@2873
   155
static SDL_bool
slouken@2874
   156
CheckXinerama(Display * display, int *major, int *minor)
slouken@2873
   157
{
icculus@6027
   158
    int event_base = 0;
icculus@6027
   159
    int error_base = 0;
slouken@2873
   160
    const char *env;
slouken@2873
   161
slouken@2873
   162
    /* Default the extension not available */
slouken@2873
   163
    *major = *minor = 0;
slouken@2873
   164
slouken@2873
   165
    /* Allow environment override */
slouken@6472
   166
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA);
slouken@2873
   167
    if (env && !SDL_atoi(env)) {
slouken@6468
   168
#ifdef X11MODES_DEBUG
slouken@6472
   169
        printf("Xinerama disabled due to hint\n");
slouken@6468
   170
#endif
slouken@2873
   171
        return SDL_FALSE;
slouken@2873
   172
    }
slouken@2873
   173
slouken@5408
   174
    if (!SDL_X11_HAVE_XINERAMA) {
slouken@6468
   175
#ifdef X11MODES_DEBUG
slouken@6468
   176
        printf("Xinerama support not available\n");
slouken@6468
   177
#endif
slouken@5408
   178
        return SDL_FALSE;
slouken@5408
   179
    }
slouken@5408
   180
slouken@2873
   181
    /* Query the extension version */
icculus@7827
   182
    if (!X11_XineramaQueryExtension(display, &event_base, &error_base) ||
icculus@7827
   183
        !X11_XineramaQueryVersion(display, major, minor) ||
icculus@7827
   184
        !X11_XineramaIsActive(display)) {
slouken@6468
   185
#ifdef X11MODES_DEBUG
slouken@6468
   186
        printf("Xinerama not active on the display\n");
slouken@6468
   187
#endif
slouken@2873
   188
        return SDL_FALSE;
slouken@2873
   189
    }
slouken@6468
   190
#ifdef X11MODES_DEBUG
slouken@6548
   191
    printf("Xinerama available at version %d.%d!\n", *major, *minor);
slouken@6468
   192
#endif
slouken@2873
   193
    return SDL_TRUE;
slouken@2873
   194
}
icculus@9789
   195
icculus@9789
   196
/* !!! FIXME: remove this later. */
icculus@9789
   197
/* we have a weird bug where XineramaQueryScreens() throws an X error, so this
icculus@9789
   198
   is here to help track it down (and not crash, too!). */
icculus@9789
   199
static SDL_bool xinerama_triggered_error = SDL_FALSE;
icculus@9789
   200
static int
icculus@9789
   201
X11_XineramaFailed(Display * d, XErrorEvent * e)
icculus@9789
   202
{
icculus@9789
   203
    xinerama_triggered_error = SDL_TRUE;
icculus@9789
   204
    fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n",
icculus@9789
   205
            e->type, e->serial, (unsigned int) e->error_code,
icculus@9789
   206
            (unsigned int) e->request_code, (unsigned int) e->minor_code);
icculus@9789
   207
    fflush(stderr);
icculus@9789
   208
    return 0;
icculus@9789
   209
}
slouken@2873
   210
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   211
slouken@2873
   212
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   213
static SDL_bool
slouken@2874
   214
CheckXRandR(Display * display, int *major, int *minor)
slouken@2873
   215
{
slouken@2873
   216
    const char *env;
slouken@2873
   217
slouken@2873
   218
    /* Default the extension not available */
slouken@2873
   219
    *major = *minor = 0;
slouken@2873
   220
slouken@2873
   221
    /* Allow environment override */
slouken@6472
   222
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR);
slouken@6558
   223
#ifdef XRANDR_DISABLED_BY_DEFAULT
slouken@6558
   224
    if (!env || !SDL_atoi(env)) {
slouken@6558
   225
#ifdef X11MODES_DEBUG
slouken@6558
   226
        printf("XRandR disabled by default due to window manager issues\n");
slouken@6558
   227
#endif
slouken@6558
   228
        return SDL_FALSE;
slouken@6558
   229
    }
slouken@6558
   230
#else
slouken@2873
   231
    if (env && !SDL_atoi(env)) {
slouken@6468
   232
#ifdef X11MODES_DEBUG
slouken@6472
   233
        printf("XRandR disabled due to hint\n");
slouken@6468
   234
#endif
slouken@2873
   235
        return SDL_FALSE;
slouken@2873
   236
    }
slouken@6558
   237
#endif /* XRANDR_ENABLED_BY_DEFAULT */
slouken@2873
   238
slouken@2873
   239
    if (!SDL_X11_HAVE_XRANDR) {
slouken@6468
   240
#ifdef X11MODES_DEBUG
slouken@6468
   241
        printf("XRandR support not available\n");
slouken@6468
   242
#endif
slouken@2873
   243
        return SDL_FALSE;
slouken@2873
   244
    }
slouken@2873
   245
slouken@2873
   246
    /* Query the extension version */
icculus@9834
   247
    *major = 1; *minor = 3;  /* we want 1.3 */
icculus@7827
   248
    if (!X11_XRRQueryVersion(display, major, minor)) {
slouken@6468
   249
#ifdef X11MODES_DEBUG
slouken@6468
   250
        printf("XRandR not active on the display\n");
slouken@6468
   251
#endif
icculus@9834
   252
        *major = *minor = 0;
slouken@2873
   253
        return SDL_FALSE;
slouken@2873
   254
    }
slouken@6468
   255
#ifdef X11MODES_DEBUG
slouken@6548
   256
    printf("XRandR available at version %d.%d!\n", *major, *minor);
slouken@6468
   257
#endif
slouken@2873
   258
    return SDL_TRUE;
slouken@2873
   259
}
slouken@6537
   260
slouken@6537
   261
#define XRANDR_ROTATION_LEFT    (1 << 1)
slouken@6537
   262
#define XRANDR_ROTATION_RIGHT   (1 << 3)
slouken@6537
   263
slouken@6548
   264
static int
slouken@6548
   265
CalculateXRandRRefreshRate(const XRRModeInfo *info)
slouken@6537
   266
{
slouken@6548
   267
    return (info->hTotal
slouken@6551
   268
            && info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0;
slouken@6548
   269
}
slouken@6548
   270
slouken@6548
   271
static SDL_bool
icculus@9834
   272
SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc,
slouken@6548
   273
                  RRMode modeID, SDL_DisplayMode *mode)
slouken@6548
   274
{
slouken@6548
   275
    int i;
slouken@6548
   276
    for (i = 0; i < res->nmode; ++i) {
icculus@9834
   277
        const XRRModeInfo *info = &res->modes[i];
icculus@9834
   278
        if (info->id == modeID) {
icculus@9834
   279
            XRRCrtcInfo *crtcinfo;
slouken@6548
   280
            Rotation rotation = 0;
slouken@6548
   281
icculus@9834
   282
            crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc);
icculus@9834
   283
            if (crtcinfo) {
icculus@9834
   284
                rotation = crtcinfo->rotation;
icculus@9834
   285
                X11_XRRFreeCrtcInfo(crtcinfo);
slouken@6548
   286
            }
slouken@6548
   287
slouken@6548
   288
            if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
slouken@6548
   289
                mode->w = info->height;
slouken@6548
   290
                mode->h = info->width;
slouken@6548
   291
            } else {
slouken@6548
   292
                mode->w = info->width;
slouken@6548
   293
                mode->h = info->height;
slouken@6548
   294
            }
slouken@6548
   295
            mode->refresh_rate = CalculateXRandRRefreshRate(info);
slouken@6548
   296
            ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
slouken@6548
   297
#ifdef X11MODES_DEBUG
icculus@6560
   298
            printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
slouken@6548
   299
#endif
slouken@6548
   300
            return SDL_TRUE;
slouken@6548
   301
        }
slouken@6537
   302
    }
slouken@6548
   303
    return SDL_FALSE;
slouken@6537
   304
}
icculus@9834
   305
icculus@9834
   306
static void
icculus@9834
   307
SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm)
icculus@9834
   308
{
icculus@9834
   309
    /* See if we can get the EDID data for the real monitor name */
icculus@9834
   310
    int inches;
icculus@9834
   311
    int nprop;
icculus@9834
   312
    Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop);
icculus@9834
   313
    int i;
icculus@9834
   314
icculus@9834
   315
    for (i = 0; i < nprop; ++i) {
icculus@9834
   316
        unsigned char *prop;
icculus@9834
   317
        int actual_format;
icculus@9834
   318
        unsigned long nitems, bytes_after;
icculus@9834
   319
        Atom actual_type;
icculus@9834
   320
icculus@9834
   321
        if (props[i] == EDID) {
icculus@9834
   322
            if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False,
icculus@9834
   323
                                         False, AnyPropertyType, &actual_type,
icculus@9834
   324
                                         &actual_format, &nitems, &bytes_after,
icculus@9834
   325
                                         &prop) == Success) {
icculus@9834
   326
                MonitorInfo *info = decode_edid(prop);
icculus@9834
   327
                if (info) {
icculus@9834
   328
#ifdef X11MODES_DEBUG
icculus@9834
   329
                    printf("Found EDID data for %s\n", name);
icculus@9834
   330
                    dump_monitor_info(info);
icculus@9834
   331
#endif
icculus@9834
   332
                    SDL_strlcpy(name, info->dsc_product_name, namelen);
icculus@9834
   333
                    free(info);
icculus@9834
   334
                }
icculus@9834
   335
                X11_XFree(prop);
icculus@9834
   336
            }
icculus@9834
   337
            break;
icculus@9834
   338
        }
icculus@9834
   339
    }
icculus@9834
   340
icculus@9834
   341
    if (props) {
icculus@9834
   342
        X11_XFree(props);
icculus@9834
   343
    }
icculus@9834
   344
icculus@10030
   345
    inches = (int)((SDL_sqrtf(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f);
icculus@9834
   346
    if (*name && inches) {
icculus@9834
   347
        const size_t len = SDL_strlen(name);
icculus@9834
   348
        SDL_snprintf(&name[len], namelen-len, " %d\"", inches);
icculus@9834
   349
    }
icculus@9834
   350
icculus@9834
   351
#ifdef X11MODES_DEBUG
icculus@9834
   352
    printf("Display name: %s\n", name);
icculus@9834
   353
#endif
icculus@9834
   354
}
icculus@9834
   355
icculus@9834
   356
icculus@9834
   357
int
icculus@9834
   358
X11_InitModes_XRandR(_THIS)
icculus@9834
   359
{
icculus@9834
   360
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
icculus@9834
   361
    Display *dpy = data->display;
icculus@9920
   362
    const int screencount = ScreenCount(dpy);
icculus@9920
   363
    const int default_screen = DefaultScreen(dpy);
icculus@9920
   364
    RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen));
icculus@9834
   365
    Atom EDID = X11_XInternAtom(dpy, "EDID", False);
icculus@9834
   366
    XRRScreenResources *res = NULL;
icculus@9834
   367
    Uint32 pixelformat;
icculus@9834
   368
    XVisualInfo vinfo;
icculus@9834
   369
    XPixmapFormatValues *pixmapformats;
icculus@9834
   370
    int looking_for_primary;
icculus@9834
   371
    int scanline_pad;
icculus@9834
   372
    int output;
icculus@9920
   373
    int screen, i, n;
icculus@9834
   374
icculus@9834
   375
    for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) {
icculus@9920
   376
        for (screen = 0; screen < screencount; screen++) {
icculus@9834
   377
icculus@9920
   378
            /* we want the primary output first, and then skipped later. */
icculus@9984
   379
            if (looking_for_primary && (screen != default_screen)) {
icculus@9834
   380
                continue;
icculus@9834
   381
            }
icculus@9834
   382
icculus@9920
   383
            if (get_visualinfo(dpy, screen, &vinfo) < 0) {
icculus@9920
   384
                continue;  /* uh, skip this screen? */
icculus@9920
   385
            }
icculus@9920
   386
icculus@9920
   387
            pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
icculus@9920
   388
            if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
icculus@9920
   389
                continue;  /* Palettized video modes are no longer supported */
icculus@9920
   390
            }
icculus@9920
   391
icculus@9920
   392
            scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
icculus@9920
   393
            pixmapformats = X11_XListPixmapFormats(dpy, &n);
icculus@9920
   394
            if (pixmapformats) {
icculus@9920
   395
                for (i = 0; i < n; ++i) {
icculus@9920
   396
                    if (pixmapformats[i].depth == vinfo.depth) {
icculus@9920
   397
                        scanline_pad = pixmapformats[i].scanline_pad;
icculus@9920
   398
                        break;
icculus@9920
   399
                    }
icculus@9920
   400
                }
icculus@9920
   401
                X11_XFree(pixmapformats);
icculus@9920
   402
            }
icculus@9920
   403
icculus@9920
   404
            res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
icculus@9920
   405
            if (!res) {
icculus@9834
   406
                continue;
icculus@9834
   407
            }
icculus@9834
   408
icculus@9920
   409
            for (output = 0; output < res->noutput; output++) {
icculus@9920
   410
                XRROutputInfo *output_info;
icculus@9920
   411
                int display_x, display_y;
icculus@9920
   412
                unsigned long display_mm_width, display_mm_height;
icculus@9920
   413
                SDL_DisplayData *displaydata;
icculus@9920
   414
                char display_name[128];
icculus@9920
   415
                SDL_DisplayMode mode;
icculus@9920
   416
                SDL_DisplayModeData *modedata;
icculus@9920
   417
                SDL_VideoDisplay display;
icculus@9920
   418
                RRMode modeID;
icculus@9920
   419
                RRCrtc output_crtc;
icculus@9920
   420
                XRRCrtcInfo *crtc;
icculus@9834
   421
icculus@9920
   422
                /* The primary output _should_ always be sorted first, but just in case... */
icculus@9984
   423
                if ((looking_for_primary && (res->outputs[output] != primary)) ||
icculus@9920
   424
                    (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
icculus@9920
   425
                    continue;
icculus@9920
   426
                }
icculus@9920
   427
icculus@9920
   428
                output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
icculus@9920
   429
                if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
icculus@9920
   430
                    X11_XRRFreeOutputInfo(output_info);
icculus@9920
   431
                    continue;
icculus@9920
   432
                }
icculus@9920
   433
icculus@9920
   434
                SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
icculus@9920
   435
                display_mm_width = output_info->mm_width;
icculus@9920
   436
                display_mm_height = output_info->mm_height;
icculus@9920
   437
                output_crtc = output_info->crtc;
icculus@9920
   438
                X11_XRRFreeOutputInfo(output_info);
icculus@9920
   439
icculus@9920
   440
                crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
icculus@9920
   441
                if (!crtc) {
icculus@9920
   442
                    continue;
icculus@9920
   443
                }
icculus@9920
   444
icculus@9920
   445
                SDL_zero(mode);
icculus@9920
   446
                modeID = crtc->mode;
icculus@9920
   447
                mode.w = crtc->width;
icculus@9920
   448
                mode.h = crtc->height;
icculus@9920
   449
                mode.format = pixelformat;
icculus@9920
   450
icculus@9920
   451
                display_x = crtc->x;
icculus@9920
   452
                display_y = crtc->y;
icculus@9920
   453
icculus@9920
   454
                X11_XRRFreeCrtcInfo(crtc);
icculus@9920
   455
icculus@9920
   456
                displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
icculus@9920
   457
                if (!displaydata) {
icculus@9920
   458
                    return SDL_OutOfMemory();
icculus@9920
   459
                }
icculus@9920
   460
icculus@9920
   461
                modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
icculus@9920
   462
                if (!modedata) {
icculus@9920
   463
                    SDL_free(displaydata);
icculus@9920
   464
                    return SDL_OutOfMemory();
icculus@9920
   465
                }
icculus@9920
   466
                modedata->xrandr_mode = modeID;
icculus@9920
   467
                mode.driverdata = modedata;
icculus@9920
   468
icculus@9920
   469
                displaydata->screen = screen;
icculus@9920
   470
                displaydata->visual = vinfo.visual;
icculus@9920
   471
                displaydata->depth = vinfo.depth;
icculus@9920
   472
                displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width;
icculus@9920
   473
                displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height;
icculus@9920
   474
                displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
icculus@9920
   475
                displaydata->scanline_pad = scanline_pad;
icculus@9920
   476
                displaydata->x = display_x;
icculus@9920
   477
                displaydata->y = display_y;
icculus@9920
   478
                displaydata->use_xrandr = 1;
icculus@9920
   479
                displaydata->xrandr_output = res->outputs[output];
icculus@9920
   480
icculus@9920
   481
                SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
icculus@9920
   482
                SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
icculus@9920
   483
icculus@9920
   484
                SDL_zero(display);
icculus@9920
   485
                if (*display_name) {
icculus@9920
   486
                    display.name = display_name;
icculus@9920
   487
                }
icculus@9920
   488
                display.desktop_mode = mode;
icculus@9920
   489
                display.current_mode = mode;
icculus@9920
   490
                display.driverdata = displaydata;
icculus@9920
   491
                SDL_AddVideoDisplay(&display);
icculus@9834
   492
            }
philipp@9944
   493
philipp@9944
   494
            X11_XRRFreeScreenResources(res);
icculus@9834
   495
        }
icculus@9834
   496
    }
icculus@9834
   497
icculus@9834
   498
    if (_this->num_displays == 0) {
icculus@9834
   499
        return SDL_SetError("No available displays");
icculus@9834
   500
    }
icculus@9834
   501
icculus@9834
   502
    return 0;
icculus@9834
   503
}
slouken@2873
   504
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   505
slouken@5408
   506
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   507
static SDL_bool
slouken@2874
   508
CheckVidMode(Display * display, int *major, int *minor)
slouken@2873
   509
{
slouken@2873
   510
    const char *env;
slouken@2873
   511
slouken@2873
   512
    /* Default the extension not available */
slouken@2873
   513
    *major = *minor = 0;
slouken@2873
   514
slouken@2873
   515
    /* Allow environment override */
slouken@6472
   516
    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
slouken@2873
   517
    if (env && !SDL_atoi(env)) {
slouken@6468
   518
#ifdef X11MODES_DEBUG
slouken@6472
   519
        printf("XVidMode disabled due to hint\n");
slouken@6468
   520
#endif
slouken@2873
   521
        return SDL_FALSE;
slouken@2873
   522
    }
slouken@2874
   523
slouken@5408
   524
    if (!SDL_X11_HAVE_XVIDMODE) {
slouken@6468
   525
#ifdef X11MODES_DEBUG
slouken@6468
   526
        printf("XVidMode support not available\n");
slouken@6468
   527
#endif
slouken@5408
   528
        return SDL_FALSE;
slouken@5408
   529
    }
slouken@5408
   530
slouken@2873
   531
    /* Query the extension version */
slouken@2873
   532
    vm_error = -1;
icculus@7827
   533
    if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
icculus@7827
   534
        || !X11_XF86VidModeQueryVersion(display, major, minor)) {
slouken@6468
   535
#ifdef X11MODES_DEBUG
slouken@6468
   536
        printf("XVidMode not active on the display\n");
slouken@6468
   537
#endif
slouken@2873
   538
        return SDL_FALSE;
slouken@2873
   539
    }
slouken@6468
   540
#ifdef X11MODES_DEBUG
slouken@6548
   541
    printf("XVidMode available at version %d.%d!\n", *major, *minor);
slouken@6468
   542
#endif
slouken@2873
   543
    return SDL_TRUE;
slouken@2873
   544
}
slouken@2873
   545
slouken@4518
   546
static
slouken@5408
   547
Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
slouken@5408
   548
                                       XF86VidModeModeInfo* info)
slouken@2873
   549
{
slouken@2873
   550
    Bool retval;
slouken@2873
   551
    int dotclock;
slouken@5408
   552
    XF86VidModeModeLine l;
slouken@2873
   553
    SDL_zerop(info);
slouken@2873
   554
    SDL_zero(l);
icculus@7827
   555
    retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
slouken@2873
   556
    info->dotclock = dotclock;
slouken@2873
   557
    info->hdisplay = l.hdisplay;
slouken@2873
   558
    info->hsyncstart = l.hsyncstart;
slouken@2873
   559
    info->hsyncend = l.hsyncend;
slouken@2873
   560
    info->htotal = l.htotal;
slouken@2873
   561
    info->hskew = l.hskew;
slouken@2873
   562
    info->vdisplay = l.vdisplay;
slouken@2873
   563
    info->vsyncstart = l.vsyncstart;
slouken@2873
   564
    info->vsyncend = l.vsyncend;
slouken@2873
   565
    info->vtotal = l.vtotal;
slouken@2873
   566
    info->flags = l.flags;
slouken@2873
   567
    info->privsize = l.privsize;
slouken@2873
   568
    info->private = l.private;
slouken@2873
   569
    return retval;
slouken@2873
   570
}
slouken@2873
   571
slouken@2873
   572
static int
slouken@6548
   573
CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
slouken@2873
   574
{
slouken@2874
   575
    return (info->htotal
slouken@2874
   576
            && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
slouken@2874
   577
                                                         info->vtotal)) : 0;
slouken@2873
   578
}
slouken@2873
   579
slouken@6548
   580
SDL_bool
slouken@6548
   581
SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
slouken@2873
   582
{
slouken@6548
   583
    mode->w = info->hdisplay;
slouken@6548
   584
    mode->h = info->vdisplay;
slouken@6548
   585
    mode->refresh_rate = CalculateXVidModeRefreshRate(info);
slouken@6548
   586
    ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
slouken@6548
   587
    return SDL_TRUE;
slouken@2873
   588
}
slouken@6548
   589
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@2873
   590
slouken@6548
   591
int
slouken@6548
   592
X11_InitModes(_THIS)
slouken@2873
   593
{
slouken@6548
   594
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
gabomdq@9167
   595
    int snum, screen, screencount;
slouken@6548
   596
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   597
    int xinerama_major, xinerama_minor;
slouken@6548
   598
    int use_xinerama = 0;
slouken@6548
   599
    XineramaScreenInfo *xinerama = NULL;
slouken@6548
   600
#endif
slouken@6548
   601
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   602
    int xrandr_major, xrandr_minor;
slouken@6548
   603
#endif
slouken@6548
   604
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   605
    int vm_major, vm_minor;
slouken@6548
   606
    int use_vidmode = 0;
slouken@6548
   607
#endif
slouken@2873
   608
icculus@9834
   609
/* XRandR is the One True Modern Way to do this on X11. If it's enabled and
icculus@9834
   610
   available, don't even look at other ways of doing things. */
icculus@9834
   611
#if SDL_VIDEO_DRIVER_X11_XRANDR
icculus@9834
   612
    /* require at least XRandR v1.3 */
icculus@9834
   613
    if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
icculus@9834
   614
        (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
icculus@9834
   615
        return X11_InitModes_XRandR(_this);
icculus@9834
   616
    }
icculus@9834
   617
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
icculus@9834
   618
icculus@9834
   619
/* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */
icculus@9834
   620
icculus@10015
   621
    /* This is a workaround for some apps (UnrealEngine4, for example) until
icculus@10015
   622
       we sort out the ramifications of removing XVidMode support outright.
icculus@10015
   623
       This block should be removed with the XVidMode support. */
icculus@10015
   624
    {
icculus@10015
   625
        const char *env = SDL_GetHint("SDL_VIDEO_X11_REQUIRE_XRANDR");
icculus@10015
   626
        if (env && SDL_atoi(env)) {
icculus@10015
   627
            #if SDL_VIDEO_DRIVER_X11_XRANDR
icculus@10015
   628
            return SDL_SetError("XRandR support is required but not available");
icculus@10015
   629
            #else
icculus@10015
   630
            return SDL_SetError("XRandR support is required but not built into SDL!");
icculus@10015
   631
            #endif
icculus@10015
   632
        }
icculus@10015
   633
    }
icculus@10015
   634
slouken@6548
   635
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   636
    /* Query Xinerama extention
slouken@6548
   637
     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
slouken@6548
   638
     *       or newer of the Nvidia binary drivers
slouken@6548
   639
     */
slouken@6548
   640
    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
icculus@9789
   641
        int (*handler) (Display *, XErrorEvent *);
icculus@9789
   642
        X11_XSync(data->display, False);
icculus@9789
   643
        handler = X11_XSetErrorHandler(X11_XineramaFailed);
icculus@7827
   644
        xinerama = X11_XineramaQueryScreens(data->display, &screencount);
icculus@9789
   645
        X11_XSync(data->display, False);
icculus@9789
   646
        X11_XSetErrorHandler(handler);
icculus@9789
   647
        if (xinerama_triggered_error) {
icculus@9789
   648
            xinerama = 0;
icculus@9789
   649
        }
slouken@6548
   650
        if (xinerama) {
slouken@6548
   651
            use_xinerama = xinerama_major * 100 + xinerama_minor;
slouken@2873
   652
        }
slouken@2873
   653
    }
slouken@6548
   654
    if (!xinerama) {
slouken@6548
   655
        screencount = ScreenCount(data->display);
slouken@2873
   656
    }
slouken@6548
   657
#else
slouken@6548
   658
    screencount = ScreenCount(data->display);
slouken@6548
   659
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@6548
   660
slouken@6548
   661
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   662
    if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
slouken@6548
   663
        use_vidmode = vm_major * 100 + vm_minor;
slouken@6548
   664
    }
slouken@6548
   665
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   666
gabomdq@9167
   667
    for (snum = 0; snum < screencount; ++snum) {
slouken@6548
   668
        XVisualInfo vinfo;
slouken@6548
   669
        SDL_VideoDisplay display;
slouken@6548
   670
        SDL_DisplayData *displaydata;
slouken@6548
   671
        SDL_DisplayMode mode;
slouken@6548
   672
        SDL_DisplayModeData *modedata;
slouken@6548
   673
        XPixmapFormatValues *pixmapFormats;
slouken@6796
   674
        char display_name[128];
slouken@6548
   675
        int i, n;
slouken@6548
   676
gabomdq@9167
   677
        /* Re-order screens to always put default screen first */
gabomdq@9167
   678
        if (snum == 0) {
gabomdq@9167
   679
            screen = DefaultScreen(data->display);
gabomdq@9167
   680
        } else if (snum == DefaultScreen(data->display)) {
gabomdq@9167
   681
            screen = 0;
gabomdq@9167
   682
        } else {
gabomdq@9167
   683
            screen = snum;
gabomdq@9167
   684
        }
gabomdq@9167
   685
slouken@6548
   686
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   687
        if (xinerama) {
slouken@6548
   688
            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
slouken@6548
   689
                continue;
slouken@6548
   690
            }
slouken@6548
   691
        } else {
slouken@6548
   692
            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   693
                continue;
slouken@6548
   694
            }
slouken@6548
   695
        }
slouken@6548
   696
#else
slouken@6548
   697
        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   698
            continue;
slouken@6548
   699
        }
slouken@6548
   700
#endif
slouken@6548
   701
slouken@6548
   702
        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
slouken@6548
   703
        if (!displaydata) {
slouken@6548
   704
            continue;
slouken@6548
   705
        }
slouken@6796
   706
        display_name[0] = '\0';
slouken@6548
   707
slouken@6548
   708
        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
slouken@6548
   709
        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
slouken@6548
   710
            /* We don't support palettized modes now */
slouken@6548
   711
            SDL_free(displaydata);
slouken@6548
   712
            continue;
slouken@6548
   713
        }
slouken@6548
   714
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   715
        if (xinerama) {
slouken@6548
   716
            mode.w = xinerama[screen].width;
slouken@6548
   717
            mode.h = xinerama[screen].height;
slouken@6548
   718
        } else {
slouken@6548
   719
            mode.w = DisplayWidth(data->display, screen);
slouken@6548
   720
            mode.h = DisplayHeight(data->display, screen);
slouken@6548
   721
        }
slouken@6548
   722
#else
slouken@6548
   723
        mode.w = DisplayWidth(data->display, screen);
slouken@6548
   724
        mode.h = DisplayHeight(data->display, screen);
slouken@6548
   725
#endif
slouken@6548
   726
        mode.refresh_rate = 0;
slouken@6548
   727
slouken@6548
   728
        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   729
        if (!modedata) {
slouken@6548
   730
            SDL_free(displaydata);
slouken@6548
   731
            continue;
slouken@6548
   732
        }
slouken@6548
   733
        mode.driverdata = modedata;
slouken@6548
   734
slouken@6548
   735
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   736
        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
slouken@6548
   737
         * there's only one screen available. So we force the screen number to zero and
slouken@6548
   738
         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
slouken@6548
   739
         */
slouken@6548
   740
        if (use_xinerama) {
slouken@6548
   741
            displaydata->screen = 0;
slouken@6548
   742
            displaydata->use_xinerama = use_xinerama;
slouken@6548
   743
            displaydata->xinerama_info = xinerama[screen];
slouken@6548
   744
            displaydata->xinerama_screen = screen;
slouken@6548
   745
        }
slouken@6548
   746
        else displaydata->screen = screen;
slouken@6548
   747
#else
slouken@6548
   748
        displaydata->screen = screen;
slouken@6548
   749
#endif
slouken@6548
   750
        displaydata->visual = vinfo.visual;
slouken@6548
   751
        displaydata->depth = vinfo.depth;
slouken@6548
   752
alfred@9814
   753
        // We use the displaydata screen index here so that this works
alfred@9814
   754
        // for both the Xinerama case, where we get the overall DPI,
alfred@9814
   755
        // and the regular X11 screen info case.
alfred@9814
   756
        displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f /
alfred@9814
   757
            DisplayWidthMM(data->display, displaydata->screen);
alfred@9814
   758
        displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f /
alfred@9814
   759
            DisplayHeightMM(data->display, displaydata->screen);
alfred@9814
   760
        displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen),
alfred@9814
   761
                                                   DisplayHeight(data->display, displaydata->screen),
alfred@9814
   762
                                                   (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f,
alfred@9814
   763
                                                   (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f);
alfred@9814
   764
slouken@6548
   765
        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
icculus@7827
   766
        pixmapFormats = X11_XListPixmapFormats(data->display, &n);
slouken@6548
   767
        if (pixmapFormats) {
slouken@6548
   768
            for (i = 0; i < n; ++i) {
slouken@6548
   769
                if (pixmapFormats[i].depth == displaydata->depth) {
slouken@6548
   770
                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
slouken@6548
   771
                    break;
slouken@6548
   772
                }
slouken@6548
   773
            }
icculus@7827
   774
            X11_XFree(pixmapFormats);
slouken@6548
   775
        }
slouken@6548
   776
slouken@6548
   777
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   778
        if (use_xinerama) {
slouken@6548
   779
            displaydata->x = xinerama[screen].x_org;
slouken@6548
   780
            displaydata->y = xinerama[screen].y_org;
slouken@6548
   781
        }
slouken@6548
   782
        else
slouken@6548
   783
#endif
slouken@6548
   784
        {
slouken@6548
   785
            displaydata->x = 0;
slouken@6548
   786
            displaydata->y = 0;
slouken@6548
   787
        }
slouken@6548
   788
slouken@6548
   789
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   790
        if (!displaydata->use_xrandr &&
slouken@6548
   791
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6564
   792
            /* XVidMode only works on the screen at the origin */
slouken@6564
   793
            (!displaydata->use_xinerama ||
slouken@6564
   794
             (displaydata->x == 0 && displaydata->y == 0)) &&
slouken@6548
   795
#endif
slouken@6548
   796
            use_vidmode) {
slouken@6548
   797
            displaydata->use_vidmode = use_vidmode;
slouken@6565
   798
            if (displaydata->use_xinerama) {
slouken@6565
   799
                displaydata->vidmode_screen = 0;
slouken@6565
   800
            } else {
slouken@6565
   801
                displaydata->vidmode_screen = screen;
slouken@6565
   802
            }
slouken@6565
   803
            XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
slouken@6548
   804
        }
slouken@6548
   805
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   806
slouken@6548
   807
        SDL_zero(display);
slouken@6796
   808
        if (*display_name) {
slouken@6796
   809
            display.name = display_name;
slouken@6796
   810
        }
slouken@6548
   811
        display.desktop_mode = mode;
slouken@6548
   812
        display.current_mode = mode;
slouken@6548
   813
        display.driverdata = displaydata;
slouken@6548
   814
        SDL_AddVideoDisplay(&display);
slouken@6548
   815
    }
slouken@6548
   816
slouken@6548
   817
#if SDL_VIDEO_DRIVER_X11_XINERAMA
icculus@7827
   818
    if (xinerama) X11_XFree(xinerama);
slouken@6548
   819
#endif
slouken@6548
   820
slouken@6548
   821
    if (_this->num_displays == 0) {
icculus@7037
   822
        return SDL_SetError("No available displays");
slouken@6548
   823
    }
slouken@6548
   824
    return 0;
slouken@2873
   825
}
slouken@2873
   826
slouken@1950
   827
void
slouken@3500
   828
X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
slouken@1950
   829
{
slouken@2870
   830
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@3500
   831
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@5408
   832
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   833
    int nmodes;
slouken@5408
   834
    XF86VidModeModeInfo ** modes;
slouken@2873
   835
#endif
slouken@2873
   836
    int screen_w;
slouken@2873
   837
    int screen_h;
slouken@1950
   838
    SDL_DisplayMode mode;
slouken@2870
   839
slouken@2873
   840
    /* Unfortunately X11 requires the window to be created with the correct
slouken@2873
   841
     * visual and depth ahead of time, but the SDL API allows you to create
slouken@2873
   842
     * a window before setting the fullscreen display mode.  This means that
slouken@2873
   843
     * we have to use the same format for all windows and all display modes.
slouken@2873
   844
     * (or support recreating the window with a new visual behind the scenes)
slouken@2873
   845
     */
slouken@3500
   846
    mode.format = sdl_display->current_mode.format;
slouken@2873
   847
    mode.driverdata = NULL;
slouken@2873
   848
slouken@2873
   849
    screen_w = DisplayWidth(display, data->screen);
slouken@2873
   850
    screen_h = DisplayHeight(display, data->screen);
slouken@2873
   851
slouken@2873
   852
#if SDL_VIDEO_DRIVER_X11_XINERAMA
gabomdq@6331
   853
    if (data->use_xinerama) {
david@7361
   854
        if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
gabomdq@6331
   855
           (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
slouken@8922
   856
            SDL_DisplayModeData *modedata;
david@7361
   857
            /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
david@7361
   858
             * if we're using vidmode.
david@7361
   859
             */
gabomdq@6331
   860
            mode.w = screen_w;
gabomdq@6331
   861
            mode.h = screen_h;
slouken@2873
   862
            mode.refresh_rate = 0;
slouken@6548
   863
            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   864
            if (modedata) {
slouken@6548
   865
                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
slouken@6548
   866
            }
slouken@6548
   867
            mode.driverdata = modedata;
icculus@9832
   868
            if (!SDL_AddDisplayMode(sdl_display, &mode)) {
icculus@9832
   869
                SDL_free(modedata);
icculus@9832
   870
            }
slouken@2873
   871
        }
david@7431
   872
        else if (!data->use_xrandr)
david@7361
   873
        {
slouken@8922
   874
            SDL_DisplayModeData *modedata;
david@7431
   875
            /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
david@7361
   876
            mode.w = data->xinerama_info.width;
david@7361
   877
            mode.h = data->xinerama_info.height;
david@7361
   878
            mode.refresh_rate = 0;
david@7361
   879
            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
david@7361
   880
            if (modedata) {
david@7361
   881
                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
david@7361
   882
            }
david@7361
   883
            mode.driverdata = modedata;
icculus@9832
   884
            if (!SDL_AddDisplayMode(sdl_display, &mode)) {
icculus@9832
   885
                SDL_free(modedata);
icculus@9832
   886
            }
david@7361
   887
        }
david@7361
   888
slouken@2873
   889
    }
slouken@2873
   890
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   891
slouken@2873
   892
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   893
    if (data->use_xrandr) {
slouken@6548
   894
        XRRScreenResources *res;
slouken@2873
   895
icculus@7827
   896
        res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
slouken@6548
   897
        if (res) {
slouken@6548
   898
            SDL_DisplayModeData *modedata;
slouken@6548
   899
            XRROutputInfo *output_info;
slouken@6548
   900
            int i;
slouken@2873
   901
icculus@7827
   902
            output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
slouken@6548
   903
            if (output_info && output_info->connection != RR_Disconnected) {
slouken@6548
   904
                for (i = 0; i < output_info->nmode; ++i) {
slouken@6548
   905
                    modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   906
                    if (!modedata) {
slouken@6548
   907
                        continue;
slouken@6548
   908
                    }
slouken@6548
   909
                    mode.driverdata = modedata;
slouken@2873
   910
icculus@9834
   911
                    if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) ||
icculus@9832
   912
                        !SDL_AddDisplayMode(sdl_display, &mode)) {
slouken@6548
   913
                        SDL_free(modedata);
slouken@6548
   914
                    }
slouken@2873
   915
                }
slouken@2873
   916
            }
icculus@7827
   917
            X11_XRRFreeOutputInfo(output_info);
icculus@7827
   918
            X11_XRRFreeScreenResources(res);
slouken@2873
   919
        }
slouken@6548
   920
        return;
slouken@2873
   921
    }
slouken@2873
   922
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   923
slouken@5408
   924
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   925
    if (data->use_vidmode &&
icculus@7827
   926
        X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
slouken@2873
   927
        int i;
slouken@8922
   928
        SDL_DisplayModeData *modedata;
slouken@2873
   929
slouken@2873
   930
#ifdef X11MODES_DEBUG
slouken@2873
   931
        printf("VidMode modes: (unsorted)\n");
slouken@2873
   932
        for (i = 0; i < nmodes; ++i) {
slouken@6566
   933
            printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
slouken@2874
   934
                   modes[i]->hdisplay, modes[i]->vdisplay,
slouken@6566
   935
                   CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
slouken@2873
   936
        }
slouken@2873
   937
#endif
slouken@2873
   938
        for (i = 0; i < nmodes; ++i) {
slouken@6548
   939
            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   940
            if (!modedata) {
slouken@6548
   941
                continue;
slouken@6548
   942
            }
slouken@6548
   943
            mode.driverdata = modedata;
slouken@6548
   944
icculus@9832
   945
            if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) {
slouken@6548
   946
                SDL_free(modedata);
slouken@6548
   947
            }
slouken@2873
   948
        }
icculus@7827
   949
        X11_XFree(modes);
slouken@6548
   950
        return;
slouken@2873
   951
    }
slouken@5408
   952
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@2873
   953
slouken@2873
   954
    if (!data->use_xrandr && !data->use_vidmode) {
slouken@8922
   955
        SDL_DisplayModeData *modedata;
slouken@6548
   956
        /* Add the desktop mode */
slouken@6548
   957
        mode = sdl_display->desktop_mode;
slouken@6548
   958
        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   959
        if (modedata) {
slouken@6548
   960
            *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
slouken@6548
   961
        }
slouken@6548
   962
        mode.driverdata = modedata;
icculus@9832
   963
        if (!SDL_AddDisplayMode(sdl_display, &mode)) {
icculus@9832
   964
            SDL_free(modedata);
icculus@9832
   965
        }
slouken@2874
   966
    }
slouken@1950
   967
}
slouken@1950
   968
slouken@1950
   969
int
slouken@3500
   970
X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
slouken@1950
   971
{
icculus@9319
   972
    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
icculus@9319
   973
    Display *display = viddata->display;
slouken@3500
   974
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@6548
   975
    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
slouken@2873
   976
icculus@9319
   977
    viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2);
icculus@9319
   978
slouken@6548
   979
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   980
    if (data->use_xrandr) {
slouken@6548
   981
        XRRScreenResources *res;
slouken@6548
   982
        XRROutputInfo *output_info;
slouken@6548
   983
        XRRCrtcInfo *crtc;
slouken@6548
   984
        Status status;
slouken@6548
   985
icculus@7827
   986
        res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
slouken@6548
   987
        if (!res) {
icculus@7037
   988
            return SDL_SetError("Couldn't get XRandR screen resources");
slouken@6548
   989
        }
slouken@6548
   990
icculus@7827
   991
        output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
slouken@6548
   992
        if (!output_info || output_info->connection == RR_Disconnected) {
icculus@7827
   993
            X11_XRRFreeScreenResources(res);
icculus@7037
   994
            return SDL_SetError("Couldn't get XRandR output info");
slouken@6548
   995
        }
slouken@6548
   996
icculus@7827
   997
        crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
slouken@6548
   998
        if (!crtc) {
icculus@7827
   999
            X11_XRRFreeOutputInfo(output_info);
icculus@7827
  1000
            X11_XRRFreeScreenResources(res);
icculus@7037
  1001
            return SDL_SetError("Couldn't get XRandR crtc info");
slouken@6548
  1002
        }
slouken@6548
  1003
icculus@7827
  1004
        status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
slouken@6548
  1005
          crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
slouken@6548
  1006
          &data->xrandr_output, 1);
slouken@6548
  1007
icculus@7827
  1008
        X11_XRRFreeCrtcInfo(crtc);
icculus@7827
  1009
        X11_XRRFreeOutputInfo(output_info);
icculus@7827
  1010
        X11_XRRFreeScreenResources(res);
slouken@6548
  1011
slouken@6548
  1012
        if (status != Success) {
icculus@7827
  1013
            return SDL_SetError("X11_XRRSetCrtcConfig failed");
slouken@6548
  1014
        }
slouken@6548
  1015
    }
slouken@6548
  1016
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@6548
  1017
slouken@6548
  1018
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
  1019
    if (data->use_vidmode) {
icculus@7827
  1020
        X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
slouken@6548
  1021
    }
slouken@6548
  1022
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
  1023
slouken@2873
  1024
    return 0;
slouken@1950
  1025
}
slouken@1950
  1026
slouken@1950
  1027
void
slouken@1950
  1028
X11_QuitModes(_THIS)
slouken@1950
  1029
{
slouken@1950
  1030
}
slouken@1950
  1031
gabomdq@6331
  1032
int
gabomdq@6331
  1033
X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
gabomdq@6331
  1034
{
gabomdq@6331
  1035
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@6502
  1036
slouken@6548
  1037
    rect->x = data->x;
slouken@6548
  1038
    rect->y = data->y;
slouken@6548
  1039
    rect->w = sdl_display->current_mode.w;
slouken@6548
  1040
    rect->h = sdl_display->current_mode.h;
gabomdq@6331
  1041
gabomdq@6331
  1042
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
  1043
    /* Get the real current bounds of the display */
slouken@6502
  1044
    if (data->use_xinerama) {
icculus@7485
  1045
        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@6548
  1046
        int screencount;
icculus@7827
  1047
        XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
slouken@6548
  1048
        if (xinerama) {
slouken@6548
  1049
            rect->x = xinerama[data->xinerama_screen].x_org;
slouken@6548
  1050
            rect->y = xinerama[data->xinerama_screen].y_org;
icculus@7827
  1051
            X11_XFree(xinerama);
slouken@6548
  1052
        }
gabomdq@6331
  1053
    }
slouken@6548
  1054
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@6475
  1055
    return 0;
gabomdq@6331
  1056
}
gabomdq@6331
  1057
alfred@9814
  1058
int
alfred@9814
  1059
X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi)
alfred@9814
  1060
{
alfred@9814
  1061
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
alfred@9814
  1062
alfred@9814
  1063
    if (ddpi) {
alfred@9814
  1064
        *ddpi = data->ddpi;
alfred@9814
  1065
    }
alfred@9814
  1066
    if (hdpi) {
alfred@9814
  1067
        *hdpi = data->hdpi;
alfred@9814
  1068
    }
alfred@9814
  1069
    if (vdpi) {
alfred@9815
  1070
        *vdpi = data->vdpi;
alfred@9814
  1071
    }
alfred@9814
  1072
philipp@10172
  1073
    return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
alfred@9814
  1074
}
alfred@9814
  1075
icculus@10019
  1076
int
icculus@10019
  1077
X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
icculus@10019
  1078
{
icculus@10019
  1079
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
icculus@10019
  1080
    Display *display = data->display;
icculus@10019
  1081
    Atom _NET_WORKAREA;
icculus@10019
  1082
    int status, real_format;
icculus@10019
  1083
    int retval = -1;
icculus@10019
  1084
    Atom real_type;
icculus@10019
  1085
    unsigned long items_read = 0, items_left = 0;
icculus@10019
  1086
    unsigned char *propdata = NULL;
icculus@10019
  1087
icculus@10019
  1088
    if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) {
icculus@10019
  1089
        return -1;
icculus@10019
  1090
    }
icculus@10019
  1091
icculus@10019
  1092
    _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False);
icculus@10019
  1093
    status = X11_XGetWindowProperty(display, DefaultRootWindow(display),
icculus@10019
  1094
                                    _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL,
icculus@10019
  1095
                                    &real_type, &real_format, &items_read,
icculus@10019
  1096
                                    &items_left, &propdata);
icculus@10019
  1097
    if ((status == Success) && (items_read >= 4)) {
icculus@10019
  1098
        const long *p = (long*) propdata;
icculus@10019
  1099
        const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] };
icculus@10031
  1100
        retval = 0;
icculus@10019
  1101
        if (!SDL_IntersectRect(rect, &usable, rect)) {
icculus@10019
  1102
            SDL_zerop(rect);
icculus@10019
  1103
        }
icculus@10019
  1104
    }
icculus@10019
  1105
icculus@10019
  1106
    if (propdata) {
icculus@10019
  1107
        X11_XFree(propdata);
icculus@10019
  1108
    }
icculus@10019
  1109
icculus@10019
  1110
    return retval;
icculus@10019
  1111
}
icculus@10019
  1112
slouken@5481
  1113
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
  1114
slouken@1950
  1115
/* vi: set ts=4 sw=4 expandtab: */