xf86RandR12.c 61.1 KB
Newer Older
1
/*
2
 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
25 26 27 28
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
29 30 31 32 33
#endif

#include "xf86.h"
#include "os.h"
#include "globals.h"
34
#include "xf86Modes.h"
35 36 37 38
#include "xf86Priv.h"
#include "xf86DDC.h"
#include "mipointer.h"
#include "windowstr.h"
39
#include "inputstr.h"
40 41 42 43 44 45 46
#include <randrstr.h>
#include <X11/extensions/render.h>

#include "xf86Crtc.h"
#include "xf86RandR12.h"

typedef struct _xf86RandR12Info {
47 48 49 50 51 52 53 54 55 56
    int virtualX;
    int virtualY;
    int mmWidth;
    int mmHeight;
    int maxX;
    int maxY;
    int pointerX;
    int pointerY;
    Rotation rotation;          /* current mode */
    Rotation supported_rotations;       /* driver supported */
57 58 59 60 61 62 63

    /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends
     * (actually, any time that we switch back into our VT).
     *
     * See https://bugs.freedesktop.org/show_bug.cgi?id=21554
     */
    xf86EnterVTProc *orig_EnterVT;
64 65 66

    Bool                         panning;
    ConstrainCursorHarderProcPtr orig_ConstrainCursorHarder;
67 68 69
} XF86RandRInfoRec, *XF86RandRInfoPtr;

#ifdef RANDR_12_INTERFACE
70 71
static Bool xf86RandR12Init12(ScreenPtr pScreen);
static Bool xf86RandR12CreateScreenResources12(ScreenPtr pScreen);
72 73
#endif

74
static int xf86RandR12Generation;
75

76
static DevPrivateKeyRec xf86RandR12KeyRec;
77
static DevPrivateKey xf86RandR12Key;
78

79 80
#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \
    dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key))
81 82

static int
83
xf86RandR12ModeRefresh(DisplayModePtr mode)
84 85
{
    if (mode->VRefresh)
86
        return (int) (mode->VRefresh + 0.5);
87
    else
88
        return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
89 90
}

91
/* Adapt panning area; return TRUE if panning area was valid without adaption */
Matthias Hopf's avatar
Matthias Hopf committed
92
static int
93 94
xf86RandR13VerifyPanningArea(xf86CrtcPtr crtc, int screenWidth,
                             int screenHeight)
Matthias Hopf's avatar
Matthias Hopf committed
95
{
96 97
    int ret = TRUE;

Matthias Hopf's avatar
Matthias Hopf committed
98
    if (crtc->version < 2)
99
        return FALSE;
Matthias Hopf's avatar
Matthias Hopf committed
100

101
    if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) {
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
        /* Panning in X is disabled */
        if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2)
            /* Illegal configuration -> fail/disable */
            ret = FALSE;
        crtc->panningTotalArea.x1 = crtc->panningTotalArea.x2 = 0;
        crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0;
        crtc->panningBorder[0] = crtc->panningBorder[2] = 0;
    }
    else {
        /* Panning in X is enabled */
        if (crtc->panningTotalArea.x1 < 0) {
            /* Panning region outside screen -> move inside */
            crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1;
            crtc->panningTotalArea.x1 = 0;
            ret = FALSE;
        }
        if (crtc->panningTotalArea.x2 <
            crtc->panningTotalArea.x1 + crtc->mode.HDisplay) {
            /* Panning region smaller than displayed area -> crop to displayed area */
            crtc->panningTotalArea.x2 =
                crtc->panningTotalArea.x1 + crtc->mode.HDisplay;
            ret = FALSE;
        }
        if (crtc->panningTotalArea.x2 > screenWidth) {
            /* Panning region larger than screen -> move inside, then crop to screen */
            crtc->panningTotalArea.x1 -=
                crtc->panningTotalArea.x2 - screenWidth;
            crtc->panningTotalArea.x2 = screenWidth;
            ret = FALSE;
            if (crtc->panningTotalArea.x1 < 0)
                crtc->panningTotalArea.x1 = 0;
        }
        if (crtc->panningBorder[0] + crtc->panningBorder[2] >
            crtc->mode.HDisplay) {
            /* Borders too large -> set to 0 */
            crtc->panningBorder[0] = crtc->panningBorder[2] = 0;
            ret = FALSE;
        }
Matthias Hopf's avatar
Matthias Hopf committed
140 141
    }

