src/video/x11/SDL_x11modes.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 05 Sep 2017 08:24:38 -0700
changeset 11454 f6b9e7bd038a
parent 11344 039ef928e200
child 11689 64ec7aae69e3
permissions -rw-r--r--
Fixed bug 3273 - Fix for slow video subsystem initialization when using XRandR.

Martín Golini

I'm having a very slow initialization of the video subsystem that locks the window creation for about 500 ms ( tested in at least 4 different systems ). What i found is that X11_InitModes_XRandR is using XRRGetScreenResources, that explicitly ask to poll the hardware for changes. This is not really necessary since if the data is already available you can use XRRGetScreenResourcesCurrent.
I attached a tentative patch that fix this issue. With the patch there's no lock when the subsystem is initialized and the window creation is instant in my applications. The patch only uses XRRGetScreenResourcesCurrent in X11_InitModes_XRandR but it could be potentially used in X11_GetDisplayModes and X11_SetDisplayMode.
slouken@1950
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 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@10609
   137
            /* break; -Wunreachable-code-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@10609
   144
            /* break; -Wunreachable-code-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@10609
   152
static 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
slouken@2873
   161
    /* Default the extension not available */
slouken@2873
   162
    *major = *minor = 0;
slouken@2873
   163
slouken@2873
   164
    /* Allow environment override */
slouken@10499
   165
    if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XINERAMA, SDL_TRUE)) {
slouken@6468
   166
#ifdef X11MODES_DEBUG
slouken@6472
   167
        printf("Xinerama disabled due to hint\n");
slouken@6468
   168
#endif
slouken@2873
   169
        return SDL_FALSE;
slouken@2873
   170
    }
slouken@2873
   171
slouken@5408
   172
    if (!SDL_X11_HAVE_XINERAMA) {
slouken@6468
   173
#ifdef X11MODES_DEBUG
slouken@6468
   174
        printf("Xinerama support not available\n");
slouken@6468
   175
#endif
slouken@5408
   176
        return SDL_FALSE;
slouken@5408
   177
    }
slouken@5408
   178
slouken@2873
   179
    /* Query the extension version */
icculus@7827
   180
    if (!X11_XineramaQueryExtension(display, &event_base, &error_base) ||
icculus@7827
   181
        !X11_XineramaQueryVersion(display, major, minor) ||
icculus@7827
   182
        !X11_XineramaIsActive(display)) {
slouken@6468
   183
#ifdef X11MODES_DEBUG
slouken@6468
   184
        printf("Xinerama not active on the display\n");
slouken@6468
   185
#endif
slouken@2873
   186
        return SDL_FALSE;
slouken@2873
   187
    }
slouken@6468
   188
#ifdef X11MODES_DEBUG
slouken@6548
   189
    printf("Xinerama available at version %d.%d!\n", *major, *minor);
slouken@6468
   190
#endif
slouken@2873
   191
    return SDL_TRUE;
slouken@2873
   192
}
icculus@9789
   193
icculus@9789
   194
/* !!! FIXME: remove this later. */
icculus@9789
   195
/* we have a weird bug where XineramaQueryScreens() throws an X error, so this
icculus@9789
   196
   is here to help track it down (and not crash, too!). */
icculus@9789
   197
static SDL_bool xinerama_triggered_error = SDL_FALSE;
icculus@9789
   198
static int
icculus@9789
   199
X11_XineramaFailed(Display * d, XErrorEvent * e)
icculus@9789
   200
{
icculus@9789
   201
    xinerama_triggered_error = SDL_TRUE;
icculus@9789
   202
    fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n",
icculus@9789
   203
            e->type, e->serial, (unsigned int) e->error_code,
icculus@9789
   204
            (unsigned int) e->request_code, (unsigned int) e->minor_code);
icculus@9789
   205
    fflush(stderr);
icculus@9789
   206
    return 0;
icculus@9789
   207
}
slouken@2873
   208
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@2873
   209
slouken@2873
   210
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@2873
   211
static SDL_bool
slouken@2874
   212
CheckXRandR(Display * display, int *major, int *minor)
slouken@2873
   213
{
slouken@2873
   214
    /* Default the extension not available */
slouken@2873
   215
    *major = *minor = 0;
slouken@2873
   216
slouken@2873
   217
    /* Allow environment override */
slouken@6558
   218
#ifdef XRANDR_DISABLED_BY_DEFAULT
slouken@10499
   219
    if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_FALSE)) {
slouken@6558
   220
#ifdef X11MODES_DEBUG
slouken@6558
   221
        printf("XRandR disabled by default due to window manager issues\n");
slouken@6558
   222
#endif
slouken@6558
   223
        return SDL_FALSE;
slouken@6558
   224
    }
