cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11modes.c (29904B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#if SDL_VIDEO_DRIVER_X11
     24
     25#include "SDL_hints.h"
     26#include "SDL_x11video.h"
     27#include "edid.h"
     28
     29/* #define X11MODES_DEBUG */
     30
     31/* I'm becoming more and more convinced that the application should never
     32 * use XRandR, and it's the window manager's responsibility to track and
     33 * manage display modes for fullscreen windows.  Right now XRandR is completely
     34 * broken with respect to window manager behavior on every window manager that
     35 * I can find.  For example, on Unity 3D if you show a fullscreen window while
     36 * the resolution is changing (within ~250 ms) your window will retain the
     37 * fullscreen state hint but be decorated and windowed.
     38 *
     39 * However, many people swear by it, so let them swear at it. :)
     40*/
     41/* #define XRANDR_DISABLED_BY_DEFAULT */
     42
     43
     44static int
     45get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
     46{
     47    const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
     48    int depth;
     49
     50    /* Look for an exact visual, if requested */
     51    if (visual_id) {
     52        XVisualInfo *vi, template;
     53        int nvis;
     54
     55        SDL_zero(template);
     56        template.visualid = SDL_strtol(visual_id, NULL, 0);
     57        vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis);
     58        if (vi) {
     59            *vinfo = *vi;
     60            X11_XFree(vi);
     61            return 0;
     62        }
     63    }
     64
     65    depth = DefaultDepth(display, screen);
     66    if ((X11_UseDirectColorVisuals() &&
     67         X11_XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
     68        X11_XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
     69        X11_XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
     70        X11_XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
     71        return 0;
     72    }
     73    return -1;
     74}
     75
     76int
     77X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
     78{
     79    XVisualInfo *vi;
     80    int nvis;
     81
     82    vinfo->visualid = X11_XVisualIDFromVisual(visual);
     83    vi = X11_XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
     84    if (vi) {
     85        *vinfo = *vi;
     86        X11_XFree(vi);
     87        return 0;
     88    }
     89    return -1;
     90}
     91
     92Uint32
     93X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
     94{
     95    if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
     96        int bpp;
     97        Uint32 Rmask, Gmask, Bmask, Amask;
     98
     99        Rmask = vinfo->visual->red_mask;
    100        Gmask = vinfo->visual->green_mask;
    101        Bmask = vinfo->visual->blue_mask;
    102        if (vinfo->depth == 32) {
    103            Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
    104        } else {
    105            Amask = 0;
    106        }
    107
    108        bpp = vinfo->depth;
    109        if (bpp == 24) {
    110            int i, n;
    111            XPixmapFormatValues *p = X11_XListPixmapFormats(display, &n);
    112            if (p) {
    113                for (i = 0; i < n; ++i) {
    114                    if (p[i].depth == 24) {
    115                        bpp = p[i].bits_per_pixel;
    116                        break;
    117                    }
    118                }
    119                X11_XFree(p);
    120            }
    121        }
    122
    123        return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
    124    }
    125
    126    if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
    127        switch (vinfo->depth) {
    128        case 8:
    129            return SDL_PIXELTYPE_INDEX8;
    130        case 4:
    131            if (BitmapBitOrder(display) == LSBFirst) {
    132                return SDL_PIXELFORMAT_INDEX4LSB;
    133            } else {
    134                return SDL_PIXELFORMAT_INDEX4MSB;
    135            }
    136            break;
    137        case 1:
    138            if (BitmapBitOrder(display) == LSBFirst) {
    139                return SDL_PIXELFORMAT_INDEX1LSB;
    140            } else {
    141                return SDL_PIXELFORMAT_INDEX1MSB;
    142            }
    143            break;
    144        }
    145    }
    146
    147    return SDL_PIXELFORMAT_UNKNOWN;
    148}
    149
    150/* Global for the error handler */
    151int vm_event, vm_error = -1;
    152
    153#if SDL_VIDEO_DRIVER_X11_XINERAMA
    154static SDL_bool
    155CheckXinerama(Display * display, int *major, int *minor)
    156{
    157    int event_base = 0;
    158    int error_base = 0;
    159    const char *env;
    160
    161    /* Default the extension not available */
    162    *major = *minor = 0;
    163
    164    /* Allow environment override */
    165    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA);
    166    if (env && !SDL_atoi(env)) {
    167#ifdef X11MODES_DEBUG
    168        printf("Xinerama disabled due to hint\n");
    169#endif
    170        return SDL_FALSE;
    171    }
    172
    173    if (!SDL_X11_HAVE_XINERAMA) {
    174#ifdef X11MODES_DEBUG
    175        printf("Xinerama support not available\n");
    176#endif
    177        return SDL_FALSE;
    178    }
    179
    180    /* Query the extension version */
    181    if (!X11_XineramaQueryExtension(display, &event_base, &error_base) ||
    182        !X11_XineramaQueryVersion(display, major, minor) ||
    183        !X11_XineramaIsActive(display)) {
    184#ifdef X11MODES_DEBUG
    185        printf("Xinerama not active on the display\n");
    186#endif
    187        return SDL_FALSE;
    188    }
    189#ifdef X11MODES_DEBUG
    190    printf("Xinerama available at version %d.%d!\n", *major, *minor);
    191#endif
    192    return SDL_TRUE;
    193}
    194#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
    195
    196#if SDL_VIDEO_DRIVER_X11_XRANDR
    197static SDL_bool
    198CheckXRandR(Display * display, int *major, int *minor)
    199{
    200    const char *env;
    201
    202    /* Default the extension not available */
    203    *major = *minor = 0;
    204
    205    /* Allow environment override */
    206    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR);
    207#ifdef XRANDR_DISABLED_BY_DEFAULT
    208    if (!env || !SDL_atoi(env)) {
    209#ifdef X11MODES_DEBUG
    210        printf("XRandR disabled by default due to window manager issues\n");
    211#endif
    212        return SDL_FALSE;
    213    }
    214#else
    215    if (env && !SDL_atoi(env)) {
    216#ifdef X11MODES_DEBUG
    217        printf("XRandR disabled due to hint\n");
    218#endif
    219        return SDL_FALSE;
    220    }
    221#endif /* XRANDR_ENABLED_BY_DEFAULT */
    222
    223    if (!SDL_X11_HAVE_XRANDR) {
    224#ifdef X11MODES_DEBUG
    225        printf("XRandR support not available\n");
    226#endif
    227        return SDL_FALSE;
    228    }
    229
    230    /* Query the extension version */
    231    if (!X11_XRRQueryVersion(display, major, minor)) {
    232#ifdef X11MODES_DEBUG
    233        printf("XRandR not active on the display\n");
    234#endif
    235        return SDL_FALSE;
    236    }
    237#ifdef X11MODES_DEBUG
    238    printf("XRandR available at version %d.%d!\n", *major, *minor);
    239#endif
    240    return SDL_TRUE;
    241}
    242
    243#define XRANDR_ROTATION_LEFT    (1 << 1)
    244#define XRANDR_ROTATION_RIGHT   (1 << 3)
    245
    246static int
    247CalculateXRandRRefreshRate(const XRRModeInfo *info)
    248{
    249    return (info->hTotal
    250            && info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0;
    251}
    252
    253static SDL_bool
    254SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
    255                  RRMode modeID, SDL_DisplayMode *mode)
    256{
    257    int i;
    258    for (i = 0; i < res->nmode; ++i) {
    259        if (res->modes[i].id == modeID) {
    260            XRRCrtcInfo *crtc;
    261            Rotation rotation = 0;
    262            const XRRModeInfo *info = &res->modes[i];
    263
    264            crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
    265            if (crtc) {
    266                rotation = crtc->rotation;
    267                X11_XRRFreeCrtcInfo(crtc);
    268            }
    269
    270            if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
    271                mode->w = info->height;
    272                mode->h = info->width;
    273            } else {
    274                mode->w = info->width;
    275                mode->h = info->height;
    276            }
    277            mode->refresh_rate = CalculateXRandRRefreshRate(info);
    278            ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
    279#ifdef X11MODES_DEBUG
    280            printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
    281#endif
    282            return SDL_TRUE;
    283        }
    284    }
    285    return SDL_FALSE;
    286}
    287#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
    288
    289#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    290static SDL_bool
    291CheckVidMode(Display * display, int *major, int *minor)
    292{
    293    const char *env;
    294
    295    /* Default the extension not available */
    296    *major = *minor = 0;
    297
    298    /* Allow environment override */
    299    env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
    300    if (env && !SDL_atoi(env)) {
    301#ifdef X11MODES_DEBUG
    302        printf("XVidMode disabled due to hint\n");
    303#endif
    304        return SDL_FALSE;
    305    }
    306
    307    if (!SDL_X11_HAVE_XVIDMODE) {
    308#ifdef X11MODES_DEBUG
    309        printf("XVidMode support not available\n");
    310#endif
    311        return SDL_FALSE;
    312    }
    313
    314    /* Query the extension version */
    315    vm_error = -1;
    316    if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
    317        || !X11_XF86VidModeQueryVersion(display, major, minor)) {
    318#ifdef X11MODES_DEBUG
    319        printf("XVidMode not active on the display\n");
    320#endif
    321        return SDL_FALSE;
    322    }
    323#ifdef X11MODES_DEBUG
    324    printf("XVidMode available at version %d.%d!\n", *major, *minor);
    325#endif
    326    return SDL_TRUE;
    327}
    328
    329static
    330Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
    331                                       XF86VidModeModeInfo* info)
    332{
    333    Bool retval;
    334    int dotclock;
    335    XF86VidModeModeLine l;
    336    SDL_zerop(info);
    337    SDL_zero(l);
    338    retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
    339    info->dotclock = dotclock;
    340    info->hdisplay = l.hdisplay;
    341    info->hsyncstart = l.hsyncstart;
    342    info->hsyncend = l.hsyncend;
    343    info->htotal = l.htotal;
    344    info->hskew = l.hskew;
    345    info->vdisplay = l.vdisplay;
    346    info->vsyncstart = l.vsyncstart;
    347    info->vsyncend = l.vsyncend;
    348    info->vtotal = l.vtotal;
    349    info->flags = l.flags;
    350    info->privsize = l.privsize;
    351    info->private = l.private;
    352    return retval;
    353}
    354
    355static int
    356CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
    357{
    358    return (info->htotal
    359            && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
    360                                                         info->vtotal)) : 0;
    361}
    362
    363SDL_bool
    364SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
    365{
    366    mode->w = info->hdisplay;
    367    mode->h = info->vdisplay;
    368    mode->refresh_rate = CalculateXVidModeRefreshRate(info);
    369    ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
    370    return SDL_TRUE;
    371}
    372#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
    373
    374int
    375X11_InitModes(_THIS)
    376{
    377    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    378    int snum, screen, screencount;
    379#if SDL_VIDEO_DRIVER_X11_XINERAMA
    380    int xinerama_major, xinerama_minor;
    381    int use_xinerama = 0;
    382    XineramaScreenInfo *xinerama = NULL;
    383#endif
    384#if SDL_VIDEO_DRIVER_X11_XRANDR
    385    int xrandr_major, xrandr_minor;
    386    int use_xrandr = 0;
    387    XRRScreenResources *res = NULL;
    388#endif
    389#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    390    int vm_major, vm_minor;
    391    int use_vidmode = 0;
    392#endif
    393
    394#if SDL_VIDEO_DRIVER_X11_XINERAMA
    395    /* Query Xinerama extention
    396     * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
    397     *       or newer of the Nvidia binary drivers
    398     */
    399    if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
    400        xinerama = X11_XineramaQueryScreens(data->display, &screencount);
    401        if (xinerama) {
    402            use_xinerama = xinerama_major * 100 + xinerama_minor;
    403        }
    404    }
    405    if (!xinerama) {
    406        screencount = ScreenCount(data->display);
    407    }
    408#else
    409    screencount = ScreenCount(data->display);
    410#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
    411
    412#if SDL_VIDEO_DRIVER_X11_XRANDR
    413    /* require at least XRandR v1.2 */
    414    if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
    415        (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
    416        use_xrandr = xrandr_major * 100 + xrandr_minor;
    417    }
    418#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
    419
    420#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    421    if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
    422        use_vidmode = vm_major * 100 + vm_minor;
    423    }
    424#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
    425
    426    for (snum = 0; snum < screencount; ++snum) {
    427        XVisualInfo vinfo;
    428        SDL_VideoDisplay display;
    429        SDL_DisplayData *displaydata;
    430        SDL_DisplayMode mode;
    431        SDL_DisplayModeData *modedata;
    432        XPixmapFormatValues *pixmapFormats;
    433        char display_name[128];
    434        int i, n;
    435
    436        /* Re-order screens to always put default screen first */
    437        if (snum == 0) {
    438            screen = DefaultScreen(data->display);
    439        } else if (snum == DefaultScreen(data->display)) {
    440            screen = 0;
    441        } else {
    442            screen = snum;
    443        }
    444
    445#if SDL_VIDEO_DRIVER_X11_XINERAMA
    446        if (xinerama) {
    447            if (get_visualinfo(data->display, 0, &vinfo) < 0) {
    448                continue;
    449            }
    450        } else {
    451            if (get_visualinfo(data->display, screen, &vinfo) < 0) {
    452                continue;
    453            }
    454        }
    455#else
    456        if (get_visualinfo(data->display, screen, &vinfo) < 0) {
    457            continue;
    458        }
    459#endif
    460
    461        displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
    462        if (!displaydata) {
    463            continue;
    464        }
    465        display_name[0] = '\0';
    466
    467        mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
    468        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
    469            /* We don't support palettized modes now */
    470            SDL_free(displaydata);
    471            continue;
    472        }
    473#if SDL_VIDEO_DRIVER_X11_XINERAMA
    474        if (xinerama) {
    475            mode.w = xinerama[screen].width;
    476            mode.h = xinerama[screen].height;
    477        } else {
    478            mode.w = DisplayWidth(data->display, screen);
    479            mode.h = DisplayHeight(data->display, screen);
    480        }
    481#else
    482        mode.w = DisplayWidth(data->display, screen);
    483        mode.h = DisplayHeight(data->display, screen);
    484#endif
    485        mode.refresh_rate = 0;
    486
    487        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    488        if (!modedata) {
    489            SDL_free(displaydata);
    490            continue;
    491        }
    492        mode.driverdata = modedata;
    493
    494#if SDL_VIDEO_DRIVER_X11_XINERAMA
    495        /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
    496         * there's only one screen available. So we force the screen number to zero and
    497         * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
    498         */
    499        if (use_xinerama) {
    500            displaydata->screen = 0;
    501            displaydata->use_xinerama = use_xinerama;
    502            displaydata->xinerama_info = xinerama[screen];
    503            displaydata->xinerama_screen = screen;
    504        }
    505        else displaydata->screen = screen;
    506#else
    507        displaydata->screen = screen;
    508#endif
    509        displaydata->visual = vinfo.visual;
    510        displaydata->depth = vinfo.depth;
    511
    512        displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
    513        pixmapFormats = X11_XListPixmapFormats(data->display, &n);
    514        if (pixmapFormats) {
    515            for (i = 0; i < n; ++i) {
    516                if (pixmapFormats[i].depth == displaydata->depth) {
    517                    displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
    518                    break;
    519                }
    520            }
    521            X11_XFree(pixmapFormats);
    522        }
    523
    524#if SDL_VIDEO_DRIVER_X11_XINERAMA
    525        if (use_xinerama) {
    526            displaydata->x = xinerama[screen].x_org;
    527            displaydata->y = xinerama[screen].y_org;
    528        }
    529        else
    530#endif
    531        {
    532            displaydata->x = 0;
    533            displaydata->y = 0;
    534        }
    535
    536#if SDL_VIDEO_DRIVER_X11_XRANDR
    537        if (use_xrandr) {
    538            res = X11_XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
    539        }
    540        if (res) {
    541            XRROutputInfo *output_info;
    542            XRRCrtcInfo *crtc;
    543            int output;
    544            Atom EDID = X11_XInternAtom(data->display, "EDID", False);
    545            Atom *props;
    546            int nprop;
    547            unsigned long width_mm;
    548            unsigned long height_mm;
    549            int inches = 0;
    550
    551            for (output = 0; output < res->noutput; output++) {
    552                output_info = X11_XRRGetOutputInfo(data->display, res, res->outputs[output]);
    553                if (!output_info || !output_info->crtc ||
    554                    output_info->connection == RR_Disconnected) {
    555                    X11_XRRFreeOutputInfo(output_info);
    556                    continue;
    557                }
    558
    559                /* Is this the output that corresponds to the current screen?
    560                   We're checking the crtc position, but that may not be a valid test
    561                   in all cases.  Anybody want to give this some love?
    562                 */
    563                crtc = X11_XRRGetCrtcInfo(data->display, res, output_info->crtc);
    564                if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y ||
    565                    crtc->width != mode.w || crtc->height != mode.h) {
    566                    X11_XRRFreeOutputInfo(output_info);
    567                    X11_XRRFreeCrtcInfo(crtc);
    568                    continue;
    569                }
    570
    571                displaydata->use_xrandr = use_xrandr;
    572                displaydata->xrandr_output = res->outputs[output];
    573                SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
    574
    575                /* Get the name of this display */
    576                width_mm = output_info->mm_width;
    577                height_mm = output_info->mm_height;
    578                inches = (int)((sqrt(width_mm * width_mm +
    579                                     height_mm * height_mm) / 25.4f) + 0.5f);
    580                SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
    581
    582                /* See if we can get the EDID data for the real monitor name */
    583                props = X11_XRRListOutputProperties(data->display, res->outputs[output], &nprop);
    584                for (i = 0; i < nprop; ++i) {
    585                    unsigned char *prop;
    586                    int actual_format;
    587                    unsigned long nitems, bytes_after;
    588                    Atom actual_type;
    589
    590                    if (props[i] == EDID) {
    591                        if (X11_XRRGetOutputProperty(data->display,
    592                                                 res->outputs[output], props[i],
    593                                                 0, 100, False, False,
    594                                                 AnyPropertyType,
    595                                                 &actual_type, &actual_format,
    596                                                 &nitems, &bytes_after, &prop) == Success ) {
    597                            MonitorInfo *info = decode_edid(prop);
    598                            if (info) {
    599    #ifdef X11MODES_DEBUG
    600                                printf("Found EDID data for %s\n", output_info->name);
    601                                dump_monitor_info(info);
    602    #endif
    603                                SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name));
    604                                free(info);
    605                            }
    606                            X11_XFree(prop);
    607                        }
    608                        break;
    609                    }
    610                }
    611                if (props) {
    612                    X11_XFree(props);
    613                }
    614
    615                if (*display_name && inches) {
    616                    size_t len = SDL_strlen(display_name);
    617                    SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches);
    618                }
    619#ifdef X11MODES_DEBUG
    620                printf("Display name: %s\n", display_name);
    621#endif
    622
    623                X11_XRRFreeOutputInfo(output_info);
    624                X11_XRRFreeCrtcInfo(crtc);
    625                break;
    626            }
    627#ifdef X11MODES_DEBUG
    628            if (output == res->noutput) {
    629                printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
    630            }
    631#endif
    632            X11_XRRFreeScreenResources(res);
    633        }
    634#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
    635
    636#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    637        if (!displaydata->use_xrandr &&
    638#if SDL_VIDEO_DRIVER_X11_XINERAMA
    639            /* XVidMode only works on the screen at the origin */
    640            (!displaydata->use_xinerama ||
    641             (displaydata->x == 0 && displaydata->y == 0)) &&
    642#endif
    643            use_vidmode) {
    644            displaydata->use_vidmode = use_vidmode;
    645            if (displaydata->use_xinerama) {
    646                displaydata->vidmode_screen = 0;
    647            } else {
    648                displaydata->vidmode_screen = screen;
    649            }
    650            XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
    651        }
    652#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
    653
    654        SDL_zero(display);
    655        if (*display_name) {
    656            display.name = display_name;
    657        }
    658        display.desktop_mode = mode;
    659        display.current_mode = mode;
    660        display.driverdata = displaydata;
    661        SDL_AddVideoDisplay(&display);
    662    }
    663
    664#if SDL_VIDEO_DRIVER_X11_XINERAMA
    665    if (xinerama) X11_XFree(xinerama);
    666#endif
    667
    668    if (_this->num_displays == 0) {
    669        return SDL_SetError("No available displays");
    670    }
    671    return 0;
    672}
    673
    674void
    675X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
    676{
    677    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    678    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
    679#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    680    int nmodes;
    681    XF86VidModeModeInfo ** modes;
    682#endif
    683    int screen_w;
    684    int screen_h;
    685    SDL_DisplayMode mode;
    686
    687    /* Unfortunately X11 requires the window to be created with the correct
    688     * visual and depth ahead of time, but the SDL API allows you to create
    689     * a window before setting the fullscreen display mode.  This means that
    690     * we have to use the same format for all windows and all display modes.
    691     * (or support recreating the window with a new visual behind the scenes)
    692     */
    693    mode.format = sdl_display->current_mode.format;
    694    mode.driverdata = NULL;
    695
    696    screen_w = DisplayWidth(display, data->screen);
    697    screen_h = DisplayHeight(display, data->screen);
    698
    699#if SDL_VIDEO_DRIVER_X11_XINERAMA
    700    if (data->use_xinerama) {
    701        if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
    702           (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
    703            SDL_DisplayModeData *modedata;
    704            /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
    705             * if we're using vidmode.
    706             */
    707            mode.w = screen_w;
    708            mode.h = screen_h;
    709            mode.refresh_rate = 0;
    710            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    711            if (modedata) {
    712                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
    713            }
    714            mode.driverdata = modedata;
    715            SDL_AddDisplayMode(sdl_display, &mode);
    716        }
    717        else if (!data->use_xrandr)
    718        {
    719            SDL_DisplayModeData *modedata;
    720            /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
    721            mode.w = data->xinerama_info.width;
    722            mode.h = data->xinerama_info.height;
    723            mode.refresh_rate = 0;
    724            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    725            if (modedata) {
    726                *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
    727            }
    728            mode.driverdata = modedata;
    729            SDL_AddDisplayMode(sdl_display, &mode);
    730        }
    731
    732    }
    733#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
    734
    735#if SDL_VIDEO_DRIVER_X11_XRANDR
    736    if (data->use_xrandr) {
    737        XRRScreenResources *res;
    738
    739        res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
    740        if (res) {
    741            SDL_DisplayModeData *modedata;
    742            XRROutputInfo *output_info;
    743            int i;
    744
    745            output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
    746            if (output_info && output_info->connection != RR_Disconnected) {
    747                for (i = 0; i < output_info->nmode; ++i) {
    748                    modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    749                    if (!modedata) {
    750                        continue;
    751                    }
    752                    mode.driverdata = modedata;
    753
    754                    if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
    755                        SDL_AddDisplayMode(sdl_display, &mode);
    756                    } else {
    757                        SDL_free(modedata);
    758                    }
    759                }
    760            }
    761            X11_XRRFreeOutputInfo(output_info);
    762            X11_XRRFreeScreenResources(res);
    763        }
    764        return;
    765    }
    766#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
    767
    768#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    769    if (data->use_vidmode &&
    770        X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
    771        int i;
    772        SDL_DisplayModeData *modedata;
    773
    774#ifdef X11MODES_DEBUG
    775        printf("VidMode modes: (unsorted)\n");
    776        for (i = 0; i < nmodes; ++i) {
    777            printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
    778                   modes[i]->hdisplay, modes[i]->vdisplay,
    779                   CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
    780        }
    781#endif
    782        for (i = 0; i < nmodes; ++i) {
    783            modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    784            if (!modedata) {
    785                continue;
    786            }
    787            mode.driverdata = modedata;
    788
    789            if (SetXVidModeModeInfo(modes[i], &mode)) {
    790                SDL_AddDisplayMode(sdl_display, &mode);
    791            } else {
    792                SDL_free(modedata);
    793            }
    794        }
    795        X11_XFree(modes);
    796        return;
    797    }
    798#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
    799
    800    if (!data->use_xrandr && !data->use_vidmode) {
    801        SDL_DisplayModeData *modedata;
    802        /* Add the desktop mode */
    803        mode = sdl_display->desktop_mode;
    804        modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
    805        if (modedata) {
    806            *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
    807        }
    808        mode.driverdata = modedata;
    809        SDL_AddDisplayMode(sdl_display, &mode);
    810    }
    811}
    812
    813int
    814X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
    815{
    816    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    817    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
    818    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
    819
    820#if SDL_VIDEO_DRIVER_X11_XRANDR
    821    if (data->use_xrandr) {
    822        XRRScreenResources *res;
    823        XRROutputInfo *output_info;
    824        XRRCrtcInfo *crtc;
    825        Status status;
    826
    827        res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
    828        if (!res) {
    829            return SDL_SetError("Couldn't get XRandR screen resources");
    830        }
    831
    832        output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
    833        if (!output_info || output_info->connection == RR_Disconnected) {
    834            X11_XRRFreeScreenResources(res);
    835            return SDL_SetError("Couldn't get XRandR output info");
    836        }
    837
    838        crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
    839        if (!crtc) {
    840            X11_XRRFreeOutputInfo(output_info);
    841            X11_XRRFreeScreenResources(res);
    842            return SDL_SetError("Couldn't get XRandR crtc info");
    843        }
    844
    845        status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
    846          crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
    847          &data->xrandr_output, 1);
    848
    849        X11_XRRFreeCrtcInfo(crtc);
    850        X11_XRRFreeOutputInfo(output_info);
    851        X11_XRRFreeScreenResources(res);
    852
    853        if (status != Success) {
    854            return SDL_SetError("X11_XRRSetCrtcConfig failed");
    855        }
    856    }
    857#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
    858
    859#if SDL_VIDEO_DRIVER_X11_XVIDMODE
    860    if (data->use_vidmode) {
    861        X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
    862    }
    863#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
    864
    865    return 0;
    866}
    867
    868void
    869X11_QuitModes(_THIS)
    870{
    871}
    872
    873int
    874X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
    875{
    876    SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
    877
    878    rect->x = data->x;
    879    rect->y = data->y;
    880    rect->w = sdl_display->current_mode.w;
    881    rect->h = sdl_display->current_mode.h;
    882
    883#if SDL_VIDEO_DRIVER_X11_XINERAMA
    884    /* Get the real current bounds of the display */
    885    if (data->use_xinerama) {
    886        Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    887        int screencount;
    888        XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
    889        if (xinerama) {
    890            rect->x = xinerama[data->xinerama_screen].x_org;
    891            rect->y = xinerama[data->xinerama_screen].y_org;
    892            X11_XFree(xinerama);
    893        }
    894    }
    895#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
    896    return 0;
    897}
    898
    899#endif /* SDL_VIDEO_DRIVER_X11 */
    900
    901/* vi: set ts=4 sw=4 expandtab: */