142
    if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) {
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
        /* Panning in Y is disabled */
        if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2)
            /* Illegal configuration -> fail/disable */
            ret = FALSE;
        crtc->panningTotalArea.y1 = crtc->panningTotalArea.y2 = 0;
        crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0;
        crtc->panningBorder[1] = crtc->panningBorder[3] = 0;
    }
    else {
        /* Panning in Y is enabled */
        if (crtc->panningTotalArea.y1 < 0) {
            /* Panning region outside screen -> move inside */
            crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1;
            crtc->panningTotalArea.y1 = 0;
            ret = FALSE;
        }
        if (crtc->panningTotalArea.y2 <
            crtc->panningTotalArea.y1 + crtc->mode.VDisplay) {
            /* Panning region smaller than displayed area -> crop to displayed area */
            crtc->panningTotalArea.y2 =
                crtc->panningTotalArea.y1 + crtc->mode.VDisplay;
            ret = FALSE;
        }
        if (crtc->panningTotalArea.y2 > screenHeight) {
            /* Panning region larger than screen -> move inside, then crop to screen */
            crtc->panningTotalArea.y1 -=
                crtc->panningTotalArea.y2 - screenHeight;
            crtc->panningTotalArea.y2 = screenHeight;
            ret = FALSE;
            if (crtc->panningTotalArea.y1 < 0)
                crtc->panningTotalArea.y1 = 0;
        }
        if (crtc->panningBorder[1] + crtc->panningBorder[3] >
            crtc->mode.VDisplay) {
            /* Borders too large -> set to 0 */
            crtc->panningBorder[1] = crtc->panningBorder[3] = 0;
            ret = FALSE;
        }
Matthias Hopf's avatar
Matthias Hopf committed
181
    }
182 183

    return ret;
Matthias Hopf's avatar
Matthias Hopf committed
184 185
}

186 187 188 189 190 191 192 193 194 195 196
/*
 * The heart of the panning operation:
 *
 * Given a frame buffer position (fb_x, fb_y),
 * and a crtc position (crtc_x, crtc_y),
 * and a transform matrix which maps frame buffer to crtc,
 * compute a panning position (pan_x, pan_y) that
 * makes the resulting transform line those two up
 */

static void
197 198 199 200 201
xf86ComputeCrtcPan(Bool transform_in_use,
                   struct pixman_f_transform *m,
                   double screen_x, double screen_y,
                   double crtc_x, double crtc_y,
                   int old_pan_x, int old_pan_y, int *new_pan_x, int *new_pan_y)
202
{
203
    if (transform_in_use) {
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
        /*
         * Given the current transform, M, the current position
         * on the Screen, S, and the desired position on the CRTC,
         * C, compute a translation, T, such that:
         *
         * M T S = C
         *
         * where T is of the form
         *
         * | 1 0 dx |
         * | 0 1 dy |
         * | 0 0 1  |
         *
         * M T S =
         *   | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 |   | Cx F |
         *   | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F |
         *   | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 |   |  F   |
         *
         * R = M S
         *
         *   Cx F = M00 dx + M01 dy + R0
         *   Cy F = M10 dx + M11 dy + R1
         *      F = M20 dx + M21 dy + R2
         *
         * Zero out dx, then dy
         *
         * F (Cx M10 - Cy M00) =
         *          (M10 M01 - M00 M11) dy + M10 R0 - M00 R1
         * F (M10 - Cy M20) =
         *          (M10 M21 - M20 M11) dy + M10 R2 - M20 R1
         *
         * F (Cx M11 - Cy M01) =
         *          (M11 M00 - M01 M10) dx + M11 R0 - M01 R1
         * F (M11 - Cy M21) =
         *          (M11 M20 - M21 M10) dx + M11 R2 - M21 R1
         *
         * Make some temporaries
         *
         * T = | Cx M10 - Cy M00 |
         *     | Cx M11 - Cy M01 |
         *
         * U = | M10 M01 - M00 M11 |
         *     | M11 M00 - M01 M10 |
         *
         * Q = | M10 R0 - M00 R1 |
         *     | M11 R0 - M01 R1 |
         *
         * P = | M10 - Cy M20 |
         *     | M11 - Cy M21 |
         *
         * W = | M10 M21 - M20 M11 |
         *     | M11 M20 - M21 M10 |
         *
         * V = | M10 R2 - M20 R1 |
         *         | M11 R2 - M21 R1 |
         *
         * Rewrite:
         *
         * F T0 = U0 dy + Q0
         * F P0 = W0 dy + V0
         * F T1 = U1 dx + Q1
         * F P1 = W1 dx + V1
         *
         * Solve for F (two ways)
         *
         * F (W0 T0 - U0 P0)  = W0 Q0 - U0 V0
         *
         *     W0 Q0 - U0 V0
         * F = -------------
         *     W0 T0 - U0 P0
         *
         * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1
         *
         *     W1 Q1 - U1 V1
         * F = -------------
         *     W1 T1 - U1 P1
         *
         * We'll use which ever solution works (denominator != 0)
         *
         * Finally, solve for dx and dy:
         *
         * dx = (F T1 - Q1) / U1
         * dx = (F P1 - V1) / W1
         *
         * dy = (F T0 - Q0) / U0
         * dy = (F P0 - V0) / W0
         */
        double r[3];
        double q[2], u[2], t[2], v[2], w[2], p[2];
        double f;
        struct pict_f_vector d;
        int i;

        /* Get the un-normalized crtc coordinates again */
        for (i = 0; i < 3; i++)
            r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2];

        /* Combine values into temporaries */
        for (i = 0; i < 2; i++) {
            q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1];
            u[i] = m->m[1][i] * m->m[0][1 - i] - m->m[0][i] * m->m[1][1 - i];
            t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y;

            v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1];
            w[i] = m->m[1][i] * m->m[2][1 - i] - m->m[2][i] * m->m[1][1 - i];
            p[i] = m->m[1][i] - m->m[2][i] * crtc_y;
        }

        /* Find a way to compute f */
        f = 0;
        for (i = 0; i < 2; i++) {
            double a = w[i] * q[i] - u[i] * v[i];
            double b = w[i] * t[i] - u[i] * p[i];

            if (b != 0) {
                f = a / b;
                break;
            }
        }

        /* Solve for the resulting transform vector */
        for (i = 0; i < 2; i++) {
            if (u[i])
                d.v[1 - i] = (t[i] * f - q[i]) / u[i];
            else if (w[1])
                d.v[1 - i] = (p[i] * f - v[i]) / w[i];
            else
                d.v[1 - i] = 0;
        }
        *new_pan_x = old_pan_x - floor(d.v[0] + 0.5);
        *new_pan_y = old_pan_y - floor(d.v[1] + 0.5);
    }
    else {
        *new_pan_x = screen_x - crtc_x;
        *new_pan_y = screen_y - crtc_y;
339 340 341
    }
}