slouken@6558
   225
#else
slouken@10499
   226
    if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_TRUE)) {
slouken@6468
   227
#ifdef X11MODES_DEBUG
slouken@6472
   228
        printf("XRandR disabled due to hint\n");
slouken@6468
   229
#endif
slouken@2873
   230
        return SDL_FALSE;
slouken@2873
   231
    }
slouken@6558
   232
#endif /* XRANDR_ENABLED_BY_DEFAULT */
slouken@2873
   233
slouken@2873
   234
    if (!SDL_X11_HAVE_XRANDR) {
slouken@6468
   235
#ifdef X11MODES_DEBUG
slouken@6468
   236
        printf("XRandR support not available\n");
slouken@6468
   237
#endif
slouken@2873
   238
        return SDL_FALSE;
slouken@2873
   239
    }
slouken@2873
   240
slouken@2873
   241
    /* Query the extension version */
icculus@9834
   242
    *major = 1; *minor = 3;  /* we want 1.3 */
icculus@7827
   243
    if (!X11_XRRQueryVersion(display, major, minor)) {
slouken@6468
   244
#ifdef X11MODES_DEBUG
slouken@6468
   245
        printf("XRandR not active on the display\n");
slouken@6468
   246
#endif
icculus@9834
   247
        *major = *minor = 0;
slouken@2873
   248
        return SDL_FALSE;
slouken@2873
   249
    }
slouken@6468
   250
#ifdef X11MODES_DEBUG
slouken@6548
   251
    printf("XRandR available at version %d.%d!\n", *major, *minor);
slouken@6468
   252
#endif
slouken@2873
   253
    return SDL_TRUE;
slouken@2873
   254
}
slouken@6537
   255
slouken@6537
   256
#define XRANDR_ROTATION_LEFT    (1 << 1)
slouken@6537
   257
#define XRANDR_ROTATION_RIGHT   (1 << 3)
slouken@6537
   258
slouken@6548
   259
static int
slouken@6548
   260
CalculateXRandRRefreshRate(const XRRModeInfo *info)
slouken@6537
   261
{
slouken@10437
   262
    return (info->hTotal && info->vTotal) ?
slouken@10437
   263
        round(((double)info->dotClock / (double)(info->hTotal * info->vTotal))) : 0;
slouken@6548
   264
}
slouken@6548
   265
slouken@6548
   266
static SDL_bool
icculus@9834
   267
SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc,
slouken@6548
   268
                  RRMode modeID, SDL_DisplayMode *mode)
slouken@6548
   269
{
slouken@6548
   270
    int i;
slouken@6548
   271
    for (i = 0; i < res->nmode; ++i) {
icculus@9834
   272
        const XRRModeInfo *info = &res->modes[i];
icculus@9834
   273
        if (info->id == modeID) {
icculus@9834
   274
            XRRCrtcInfo *crtcinfo;
slouken@6548
   275
            Rotation rotation = 0;
slouken@6548
   276
icculus@9834
   277
            crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc);
icculus@9834
   278
            if (crtcinfo) {
icculus@9834
   279
                rotation = crtcinfo->rotation;
icculus@9834
   280
                X11_XRRFreeCrtcInfo(crtcinfo);
slouken@6548
   281
            }
slouken@6548
   282
slouken@6548
   283
            if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
slouken@6548
   284
                mode->w = info->height;
slouken@6548
   285
                mode->h = info->width;
slouken@6548
   286
            } else {
slouken@6548
   287
                mode->w = info->width;
slouken@6548
   288
                mode->h = info->height;
slouken@6548
   289
            }
slouken@6548
   290
            mode->refresh_rate = CalculateXRandRRefreshRate(info);
slouken@6548
   291
            ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
slouken@6548
   292
#ifdef X11MODES_DEBUG
icculus@6560
   293
            printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
slouken@6548
   294
#endif
slouken@6548
   295
            return SDL_TRUE;
slouken@6548
   296
        }
slouken@6537
   297
    }
slouken@6548
   298
    return SDL_FALSE;
slouken@6537
   299
}
icculus@9834
   300
icculus@9834
   301
static void
icculus@9834
   302
SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm)
icculus@9834
   303
{
icculus@9834
   304
    /* See if we can get the EDID data for the real monitor name */
icculus@9834
   305
    int inches;
icculus@9834
   306
    int nprop;
icculus@9834
   307
    Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop);