Matthias Hopf's avatar
Matthias Hopf committed
342
static void
343
xf86RandR13Pan(xf86CrtcPtr crtc, int x, int y)
Matthias Hopf's avatar
Matthias Hopf committed
344 345 346
{
    int newX, newY;
    int width, height;
347
    Bool panned = FALSE;
Matthias Hopf's avatar
Matthias Hopf committed
348 349

    if (crtc->version < 2)
350
        return;
Matthias Hopf's avatar
Matthias Hopf committed
351

352 353 354 355
    if (!crtc->enabled ||
        (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 &&
         crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1))
        return;
Matthias Hopf's avatar
Matthias Hopf committed
356

357 358 359
    newX = crtc->x;
    newY = crtc->y;
    width = crtc->mode.HDisplay;
Matthias Hopf's avatar
Matthias Hopf committed
360 361
    height = crtc->mode.VDisplay;

362
    if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 ||
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
         (x >= crtc->panningTrackingArea.x1 &&
          x < crtc->panningTrackingArea.x2)) &&
        (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 ||
         (y >= crtc->panningTrackingArea.y1 &&
          y < crtc->panningTrackingArea.y2))) {
        struct pict_f_vector c;

        /*
         * Pre-clip the mouse position to the panning area so that we don't
         * push the crtc outside. This doesn't deal with changes to the
         * panning values, only mouse position changes.
         */
        if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
            if (x < crtc->panningTotalArea.x1)
                x = crtc->panningTotalArea.x1;
            if (x >= crtc->panningTotalArea.x2)
                x = crtc->panningTotalArea.x2 - 1;
        }
        if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
            if (y < crtc->panningTotalArea.y1)
                y = crtc->panningTotalArea.y1;
            if (y >= crtc->panningTotalArea.y2)
                y = crtc->panningTotalArea.y2 - 1;
        }

        c.v[0] = x;
        c.v[1] = y;
        c.v[2] = 1.0;
        if (crtc->transform_in_use) {
            pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c);
        }
        else {
            c.v[0] -= crtc->x;
            c.v[1] -= crtc->y;
        }

        if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
            if (c.v[0] < crtc->panningBorder[0]) {
                c.v[0] = crtc->panningBorder[0];
                panned = TRUE;
            }
            if (c.v[0] >= width - crtc->panningBorder[2]) {
                c.v[0] = width - crtc->panningBorder[2] - 1;
                panned = TRUE;
            }
        }
        if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
            if (c.v[1] < crtc->panningBorder[1]) {
                c.v[1] = crtc->panningBorder[1];
                panned = TRUE;
            }
            if (c.v[1] >= height - crtc->panningBorder[3]) {
                c.v[1] = height - crtc->panningBorder[3] - 1;
                panned = TRUE;
            }
        }
        if (panned)
            xf86ComputeCrtcPan(crtc->transform_in_use,
                               &crtc->f_framebuffer_to_crtc,
                               x, y, c.v[0], c.v[1], newX, newY, &newX, &newY);
Matthias Hopf's avatar
Matthias Hopf committed
423
    }
424 425 426 427 428 429 430

    /*
     * Ensure that the crtc is within the panning region.
     *
     * XXX This computation only works when we do not have a transform
     * in use.
     */
431 432 433 434 435 436 437 438 439 440 441 442 443 444
    if (!crtc->transform_in_use) {
        /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */
        if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
            if (newX > crtc->panningTotalArea.x2 - width)
                newX = crtc->panningTotalArea.x2 - width;
            if (newX < crtc->panningTotalArea.x1)
                newX = crtc->panningTotalArea.x1;
        }
        if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
            if (newY > crtc->panningTotalArea.y2 - height)
                newY = crtc->panningTotalArea.y2 - height;
            if (newY < crtc->panningTotalArea.y1)
                newY = crtc->panningTotalArea.y1;
        }
445
    }
Matthias Hopf's avatar
Matthias Hopf committed
446
    if (newX != crtc->x || newY != crtc->y)
447
        xf86CrtcSetOrigin(crtc, newX, newY);
Matthias Hopf's avatar
Matthias Hopf committed
448 449
}

450
static Bool
451
xf86RandR12GetInfo(ScreenPtr pScreen, Rotation * rotations)
452
{
453
    RRScreenSizePtr pSize;
454
    ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
455 456 457
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
    DisplayModePtr mode;
    int maxX = 0, maxY = 0;
458 459 460

    *rotations = randrp->supported_rotations;

461 462 463
    if (randrp->virtualX == -1 || randrp->virtualY == -1) {
        randrp->virtualX = scrp->virtualX;
        randrp->virtualY = scrp->virtualY;
464 465 466
    }

    /* Re-probe the outputs for new monitors or modes */
467 468 469
    if (scrp->vtSema) {
        xf86ProbeOutputModes(scrp, 0, 0);
        xf86SetScrnInfoModes(scrp);
470
    }
471

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
    for (mode = scrp->modes;; mode = mode->next) {
        int refresh = xf86RandR12ModeRefresh(mode);

        if (randrp->maxX == 0 || randrp->maxY == 0) {
            if (maxX < mode->HDisplay)
                maxX = mode->HDisplay;
            if (maxY < mode->VDisplay)
                maxY = mode->VDisplay;
        }
        pSize = RRRegisterSize(pScreen,
                               mode->HDisplay, mode->VDisplay,
                               randrp->mmWidth, randrp->mmHeight);
        if (!pSize)
            return FALSE;
        RRRegisterRate(pScreen, pSize, refresh);

        if (xf86ModesEqual(mode, scrp->currentMode)) {
            RRSetCurrentConfig(pScreen, randrp->rotation, refresh, pSize);
        }
        if (mode->next == scrp->modes)
            break;
493 494
    }

495 496 497
    if (randrp->maxX == 0 || randrp->maxY == 0) {
        randrp->maxX = maxX;
        randrp->maxY = maxY;
498 499 500 501 502 503
    }

    return TRUE;
}

static Bool
504 505 506
xf86RandR12SetMode(ScreenPtr pScreen,
                   DisplayModePtr mode,
                   Bool useVirtual, int mmWidth, int mmHeight)
507
{
508
    ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
509 510 511 512 513 514 515 516
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
    int oldWidth = pScreen->width;
    int oldHeight = pScreen->height;
    int oldmmWidth = pScreen->mmWidth;
    int oldmmHeight = pScreen->mmHeight;
    WindowPtr pRoot = pScreen->root;
    DisplayModePtr currentMode = NULL;
    Bool ret = TRUE;
517 518

    if (pRoot)
519
        (*scrp->EnableDisableFBAccess) (scrp, FALSE);
520 521 522
    if (useVirtual) {
        scrp->virtualX = randrp->virtualX;
        scrp->virtualY = randrp->virtualY;
523
    }
524 525 526
    else {
        scrp->virtualX = mode->HDisplay;
        scrp->virtualY = mode->VDisplay;
527 528
    }

529 530 531 532 533 534
    if (randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
        /* If the screen is rotated 90 or 270 degrees, swap the sizes. */
        pScreen->width = scrp->virtualY;
        pScreen->height = scrp->virtualX;
        pScreen->mmWidth = mmHeight;
        pScreen->mmHeight = mmWidth;
535
    }
536 537 538 539 540
    else {
        pScreen->width = scrp->virtualX;
        pScreen->height = scrp->virtualY;
        pScreen->mmWidth = mmWidth;
        pScreen->mmHeight = mmHeight;
541 542 543 544 545 546 547 548 549 550 551
    }
    if (scrp->currentMode == mode) {
        /* Save current mode */
        currentMode = scrp->currentMode;
        /* Reset, just so we ensure the drivers SwitchMode is called */
        scrp->currentMode = NULL;
    }
    /*
     * We know that if the driver failed to SwitchMode to the rotated
     * version, then it should revert back to it's prior mode.
     */
552
    if (!xf86SwitchMode(pScreen, mode)) {
553
        ret = FALSE;
554 555 556 557
        scrp->virtualX = pScreen->width = oldWidth;
        scrp->virtualY = pScreen->height = oldHeight;
        pScreen->mmWidth = oldmmWidth;
        pScreen->mmHeight = oldmmHeight;
558 559 560 561 562 563 564 565 566 567 568
        scrp->currentMode = currentMode;
    }

    /*
     * Make sure the layout is correct
     */
    xf86ReconfigureLayout();

    /*
     * Make sure the whole screen is visible
     */
569 570
    xf86SetViewport(pScreen, pScreen->width, pScreen->height);
    xf86SetViewport(pScreen, 0, 0);
571
    if (pRoot)
572
        (*scrp->EnableDisableFBAccess) (scrp, TRUE);
573 574 575
    return ret;
}

576
Bool
577 578
xf86RandR12SetConfig(ScreenPtr pScreen,
                     Rotation rotation, int rate, RRScreenSizePtr pSize)