icculus@9834
   308
    int i;
icculus@9834
   309
icculus@9834
   310
    for (i = 0; i < nprop; ++i) {
icculus@9834
   311
        unsigned char *prop;
icculus@9834
   312
        int actual_format;
icculus@9834
   313
        unsigned long nitems, bytes_after;
icculus@9834
   314
        Atom actual_type;
icculus@9834
   315
icculus@9834
   316
        if (props[i] == EDID) {
icculus@9834
   317
            if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False,
icculus@9834
   318
                                         False, AnyPropertyType, &actual_type,
icculus@9834
   319
                                         &actual_format, &nitems, &bytes_after,
icculus@9834
   320
                                         &prop) == Success) {
icculus@9834
   321
                MonitorInfo *info = decode_edid(prop);
icculus@9834
   322
                if (info) {
icculus@9834
   323
#ifdef X11MODES_DEBUG
icculus@9834
   324
                    printf("Found EDID data for %s\n", name);
icculus@9834
   325
                    dump_monitor_info(info);
icculus@9834
   326
#endif
icculus@9834
   327
                    SDL_strlcpy(name, info->dsc_product_name, namelen);
icculus@9834
   328
                    free(info);
icculus@9834
   329
                }
icculus@9834
   330
                X11_XFree(prop);
icculus@9834
   331
            }
icculus@9834
   332
            break;
icculus@9834
   333
        }
icculus@9834
   334
    }
icculus@9834
   335
icculus@9834
   336
    if (props) {
icculus@9834
   337
        X11_XFree(props);
icculus@9834
   338
    }
icculus@9834
   339
icculus@10030
   340
    inches = (int)((SDL_sqrtf(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f);
icculus@9834
   341
    if (*name && inches) {
icculus@9834
   342
        const size_t len = SDL_strlen(name);
icculus@9834
   343
        SDL_snprintf(&name[len], namelen-len, " %d\"", inches);
icculus@9834
   344
    }
icculus@9834
   345
icculus@9834
   346
#ifdef X11MODES_DEBUG
icculus@9834
   347
    printf("Display name: %s\n", name);
icculus@9834
   348
#endif
icculus@9834
   349
}
icculus@9834
   350
icculus@9834
   351
slouken@10609
   352
static int
icculus@9834
   353
X11_InitModes_XRandR(_THIS)
icculus@9834
   354
{
icculus@9834
   355
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
icculus@9834
   356
    Display *dpy = data->display;
icculus@9920
   357
    const int screencount = ScreenCount(dpy);
icculus@9920
   358
    const int default_screen = DefaultScreen(dpy);
icculus@9920
   359
    RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen));
icculus@9834
   360
    Atom EDID = X11_XInternAtom(dpy, "EDID", False);
icculus@9834
   361
    XRRScreenResources *res = NULL;
icculus@9834
   362
    Uint32 pixelformat;
icculus@9834
   363
    XVisualInfo vinfo;
icculus@9834
   364
    XPixmapFormatValues *pixmapformats;
icculus@9834
   365
    int looking_for_primary;
icculus@9834
   366
    int scanline_pad;
icculus@9834
   367
    int output;
icculus@9920
   368
    int screen, i, n;
icculus@9834
   369
icculus@9834
   370
    for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) {
icculus@9920
   371
        for (screen = 0; screen < screencount; screen++) {
icculus@9834
   372
icculus@9920
   373
            /* we want the primary output first, and then skipped later. */
icculus@9984
   374
            if (looking_for_primary && (screen != default_screen)) {
icculus@9834
   375
                continue;
icculus@9834
   376
            }
icculus@9834
   377
icculus@9920
   378
            if (get_visualinfo(dpy, screen, &vinfo) < 0) {
icculus@9920
   379
                continue;  /* uh, skip this screen? */
icculus@9920
   380
            }
icculus@9920
   381
icculus@9920
   382
            pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
icculus@9920
   383
            if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
icculus@9920
   384
                continue;  /* Palettized video modes are no longer supported */
icculus@9920
   385
            }
icculus@9920
   386
icculus@9920
   387
            scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
icculus@9920
   388
            pixmapformats = X11_XListPixmapFormats(dpy, &n);
icculus@9920
   389
            if (pixmapformats) {
icculus@9920
   390
                for (i = 0; i < n; ++i) {
icculus@9920
   391
                    if (pixmapformats[i].depth == vinfo.depth) {
icculus@9920
   392
                        scanline_pad = pixmapformats[i].scanline_pad;
icculus@9920
   393
                        break;
icculus@9920
   394
                    }
icculus@9920
   395
                }
icculus@9920
   396
                X11_XFree(pixmapformats);
icculus@9920
   397
            }
icculus@9920
   398
slouken@11454
   399
            res = X11_XRRGetScreenResourcesCurrent(dpy, RootWindow(dpy, screen));
slouken@11454
   400
            if (!res || res->noutput == 0) {
slouken@11454
   401
                if (res) {
slouken@11454
   402
                    X11_XRRFreeScreenResources(res);
slouken@11454
   403
                }
slouken@11454
   404
slouken@11454
   405
                res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
slouken@11454
   406
                if (!res) {
slouken@11454
   407
                    continue;
slouken@11454
   408
                }
icculus@9834
   409
            }
icculus@9834
   410
icculus@9920
   411
            for (output = 0; output < res->noutput; output++) {
icculus@9920
   412
                XRROutputInfo *output_info;
icculus@9920
   413
                int display_x, display_y;
icculus@9920
   414
                unsigned long display_mm_width, display_mm_height;
icculus@9920
   415
                SDL_DisplayData *displaydata;
icculus@9920
   416
                char display_name[128];
icculus@9920
   417
                SDL_DisplayMode mode;
icculus@9920
   418
                SDL_DisplayModeData *modedata;
icculus@9920
   419
                SDL_VideoDisplay display;
icculus@9920
   420
                RRMode modeID;
icculus@9920
   421
                RRCrtc output_crtc;
icculus@9920
   422
                XRRCrtcInfo *crtc;
icculus@9834
   423
icculus@9920
   424
                /* The primary output _should_ always be sorted first, but just in case... */
icculus@9984
   425
                if ((looking_for_primary && (res->outputs[output] != primary)) ||
icculus@9920
   426
                    (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
icculus@9920
   427
                    continue;
icculus@9920
   428
                }
icculus@9920
   429
icculus@9920
   430
                output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
icculus@9920
   431
                if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
icculus@9920
   432
                    X11_XRRFreeOutputInfo(output_info);
icculus@9920
   433
                    continue;
icculus@9920
   434
                }
icculus@9920
   435
icculus@9920
   436
                SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
icculus@9920
   437
                display_mm_width = output_info->mm_width;
icculus@9920
   438
                display_mm_height = output_info->mm_height;
icculus@9920
   439
                output_crtc = output_info->crtc;
icculus@9920
   440
                X11_XRRFreeOutputInfo(output_info);
icculus@9920
   441
icculus@9920
   442
                crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
icculus@9920
   443
                if (!crtc) {
icculus@9920
   444
                    continue;
icculus@9920
   445
                }
icculus@9920
   446
icculus@9920
   447
                SDL_zero(mode);
icculus@9920
   448
                modeID = crtc->mode;
icculus@9920
   449
                mode.w = crtc->width;
icculus@9920
   450
                mode.h = crtc->height;
icculus@9920
   451
                mode.format = pixelformat;
icculus@9920
   452
icculus@9920
   453
                display_x = crtc->x;
icculus@9920
   454
                display_y = crtc->y;
icculus@9920
   455
icculus@9920
   456
                X11_XRRFreeCrtcInfo(crtc);
icculus@9920
   457
icculus@9920
   458
                displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
icculus@9920
   459
                if (!displaydata) {
icculus@9920
   460
                    return SDL_OutOfMemory();
icculus@9920
   461
                }
icculus@9920
   462
icculus@9920
   463
                modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
icculus@9920
   464
                if (!modedata) {
icculus@9920
   465
                    SDL_free(displaydata);
icculus@9920
   466
                    return SDL_OutOfMemory();
icculus@9920
   467
                }
icculus@9920
   468
                modedata->xrandr_mode = modeID;
icculus@9920
   469
                mode.driverdata = modedata;
icculus@9920
   470
icculus@9920
   471
                displaydata->screen = screen;
icculus@9920
   472
                displaydata->visual = vinfo.visual;
icculus@9920
   473
                displaydata->depth = vinfo.depth;
icculus@10746
   474
                displaydata->hdpi = display_mm_width ? (((float) mode.w) * 25.4f / display_mm_width) : 0.0f;
icculus@10746
   475
                displaydata->vdpi = display_mm_height ? (((float) mode.h) * 25.4f / display_mm_height) : 0.0f;
icculus@9920
   476
                displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
icculus@9920
   477
                displaydata->scanline_pad = scanline_pad;
icculus@9920
   478
                displaydata->x = display_x;
icculus@9920
   479
                displaydata->y = display_y;
icculus@9920
   480
                displaydata->use_xrandr = 1;
icculus@9920
   481
                displaydata->xrandr_output = res->outputs[output];
icculus@9920
   482
icculus@9920
   483
                SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
icculus@9920
   484
                SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
icculus@9920
   485
icculus@9920
   486
                SDL_zero(display);
icculus@9920
   487
                if (*display_name) {
icculus@9920
   488
                    display.name = display_name;
icculus@9920
   489
                }
icculus@9920
   490
                display.desktop_mode = mode;
icculus@9920
   491
                display.current_mode = mode;
icculus@9920
   492
                display.driverdata = displaydata;
icculus@9920
   493
                SDL_AddVideoDisplay(&display);
icculus@9834
   494
            }
philipp@9944
   495
philipp@9944
   496
            X11_XRRFreeScreenResources(res);
icculus@9834
   497
        }