579
{
580
    ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
581 582 583 584 585 586 587 588
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
    DisplayModePtr mode;
    int pos[MAXDEVICES][2];
    Bool useVirtual = FALSE;
    int maxX = 0, maxY = 0;
    Rotation oldRotation = randrp->rotation;
    DeviceIntPtr dev;
    Bool view_adjusted = FALSE;
589 590 591

    randrp->rotation = rotation;

592 593 594
    if (randrp->virtualX == -1 || randrp->virtualY == -1) {
        randrp->virtualX = scrp->virtualX;
        randrp->virtualY = scrp->virtualY;
595 596
    }

597 598 599
    for (dev = inputInfo.devices; dev; dev = dev->next) {
        if (!IsMaster(dev) && !IsFloating(dev))
            continue;
600

601
        miPointerGetPosition(dev, &pos[dev->id][0], &pos[dev->id][1]);
602 603
    }

604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
    for (mode = scrp->modes;; mode = mode->next) {
        if (randrp->maxX == 0 || randrp->maxY == 0) {
            if (maxX < mode->HDisplay)
                maxX = mode->HDisplay;
            if (maxY < mode->VDisplay)
                maxY = mode->VDisplay;
        }
        if (mode->HDisplay == pSize->width &&
            mode->VDisplay == pSize->height &&
            (rate == 0 || xf86RandR12ModeRefresh(mode) == rate))
            break;
        if (mode->next == scrp->modes) {
            if (pSize->width == randrp->virtualX &&
                pSize->height == randrp->virtualY) {
                mode = scrp->modes;
                useVirtual = TRUE;
                break;
            }
            if (randrp->maxX == 0 || randrp->maxY == 0) {
                randrp->maxX = maxX;
                randrp->maxY = maxY;
            }
            return FALSE;
        }
628 629
    }

630 631 632
    if (randrp->maxX == 0 || randrp->maxY == 0) {
        randrp->maxX = maxX;
        randrp->maxY = maxY;
633 634
    }

635 636
    if (!xf86RandR12SetMode(pScreen, mode, useVirtual, pSize->mmWidth,
                            pSize->mmHeight)) {
637
        randrp->rotation = oldRotation;
638
        return FALSE;
639 640 641 642
    }

    /*
     * Move the cursor back where it belongs; SwitchMode repositions it
643
     * FIXME: duplicated code, see modes/xf86RandR12.c
644
     */
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
    for (dev = inputInfo.devices; dev; dev = dev->next) {
        if (!IsMaster(dev) && !IsFloating(dev))
            continue;

        if (pScreen == miPointerGetScreen(dev)) {
            int px = pos[dev->id][0];
            int py = pos[dev->id][1];

            px = (px >= pScreen->width ? (pScreen->width - 1) : px);
            py = (py >= pScreen->height ? (pScreen->height - 1) : py);

            /* Setting the viewpoint makes only sense on one device */
            if (!view_adjusted && IsMaster(dev)) {
                xf86SetViewport(pScreen, px, py);
                view_adjusted = TRUE;
            }

            (*pScreen->SetCursorPosition) (dev, pScreen, px, py, FALSE);
        }
664 665 666 667 668
    }

    return TRUE;
}

669 670 671 672
#define PANNING_ENABLED(crtc)                                           \
    ((crtc)->panningTotalArea.x2 > (crtc)->panningTotalArea.x1 ||       \
     (crtc)->panningTotalArea.y2 > (crtc)->panningTotalArea.y1)

673
static Bool
674 675 676
xf86RandR12ScreenSetSize(ScreenPtr pScreen,
                         CARD16 width,
                         CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
677
{
678
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
679
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
680 681 682 683 684
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
    WindowPtr pRoot = pScreen->root;
    PixmapPtr pScrnPix;
    Bool ret = FALSE;
    int c;
685

686 687 688
    if (randrp->virtualX == -1 || randrp->virtualY == -1) {
        randrp->virtualX = pScrn->virtualX;
        randrp->virtualY = pScrn->virtualY;
689
    }
690
    if (pRoot && pScrn->vtSema)
691
        (*pScrn->EnableDisableFBAccess) (pScrn, FALSE);
692

693
    /* Let the driver update virtualX and virtualY */
694 695
    if (!(*config->funcs->resize) (pScrn, width, height))
        goto finish;
696 697

    ret = TRUE;
698 699
    /* Update panning information */
    for (c = 0; c < config->num_crtc; c++) {
700 701
        xf86CrtcPtr crtc = config->crtc[c];

702
	if (PANNING_ENABLED (crtc)) {
703 704 705 706 707 708 709 710 711 712 713
            if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1)
                crtc->panningTotalArea.x2 += width - pScreen->width;
            if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1)
                crtc->panningTotalArea.y2 += height - pScreen->height;
            if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1)
                crtc->panningTrackingArea.x2 += width - pScreen->width;
            if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1)
                crtc->panningTrackingArea.y2 += height - pScreen->height;
            xf86RandR13VerifyPanningArea(crtc, width, height);
            xf86RandR13Pan(crtc, randrp->pointerX, randrp->pointerY);
        }
Matthias Hopf's avatar
Matthias Hopf committed
714
    }
715

716
    pScrnPix = (*pScreen->GetScreenPixmap) (pScreen);
717 718
    pScreen->width = pScrnPix->drawable.width = width;
    pScreen->height = pScrnPix->drawable.height = height;
719 720
    randrp->mmWidth = pScreen->mmWidth = mmWidth;
    randrp->mmHeight = pScreen->mmHeight = mmHeight;
721

722 723
    xf86SetViewport(pScreen, pScreen->width - 1, pScreen->height - 1);
    xf86SetViewport(pScreen, 0, 0);
724

725
 finish:
726 727
    update_desktop_dimensions();

728
    if (pRoot && pScrn->vtSema)
729
        (*pScrn->EnableDisableFBAccess) (pScrn, TRUE);