icculus@9834
   498
    }
icculus@9834
   499
icculus@9834
   500
    if (_this->num_displays == 0) {
icculus@9834
   501
        return SDL_SetError("No available displays");
icculus@9834
   502
    }
icculus@9834
   503
icculus@9834
   504
    return 0;
icculus@9834
   505
}
slouken@2873
   506
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
slouken@2873
   507
slouken@5408
   508
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   509
static SDL_bool
slouken@2874
   510
CheckVidMode(Display * display, int *major, int *minor)
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@10499
   516
    if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XVIDMODE, SDL_TRUE)) {
slouken@6468
   517
#ifdef X11MODES_DEBUG
slouken@6472
   518
        printf("XVidMode disabled due to hint\n");
slouken@6468
   519
#endif
slouken@2873
   520
        return SDL_FALSE;
slouken@2873
   521
    }
slouken@2874
   522
slouken@5408
   523
    if (!SDL_X11_HAVE_XVIDMODE) {
slouken@6468
   524
#ifdef X11MODES_DEBUG
slouken@6468
   525
        printf("XVidMode support not available\n");
slouken@6468
   526
#endif
slouken@5408
   527
        return SDL_FALSE;
slouken@5408
   528
    }
slouken@5408
   529
slouken@2873
   530
    /* Query the extension version */
slouken@2873
   531
    vm_error = -1;
icculus@7827
   532
    if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
icculus@7827
   533
        || !X11_XF86VidModeQueryVersion(display, major, minor)) {
slouken@6468
   534
#ifdef X11MODES_DEBUG
slouken@6468
   535
        printf("XVidMode not active on the display\n");
slouken@6468
   536
#endif
slouken@2873
   537
        return SDL_FALSE;
slouken@2873
   538
    }
slouken@6468
   539
#ifdef X11MODES_DEBUG
slouken@6548
   540
    printf("XVidMode available at version %d.%d!\n", *major, *minor);
slouken@6468
   541
#endif
slouken@2873
   542
    return SDL_TRUE;
slouken@2873
   543
}
slouken@2873
   544
slouken@4518
   545
static
slouken@5408
   546
Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
slouken@5408
   547
                                       XF86VidModeModeInfo* info)
slouken@2873
   548
{
slouken@2873
   549
    Bool retval;
slouken@2873
   550
    int dotclock;
slouken@5408
   551
    XF86VidModeModeLine l;
slouken@2873
   552
    SDL_zerop(info);
slouken@2873
   553
    SDL_zero(l);
icculus@7827
   554
    retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
slouken@2873
   555
    info->dotclock = dotclock;
slouken@2873
   556
    info->hdisplay = l.hdisplay;
slouken@2873
   557
    info->hsyncstart = l.hsyncstart;
slouken@2873
   558
    info->hsyncend = l.hsyncend;
slouken@2873
   559
    info->htotal = l.htotal;
slouken@2873
   560
    info->hskew = l.hskew;
slouken@2873
   561
    info->vdisplay = l.vdisplay;
slouken@2873
   562
    info->vsyncstart = l.vsyncstart;
slouken@2873
   563
    info->vsyncend = l.vsyncend;
slouken@2873
   564
    info->vtotal = l.vtotal;
slouken@2873
   565
    info->flags = l.flags;
slouken@2873
   566
    info->privsize = l.privsize;
slouken@2873
   567
    info->private = l.private;
slouken@2873
   568
    return retval;
slouken@2873
   569
}
slouken@2873
   570
slouken@2873
   571
static int
slouken@6548
   572
CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
slouken@2873
   573
{
slouken@2874
   574
    return (info->htotal
slouken@2874
   575
            && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
slouken@2874
   576
                                                         info->vtotal)) : 0;
slouken@2873
   577
}
slouken@2873
   578
slouken@10609
   579
static SDL_bool
slouken@6548
   580
SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
slouken@2873
   581
{
slouken@6548
   582
    mode->w = info->hdisplay;
slouken@6548
   583
    mode->h = info->vdisplay;
slouken@6548
   584
    mode->refresh_rate = CalculateXVidModeRefreshRate(info);
slouken@6548
   585
    ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
slouken@6548
   586
    return SDL_TRUE;
slouken@2873
   587
}
slouken@6548
   588
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@2873
   589
slouken@6548
   590
int
slouken@6548
   591
X11_InitModes(_THIS)
slouken@2873
   592
{
slouken@6548
   593
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@10609
   594
    int snum, screen, screencount = 0;
slouken@6548
   595
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   596
    int xinerama_major, xinerama_minor;
slouken@6548
   597
    int use_xinerama = 0;
slouken@6548
   598
    XineramaScreenInfo *xinerama = NULL;
slouken@6548
   599
#endif
slouken@6548
   600
#if SDL_VIDEO_DRIVER_X11_XRANDR
slouken@6548
   601
    int xrandr_major, xrandr_minor;
slouken@6548
   602
#endif
slouken@6548
   603
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   604
    int vm_major, vm_minor;
slouken@6548
   605
    int use_vidmode = 0;
slouken@6548
   606
#endif
slouken@2873
   607
icculus@9834
   608
/* XRandR is the One True Modern Way to do this on X11. If it's enabled and
icculus@9834
   609
   available, don't even look at other ways of doing things. */
icculus@9834
   610
#if SDL_VIDEO_DRIVER_X11_XRANDR
icculus@9834
   611
    /* require at least XRandR v1.3 */
icculus@9834
   612
    if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
icculus@9834
   613
        (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
slouken@11177
   614
        if (X11_InitModes_XRandR(_this) == 0)
slouken@11177
   615
            return 0;
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
    {
slouken@10499
   625
        if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) {
icculus@10015
   626
            #if SDL_VIDEO_DRIVER_X11_XRANDR
icculus@10015
   627
            return SDL_SetError("XRandR support is required but not available");
icculus@10015
   628
            #else
icculus@10015
   629
            return SDL_SetError("XRandR support is required but not built into SDL!");
icculus@10015
   630
            #endif
icculus@10015
   631
        }
icculus@10015
   632
    }
icculus@10015
   633
slouken@6548
   634
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   635
    /* Query Xinerama extention
slouken@6548
   636
     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
slouken@6548
   637
     *       or newer of the Nvidia binary drivers
slouken@6548
   638
     */
slouken@6548
   639
    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
icculus@9789
   640
        int (*handler) (Display *, XErrorEvent *);
icculus@9789
   641
        X11_XSync(data->display, False);
icculus@9789
   642
        handler = X11_XSetErrorHandler(X11_XineramaFailed);
icculus@7827
   643
        xinerama = X11_XineramaQueryScreens(data->display, &screencount);
icculus@9789
   644
        X11_XSync(data->display, False);
icculus@9789
   645
        X11_XSetErrorHandler(handler);
icculus@9789
   646
        if (xinerama_triggered_error) {
icculus@9789
   647
            xinerama = 0;
icculus@9789
   648
        }
slouken@6548
   649
        if (xinerama) {
slouken@6548
   650
            use_xinerama = xinerama_major * 100 + xinerama_minor;
slouken@2873
   651
        }
slouken@2873
   652
    }
slouken@6548
   653
    if (!xinerama) {
slouken@6548
   654
        screencount = ScreenCount(data->display);
slouken@2873
   655
    }
slouken@6548
   656
#else
slouken@6548
   657
    screencount = ScreenCount(data->display);
slouken@6548
   658
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
slouken@6548
   659
slouken@6548
   660
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   661
    if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
slouken@6548
   662
        use_vidmode = vm_major * 100 + vm_minor;
slouken@6548
   663
    }