730
#if RANDR_12_INTERFACE
731
    if (pScreen->root && ret)
732
        RRScreenSizeNotify(pScreen);
733 734 735 736
#endif
    return ret;
}

737
Rotation
738 739
xf86RandR12GetRotation(ScreenPtr pScreen)
{
740
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
741 742 743 744

    return randrp->rotation;
}

745
Bool
746
xf86RandR12CreateScreenResources(ScreenPtr pScreen)
747
{
748
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
749 750 751 752 753 754
    xf86CrtcConfigPtr config;
    XF86RandRInfoPtr randrp;
    int c;
    int width, height;
    int mmWidth, mmHeight;

755 756 757
#ifdef PANORAMIX
    /* XXX disable RandR when using Xinerama */
    if (!noPanoramiXExtension)
758
        return TRUE;
759 760
#endif

761 762
    config = XF86_CRTC_CONFIG_PTR(pScrn);
    randrp = XF86RANDRINFO(pScreen);
763 764 765
    /*
     * Compute size of screen
     */
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
    width = 0;
    height = 0;
    for (c = 0; c < config->num_crtc; c++) {
        xf86CrtcPtr crtc = config->crtc[c];
        int crtc_width = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
        int crtc_height = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);

        if (crtc->enabled) {
            if (crtc_width > width)
                width = crtc_width;
            if (crtc_height > height)
                height = crtc_height;
            if (crtc->panningTotalArea.x2 > width)
                width = crtc->panningTotalArea.x2;
            if (crtc->panningTotalArea.y2 > height)
                height = crtc->panningTotalArea.y2;
        }
783
    }
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824

    if (width && height) {
        /*
         * Compute physical size of screen
         */
        if (monitorResolution) {
            mmWidth = width * 25.4 / monitorResolution;
            mmHeight = height * 25.4 / monitorResolution;
        }
        else {
            xf86OutputPtr output = xf86CompatOutput(pScrn);

            if (output &&
                output->conf_monitor &&
                (output->conf_monitor->mon_width > 0 &&
                 output->conf_monitor->mon_height > 0)) {
                /*
                 * Prefer user configured DisplaySize
                 */
                mmWidth = output->conf_monitor->mon_width;
                mmHeight = output->conf_monitor->mon_height;
            }
            else {
                /*
                 * Otherwise, just set the screen to DEFAULT_DPI
                 */
                mmWidth = width * 25.4 / DEFAULT_DPI;
                mmHeight = height * 25.4 / DEFAULT_DPI;
            }
        }
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                   "Setting screen physical size to %d x %d\n",
                   mmWidth, mmHeight);
        /*
         * This is the initial setting of the screen size.
         * We have to pre-set it here, otherwise panning would be adapted
         * to the new screen size.
         */
        pScreen->width = width;
        pScreen->height = height;
        xf86RandR12ScreenSetSize(pScreen, width, height, mmWidth, mmHeight);
825 826
    }

827 828 829
    if (randrp->virtualX == -1 || randrp->virtualY == -1) {
        randrp->virtualX = pScrn->virtualX;
        randrp->virtualY = pScrn->virtualY;
830
    }
831
    xf86CrtcSetScreenSubpixelOrder(pScreen);
832
#if RANDR_12_INTERFACE
833 834
    if (xf86RandR12CreateScreenResources12(pScreen))
        return TRUE;
835 836 837 838
#endif
    return TRUE;
}

839
Bool
840
xf86RandR12Init(ScreenPtr pScreen)
841
{
842 843
    rrScrPrivPtr rp;
    XF86RandRInfoPtr randrp;
844 845 846

#ifdef PANORAMIX
    /* XXX disable RandR when using Xinerama */
847
    if (!noPanoramiXExtension) {
848 849 850 851 852
        if (xf86NumScreens == 1)
            noPanoramiXExtension = TRUE;
        else
            return TRUE;
    }
853
#endif
854

855
    if (xf86RandR12Generation != serverGeneration)
856
        xf86RandR12Generation = serverGeneration;
857

858 859
    xf86RandR12Key = &xf86RandR12KeyRec;
    if (!dixRegisterPrivateKey(&xf86RandR12KeyRec, PRIVATE_SCREEN, 0))
860
        return FALSE;
861

862
    randrp = malloc(sizeof(XF86RandRInfoRec));
863
    if (!randrp)
864
        return FALSE;
865

866 867 868
    if (!RRScreenInit(pScreen)) {
        free(randrp);
        return FALSE;
869 870 871 872 873 874 875 876 877 878
    }
    rp = rrGetScrPriv(pScreen);
    rp->rrGetInfo = xf86RandR12GetInfo;
    rp->rrSetConfig = xf86RandR12SetConfig;

    randrp->virtualX = -1;
    randrp->virtualY = -1;
    randrp->mmWidth = pScreen->mmWidth;
    randrp->mmHeight = pScreen->mmHeight;

879
    randrp->rotation = RR_Rotate_0;     /* initial rotated mode */
880 881 882 883 884

    randrp->supported_rotations = RR_Rotate_0;

    randrp->maxX = randrp->maxY = 0;

885
    dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp);
886 887

#if RANDR_12_INTERFACE
888 889
    if (!xf86RandR12Init12(pScreen))
        return FALSE;
890 891 892 893
#endif
    return TRUE;
}

894
void
895
xf86RandR12CloseScreen(ScreenPtr pScreen)
896
{
897
    XF86RandRInfoPtr randrp;
898 899

    if (xf86RandR12Key == NULL)
900
        return;
901 902 903

    randrp = XF86RANDRINFO(pScreen);
#if RANDR_12_INTERFACE
904
    xf86ScreenToScrn(pScreen)->EnterVT = randrp->orig_EnterVT;
905
    pScreen->ConstrainCursorHarder = randrp->orig_ConstrainCursorHarder;
906 907 908 909 910
#endif

    free(randrp);
}

911
void
912
xf86RandR12SetRotations(ScreenPtr pScreen, Rotation rotations)
913
{
914 915
    XF86RandRInfoPtr randrp;

916
#if RANDR_12_INTERFACE
917
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
918 919
    int c;
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
920
#endif
921

922
    if (xf86RandR12Key == NULL)
923
        return;
924

925
    randrp = XF86RANDRINFO(pScreen);
926
#if RANDR_12_INTERFACE
927
    for (c = 0; c < config->num_crtc; c++) {
928
        xf86CrtcPtr crtc = config->crtc[c];
929

930
        RRCrtcSetRotations(crtc->randr_crtc, rotations);
931 932
    }
#endif
933
    randrp->supported_rotations = rotations;
934 935
}

936
void
937
xf86RandR12SetTransformSupport(ScreenPtr pScreen, Bool transforms)
938 939
{
#if RANDR_13_INTERFACE
940
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
941 942
    int c;
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
943 944 945
#endif

    if (xf86RandR12Key == NULL)
946
        return;
947 948 949

#if RANDR_13_INTERFACE
    for (c = 0; c < config->num_crtc; c++) {
950
        xf86CrtcPtr crtc = config->crtc[c];
951

952
        RRCrtcSetTransformSupport(crtc->randr_crtc, transforms);
953 954 955 956
    }
#endif
}

957
void
958 959
xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
{
960
    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
961 962

    if (xf86RandR12Generation != serverGeneration ||
963 964 965 966 967 968 969 970 971
        XF86RANDRINFO(pScreen)->virtualX == -1) {
        *x = pScrn->virtualX;
        *y = pScrn->virtualY;
    }
    else {
        XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);

        *x = randrp->virtualX;
        *y = randrp->virtualY;
972 973 974 975
    }
}

#if RANDR_12_INTERFACE
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992

#define FLAG_BITS (RR_HSyncPositive | \
		   RR_HSyncNegative | \
		   RR_VSyncPositive | \
		   RR_VSyncNegative | \
		   RR_Interlace | \
		   RR_DoubleScan | \
		   RR_CSync | \
		   RR_CSyncPositive | \
		   RR_CSyncNegative | \
		   RR_HSkewPresent | \
		   RR_BCast | \
		   RR_PixelMultiplex | \
		   RR_DoubleClock | \
		   RR_ClockDivideBy2)

static Bool
993
xf86RandRModeMatches(RRModePtr randr_mode, DisplayModePtr mode)
994 995
{
#if 0
996 997 998 999 1000 1001 1002 1003
    if (match_name) {
        /* check for same name */
        int len = strlen(mode->name);

        if (randr_mode->mode.nameLength != len)
            return FALSE;
        if (memcmp(randr_mode->name, mode->name, len) != 0)
            return FALSE;
1004 1005
    }
#endif
1006

1007
    /* check for same timings */
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
    if (randr_mode->mode.dotClock / 1000 != mode->Clock)
        return FALSE;
    if (randr_mode->mode.width != mode->HDisplay)
        return FALSE;
    if (randr_mode->mode.hSyncStart != mode->HSyncStart)
        return FALSE;
    if (randr_mode->mode.hSyncEnd != mode->HSyncEnd)
        return FALSE;
    if (randr_mode->mode.hTotal != mode->HTotal)
        return FALSE;
    if (randr_mode->mode.hSkew != mode->HSkew)
        return FALSE;
    if (randr_mode->mode.height != mode->VDisplay)
        return FALSE;
    if (randr_mode->mode.vSyncStart != mode->VSyncStart)
        return FALSE;
    if (randr_mode->mode.vSyncEnd != mode->VSyncEnd)
        return FALSE;
    if (randr_mode->mode.vTotal != mode->VTotal)
        return FALSE;

1029 1030
    /* check for same flags (using only the XF86 valid flag bits) */
    if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
1031 1032
        return FALSE;

1033 1034 1035 1036
    /* everything matches */
    return TRUE;
}