slouken@6548
   664
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   665
gabomdq@9167
   666
    for (snum = 0; snum < screencount; ++snum) {
slouken@6548
   667
        XVisualInfo vinfo;
slouken@6548
   668
        SDL_VideoDisplay display;
slouken@6548
   669
        SDL_DisplayData *displaydata;
slouken@6548
   670
        SDL_DisplayMode mode;
slouken@6548
   671
        SDL_DisplayModeData *modedata;
slouken@6548
   672
        XPixmapFormatValues *pixmapFormats;
slouken@6796
   673
        char display_name[128];
slouken@6548
   674
        int i, n;
slouken@6548
   675
gabomdq@9167
   676
        /* Re-order screens to always put default screen first */
gabomdq@9167
   677
        if (snum == 0) {
gabomdq@9167
   678
            screen = DefaultScreen(data->display);
gabomdq@9167
   679
        } else if (snum == DefaultScreen(data->display)) {
gabomdq@9167
   680
            screen = 0;
gabomdq@9167
   681
        } else {
gabomdq@9167
   682
            screen = snum;
gabomdq@9167
   683
        }
gabomdq@9167
   684
slouken@6548
   685
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   686
        if (xinerama) {
slouken@6548
   687
            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
slouken@6548
   688
                continue;
slouken@6548
   689
            }
slouken@6548
   690
        } else {
slouken@6548
   691
            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   692
                continue;
slouken@6548
   693
            }
slouken@6548
   694
        }
slouken@6548
   695
#else
slouken@6548
   696
        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
slouken@6548
   697
            continue;
slouken@6548
   698
        }
slouken@6548
   699
#endif
slouken@6548
   700
slouken@6548
   701
        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
slouken@6548
   702
        if (!displaydata) {
slouken@6548
   703
            continue;
slouken@6548
   704
        }
slouken@6796
   705
        display_name[0] = '\0';
slouken@6548
   706
slouken@6548
   707
        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
slouken@6548
   708
        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
slouken@6548
   709
            /* We don't support palettized modes now */
slouken@6548
   710
            SDL_free(displaydata);
slouken@6548
   711
            continue;
slouken@6548
   712
        }
slouken@6548
   713
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   714
        if (xinerama) {
slouken@6548
   715
            mode.w = xinerama[screen].width;
slouken@6548
   716
            mode.h = xinerama[screen].height;
slouken@6548
   717
        } else {
slouken@6548
   718
            mode.w = DisplayWidth(data->display, screen);
slouken@6548
   719
            mode.h = DisplayHeight(data->display, screen);
slouken@6548
   720
        }
slouken@6548
   721
#else
slouken@6548
   722
        mode.w = DisplayWidth(data->display, screen);
slouken@6548
   723
        mode.h = DisplayHeight(data->display, screen);
slouken@6548
   724
#endif
slouken@6548
   725
        mode.refresh_rate = 0;
slouken@6548
   726
slouken@6548
   727
        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
slouken@6548
   728
        if (!modedata) {
slouken@6548
   729
            SDL_free(displaydata);
slouken@6548
   730
            continue;
slouken@6548
   731
        }
slouken@6548
   732
        mode.driverdata = modedata;
slouken@6548
   733
slouken@6548
   734
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   735
        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
slouken@6548
   736
         * there's only one screen available. So we force the screen number to zero and
slouken@6548
   737
         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
slouken@6548
   738
         */
slouken@6548
   739
        if (use_xinerama) {
slouken@6548
   740
            displaydata->screen = 0;
slouken@6548
   741
            displaydata->use_xinerama = use_xinerama;
slouken@6548
   742
            displaydata->xinerama_info = xinerama[screen];
slouken@6548
   743
            displaydata->xinerama_screen = screen;
slouken@6548
   744
        }
slouken@6548
   745
        else displaydata->screen = screen;
slouken@6548
   746
#else
slouken@6548
   747
        displaydata->screen = screen;
slouken@6548
   748
#endif
slouken@6548
   749
        displaydata->visual = vinfo.visual;
slouken@6548
   750
        displaydata->depth = vinfo.depth;
slouken@6548
   751
icculus@10780
   752
        /* We use the displaydata screen index here so that this works
icculus@10780
   753
           for both the Xinerama case, where we get the overall DPI,
icculus@10780
   754
           and the regular X11 screen info case. */
alfred@9814
   755
        displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f /
alfred@9814
   756
            DisplayWidthMM(data->display, displaydata->screen);
alfred@9814
   757
        displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f /
alfred@9814
   758
            DisplayHeightMM(data->display, displaydata->screen);
alfred@9814
   759
        displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen),
alfred@9814
   760
                                                   DisplayHeight(data->display, displaydata->screen),
alfred@9814
   761
                                                   (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f,
alfred@9814
   762
                                                   (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f);
alfred@9814
   763
slouken@6548
   764
        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
icculus@7827
   765
        pixmapFormats = X11_XListPixmapFormats(data->display, &n);
slouken@6548
   766
        if (pixmapFormats) {
slouken@6548
   767
            for (i = 0; i < n; ++i) {
slouken@6548
   768
                if (pixmapFormats[i].depth == displaydata->depth) {
slouken@6548
   769
                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
slouken@6548
   770
                    break;
slouken@6548
   771
                }
slouken@6548
   772
            }
icculus@7827
   773
            X11_XFree(pixmapFormats);
slouken@6548
   774
        }
slouken@6548
   775
slouken@6548
   776
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6548
   777
        if (use_xinerama) {
slouken@6548
   778
            displaydata->x = xinerama[screen].x_org;
slouken@6548
   779
            displaydata->y = xinerama[screen].y_org;
slouken@6548
   780
        }
slouken@6548
   781
        else
slouken@6548
   782
#endif
slouken@6548
   783
        {
slouken@6548
   784
            displaydata->x = 0;
slouken@6548
   785
            displaydata->y = 0;
slouken@6548
   786
        }
slouken@6548
   787
slouken@6548
   788
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@6548
   789
        if (!displaydata->use_xrandr &&
slouken@6548
   790
#if SDL_VIDEO_DRIVER_X11_XINERAMA
slouken@6564
   791
            /* XVidMode only works on the screen at the origin */
slouken@6564
   792
            (!displaydata->use_xinerama ||
slouken@6564
   793
             (displaydata->x == 0 && displaydata->y == 0)) &&
slouken@6548
   794
#endif
slouken@6548
   795
            use_vidmode) {
slouken@6548
   796
            displaydata->use_vidmode = use_vidmode;
slouken@6565
   797
            if (displaydata->use_xinerama) {
slouken@6565
   798
                displaydata->vidmode_screen = 0;
slouken@6565
   799
            } else {
slouken@6565
   800
                displaydata->vidmode_screen = screen;
slouken@6565
   801
            }
slouken@6565
   802
            XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
slouken@6548
   803
        }
slouken@6548
   804
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
slouken@6548
   805
slouken@6548
   806
        SDL_zero(display);
slouken@6796
   807
        if (*display_name) {
slouken@6796
   808
            display.name = display_name;
slouken@6796
   809
        }
slouken@6548
   810
        display.desktop_mode = mode;
slouken@6548
   811
        display.current_mode = mode;
slouken@6548
   812
        display.driverdata = displaydata;
slouken@6548
   813
        SDL_AddVideoDisplay(&display);
slouken@6548
   814
    }
slouken@6548
   815
slouken@6548
   816
#if SDL_VIDEO_DRIVER_X11_XINERAMA
icculus@7827
   817
    if (xinerama) X11_XFree(xinerama);
slouken@6548
   818
#endif
slouken@6548
   819
slouken@6548
   820
    if (_this->num_displays == 0) {
icculus@7037
   821
        return SDL_SetError("No available displays");
slouken@6548
   822
    }
slouken@6548
   823
    return 0;
slouken@2873
   824
}
slouken@2873
   825
slouken@1950
   826
void
slouken@3500
   827
X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
slouken@1950
   828
{
slouken@2870
   829
    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
slouken@3500
   830
    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
slouken@5408
   831
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
slouken@2873
   832
    int nmodes;
slouken@5408
   833
    XF86VidModeModeInfo ** modes;
slouken@2873
   834
#endif
slouken@1950
   835
    SDL_DisplayMode mode;
slouken@2870
   836
slouken@2873
   837
    /* Unfortunately X11 requires the window to be created with the correct
slouken@2873
   838
     * visual and depth ahead of time, but the SDL API allows you to create
slouken@2873
   839
     * a window before setting the fullscreen display mode.  This means that
slouken@2873
   840
     * we have to use the same format for all windows and all display modes.
slouken@2873
   841
     * (or support recreating the window with a new visual behind the scenes)
slouken@2873
   842
     */
slouken@3500
   843
    mode.format = sdl_display->current_mode.format;
slouken@2873
   844
    mode.driverdata = NULL;
slouken@2873
   845
slouken@2873
   846
#if SDL_VIDEO_DRIVER_X11_XINERAMA
gabomdq@6331
   847
    if (data->use_xinerama) {
brandon@11344
   848
        int screen_w;
brandon@11344
   849
        int screen_h;
brandon@11344
   850
brandon@11344
   851
        screen_w = DisplayWidth(display, data->screen);
brandon@11344
   852
        screen_h = DisplayHeight(display, data->screen);
brandon@11344
   853
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: */