1037
static Bool
1038
xf86RandR12CrtcNotify(RRCrtcPtr randr_crtc)
1039
{
1040
    ScreenPtr pScreen = randr_crtc->pScreen;
1041
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
    RRModePtr randr_mode = NULL;
    int x;
    int y;
    Rotation rotation;
    int numOutputs;
    RROutputPtr *randr_outputs;
    RROutputPtr randr_output;
    xf86CrtcPtr crtc = randr_crtc->devPrivate;
    xf86OutputPtr output;
    int i, j;
    DisplayModePtr mode = &crtc->mode;
    Bool ret;

1056
    randr_outputs = xallocarray(config->num_output, sizeof(RROutputPtr));
1057
    if (!randr_outputs)
1058
        return FALSE;
1059 1060 1061 1062 1063
    x = crtc->x;
    y = crtc->y;
    rotation = crtc->rotation;
    numOutputs = 0;
    randr_mode = NULL;
1064 1065 1066 1067 1068 1069
    for (i = 0; i < config->num_output; i++) {
        output = config->output[i];
        if (output->crtc == crtc) {
            randr_output = output->randr_output;
            randr_outputs[numOutputs++] = randr_output;
            /*
Peter Hutterer's avatar
Peter Hutterer committed
1070
             * We make copies of modes, so pointer equality
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
             * isn't sufficient
             */
            for (j = 0; j < randr_output->numModes + randr_output->numUserModes;
                 j++) {
                RRModePtr m =
                    (j <
                     randr_output->numModes ? randr_output->
                     modes[j] : randr_output->userModes[j -
                                                        randr_output->
                                                        numModes]);

                if (xf86RandRModeMatches(m, mode)) {
                    randr_mode = m;
                    break;
                }
            }
        }
1088
    }
1089 1090 1091 1092
    ret = RRCrtcNotify(randr_crtc, randr_mode, x, y,
                       rotation,
                       crtc->transformPresent ? &crtc->transform : NULL,
                       numOutputs, randr_outputs);
1093
    free(randr_outputs);
1094 1095 1096
    return ret;
}

1097 1098 1099 1100
/*
 * Convert a RandR mode to a DisplayMode
 */
static void
1101 1102
xf86RandRModeConvert(ScrnInfoPtr scrn,
                     RRModePtr randr_mode, DisplayModePtr mode)
1103
{
1104
    memset(mode, 0, sizeof(DisplayModeRec));
1105 1106 1107
    mode->status = MODE_OK;

    mode->Clock = randr_mode->mode.dotClock / 1000;
1108

1109 1110 1111 1112 1113
    mode->HDisplay = randr_mode->mode.width;
    mode->HSyncStart = randr_mode->mode.hSyncStart;
    mode->HSyncEnd = randr_mode->mode.hSyncEnd;
    mode->HTotal = randr_mode->mode.hTotal;
    mode->HSkew = randr_mode->mode.hSkew;
1114

1115 1116 1117 1118 1119 1120 1121 1122
    mode->VDisplay = randr_mode->mode.height;
    mode->VSyncStart = randr_mode->mode.vSyncStart;
    mode->VSyncEnd = randr_mode->mode.vSyncEnd;
    mode->VTotal = randr_mode->mode.vTotal;
    mode->VScan = 0;

    mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;

1123
    xf86SetModeCrtc(mode, scrn->adjustFlags);
1124 1125
}

1126
static Bool
1127 1128 1129 1130 1131 1132 1133
xf86RandR12CrtcSet(ScreenPtr pScreen,
                   RRCrtcPtr randr_crtc,
                   RRModePtr randr_mode,
                   int x,
                   int y,
                   Rotation rotation,
                   int num_randr_outputs, RROutputPtr * randr_outputs)
1134
{
1135
    XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
1136
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1137 1138 1139 1140 1141 1142 1143
    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
    xf86CrtcPtr crtc = randr_crtc->devPrivate;
    RRTransformPtr transform;
    Bool changed = FALSE;
    int o, ro;
    xf86CrtcPtr *save_crtcs;
    Bool save_enabled = crtc->enabled;
1144

1145
    if (!crtc->scrn->vtSema)
1146
        return FALSE;
1147

1148
    save_crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr));
1149
    if ((randr_mode != NULL) != crtc->enabled)
1150 1151 1152 1153
        changed = TRUE;
    else if (randr_mode && !xf86RandRModeMatches(randr_mode, &crtc->mode))
        changed = TRUE;

1154
    if (rotation != crtc->rotation)
1155
        changed = TRUE;
1156

1157 1158 1159
    if (crtc->current_scanout != randr_crtc->scanout_pixmap)
        changed = TRUE;

1160
    transform = RRCrtcGetTransform(randr_crtc);
1161
    if ((transform != NULL) != crtc->transformPresent)
1162 1163 1164 1165 1166
        changed = TRUE;
    else if (transform &&
             memcmp(&transform->transform, &crtc->transform.transform,
                    sizeof(transform->transform)) != 0)
        changed = TRUE;
1167

1168
    if (x != crtc->x || y != crtc->y)
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
        changed = TRUE;
    for (o = 0; o < config->num_output; o++) {
        xf86OutputPtr output = config->output[o];
        xf86CrtcPtr new_crtc;

        save_crtcs[o] = output->crtc;

        if (output->crtc == crtc)
            new_crtc = NULL;
        else
            new_crtc = output->crtc;
        for (ro = 0; ro < num_randr_outputs; ro++)
            if (output->randr_output == randr_outputs[ro]) {
                new_crtc = crtc;
                break;
            }
        if (new_crtc != output->crtc) {
            changed = TRUE;
            output->crtc = new_crtc;
        }
1189
    }
1190
    for (ro = 0; ro < num_randr_outputs; ro++)
1191
        if (randr_outputs[ro]->pendingProperties)