xf86Cursors.c 20.4 KB
Newer Older
1 2
/*
 * Copyright © 2007 Keith Packard
3
 * Copyright © 2010-2011 Aaron Plattner
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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>
#endif

#include <stddef.h>
#include <string.h>
#include <stdio.h>

32
#include <X11/Xarch.h>
33 34 35 36 37
#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
#include "xf86RandR12.h"
38
#include "xf86CursorPriv.h"
39
#include "X11/extensions/render.h"
Peter Hutterer's avatar
Peter Hutterer committed
40
#include "X11/extensions/dpmsconst.h"
41 42 43
#include "X11/Xatom.h"
#include "picturestr.h"
#include "cursorstr.h"
44
#include "inputstr.h"
45

46 47 48 49 50
/*
 * Returns the rotation being performed by the server.  If the driver indicates
 * that it's handling the screen transform, then this returns RR_Rotate_0.
 */
static Rotation
51
xf86_crtc_cursor_rotation(xf86CrtcPtr crtc)
52
{
53
    if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorImage)
54
        return RR_Rotate_0;
55 56 57
    return crtc->rotation;
}

58 59 60 61
/*
 * Given a screen coordinate, rotate back to a cursor source coordinate
 */
static void
62 63 64
xf86_crtc_rotate_coord(Rotation rotation,
                       int width,
                       int height, int x_dst, int y_dst, int *x_src, int *y_src)
65
{
Keith Packard's avatar
Keith Packard committed
66
    int t;
67

Keith Packard's avatar
Keith Packard committed
68 69
    switch (rotation & 0xf) {
    case RR_Rotate_0:
70
        break;
Keith Packard's avatar
Keith Packard committed
71
    case RR_Rotate_90:
72
        t = x_dst;
73
        x_dst = width - y_dst - 1;
74 75
        y_dst = t;
        break;
Keith Packard's avatar
Keith Packard committed
76
    case RR_Rotate_180:
77 78 79
        x_dst = width - x_dst - 1;
        y_dst = height - y_dst - 1;
        break;
Keith Packard's avatar
Keith Packard committed
80
    case RR_Rotate_270:
81 82
        t = x_dst;
        x_dst = y_dst;
83
        y_dst = height - t - 1;
84
        break;
Keith Packard's avatar
Keith Packard committed
85
    }
86
    if (rotation & RR_Reflect_X)
87
        x_dst = width - x_dst - 1;
88
    if (rotation & RR_Reflect_Y)
89
        y_dst = height - y_dst - 1;
Keith Packard's avatar
Keith Packard committed
90 91 92 93 94 95 96 97
    *x_src = x_dst;
    *y_src = y_dst;
}

/*
 * Given a cursor source  coordinate, rotate to a screen coordinate
 */
static void
98 99 100 101
xf86_crtc_rotate_coord_back(Rotation rotation,
                            int width,
                            int height,
                            int x_dst, int y_dst, int *x_src, int *y_src)
Keith Packard's avatar
Keith Packard committed
102 103
{
    int t;
104

Keith Packard's avatar
Keith Packard committed
105
    if (rotation & RR_Reflect_X)
106
        x_dst = width - x_dst - 1;
Keith Packard's avatar
Keith Packard committed
107
    if (rotation & RR_Reflect_Y)
108
        y_dst = height - y_dst - 1;
Keith Packard's avatar
Keith Packard committed
109

110 111
    switch (rotation & 0xf) {
    case RR_Rotate_0:
112
        break;
113
    case RR_Rotate_90:
114 115 116 117
        t = x_dst;
        x_dst = y_dst;
        y_dst = width - t - 1;
        break;
118
    case RR_Rotate_180:
119 120 121
        x_dst = width - x_dst - 1;
        y_dst = height - y_dst - 1;
        break;
122
    case RR_Rotate_270:
123 124 125 126
        t = x_dst;
        x_dst = height - y_dst - 1;
        y_dst = t;
        break;
127
    }
Keith Packard's avatar
Keith Packard committed
128 129
    *x_src = x_dst;
    *y_src = y_dst;
130 131
}

132 133 134 135 136
struct cursor_bit {
    CARD8 *byte;
    char bitpos;
};

137 138 139
/*
 * Convert an x coordinate to a position within the cursor bitmap
 */
140
static struct cursor_bit
141 142
cursor_bitpos(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y,
              Bool mask)
143
{
144 145
    const int flags = cursor_info->Flags;
    const Bool interleaved =
146 147 148 149 150
        ! !(flags & (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
151 152 153 154 155 156 157 158
    const int width = cursor_info->MaxWidth;
    const int height = cursor_info->MaxHeight;
    const int stride = interleaved ? width / 4 : width / 8;

    struct cursor_bit ret;

    image += y * stride;

159
    if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
160
        mask = !mask;
161
    if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
162
        x = (x & ~3) | (3 - (x & 3));
163
    if (((flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) == 0) ==
164 165
        (X_BYTE_ORDER == X_BIG_ENDIAN))
        x = (x & ~7) | (7 - (x & 7));
166
    if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1)
167
        x = (x << 1) + mask;
168
    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8)
169
        x = ((x & ~7) << 1) | (mask << 3) | (x & 7);
170
    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16)
171
        x = ((x & ~15) << 1) | (mask << 4) | (x & 15);
172
    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32)
173
        x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
174
    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
175
        x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
176
    else if (mask)
177
        image += stride * height;
178 179 180 181 182

    ret.byte = image + (x / 8);
    ret.bitpos = x & 7;

    return ret;
183 184 185 186 187 188
}

/*
 * Fetch one bit from a cursor bitmap
 */
static CARD8
189
get_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
190
{
191
    struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
192

193
    return (*bit.byte >> bit.bitpos) & 1;
194 195 196 197 198 199
}

/*
 * Set one bit in a cursor bitmap
 */
static void
200
set_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
201
{
202
    struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
203

204
    *bit.byte |= 1 << bit.bitpos;
205
}
206

207 208
/*
 * Wrappers to deal with API compatibility with drivers that don't expose
209
 * *_cursor_*_check
210
 */
211 212 213 214 215 216
static inline Bool
xf86_driver_has_show_cursor(xf86CrtcPtr crtc)
{
    return crtc->funcs->show_cursor_check || crtc->funcs->show_cursor;
}

217 218 219 220 221 222 223 224 225 226 227 228
static inline Bool
xf86_driver_has_load_cursor_image(xf86CrtcPtr crtc)
{
    return crtc->funcs->load_cursor_image_check || crtc->funcs->load_cursor_image;
}

static inline Bool
xf86_driver_has_load_cursor_argb(xf86CrtcPtr crtc)
{
    return crtc->funcs->load_cursor_argb_check || crtc->funcs->load_cursor_argb;
}

229 230 231 232 233 234 235 236 237
static inline Bool
xf86_driver_show_cursor(xf86CrtcPtr crtc)
{
    if (crtc->funcs->show_cursor_check)
        return crtc->funcs->show_cursor_check(crtc);
    crtc->funcs->show_cursor(crtc);
    return TRUE;
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
static inline Bool
xf86_driver_load_cursor_image(xf86CrtcPtr crtc, CARD8 *cursor_image)
{
    if (crtc->funcs->load_cursor_image_check)
        return crtc->funcs->load_cursor_image_check(crtc, cursor_image);
    crtc->funcs->load_cursor_image(crtc, cursor_image);
    return TRUE;
}

static inline Bool
xf86_driver_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *cursor_argb)
{
    if (crtc->funcs->load_cursor_argb_check)
        return crtc->funcs->load_cursor_argb_check(crtc, cursor_argb);
    crtc->funcs->load_cursor_argb(crtc, cursor_argb);
    return TRUE;
}

256 257 258
/*
 * Load a two color cursor into a driver that supports only ARGB cursors
 */
259
static Bool
260
xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc, unsigned char *src)
261
{
262 263 264 265 266 267 268 269 270
    ScrnInfoPtr scrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
    int x, y;
    int xin, yin;
    int flags = cursor_info->Flags;
    CARD32 bits;
    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
271 272 273 274

    crtc->cursor_argb = FALSE;

    for (y = 0; y < cursor_info->MaxHeight; y++)
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
        for (x = 0; x < cursor_info->MaxWidth; x++) {
            xf86_crtc_rotate_coord(rotation,
                                   cursor_info->MaxWidth,
                                   cursor_info->MaxHeight, x, y, &xin, &yin);
            if (get_bit(src, cursor_info, xin, yin, TRUE) ==
                ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) {
                if (get_bit(src, cursor_info, xin, yin, FALSE))
                    bits = xf86_config->cursor_fg;
                else
                    bits = xf86_config->cursor_bg;
            }
            else
                bits = 0;
            cursor_image[y * cursor_info->MaxWidth + x] = bits;
        }
290
    return xf86_driver_load_cursor_argb(crtc, cursor_image);
291 292 293 294 295 296
}

/*
 * Set the colors for a two-color cursor (ignore for ARGB cursors)
 */
static void
297
xf86_set_cursor_colors(ScrnInfoPtr scrn, int bg, int fg)
298
{
299 300
    ScreenPtr screen = scrn->pScreen;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
301
    CursorPtr cursor = xf86CurrentCursor(screen);
302 303
    int c;
    CARD8 *bits = cursor ?
304
        dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey, screen)
305
        : NULL;
306 307 308 309

    /* Save ARGB versions of these colors */
    xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
    xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
310 311 312 313 314

    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];

        if (crtc->enabled && !crtc->cursor_argb) {
315
            if (xf86_driver_has_load_cursor_image(crtc))
316 317 318 319
                crtc->funcs->set_cursor_colors(crtc, bg, fg);
            else if (bits)
                xf86_crtc_convert_cursor_to_argb(crtc, bits);
        }
320 321 322 323
    }
}

static void
324
xf86_crtc_hide_cursor(xf86CrtcPtr crtc)
325
{
326 327 328
    if (crtc->cursor_shown) {
        crtc->funcs->hide_cursor(crtc);
        crtc->cursor_shown = FALSE;
329 330 331
    }
}

332
void
333
xf86_hide_cursors(ScrnInfoPtr scrn)
334
{
335 336
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
337 338

    xf86_config->cursor_on = FALSE;
339 340
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];
341

342 343
        if (crtc->enabled)
            xf86_crtc_hide_cursor(crtc);
344 345
    }
}
346

347
static Bool
348
xf86_crtc_show_cursor(xf86CrtcPtr crtc)
349
{
350 351 352 353 354 355 356
    if (!crtc->cursor_in_range)
        return TRUE;

    if (!crtc->cursor_shown)
        crtc->cursor_shown = xf86_driver_show_cursor(crtc);

    return crtc->cursor_shown;
357 358
}

359
Bool
360
xf86_show_cursors(ScrnInfoPtr scrn)
361
{
362 363
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
364 365

    xf86_config->cursor_on = TRUE;
366 367
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];
368

369 370
        if (crtc->enabled && !xf86_crtc_show_cursor(crtc))
            return FALSE;
371
    }
372 373

    return TRUE;
374
}
375

376 377
static void
xf86_crtc_transform_cursor_position(xf86CrtcPtr crtc, int *x, int *y)
378 379 380 381 382 383
{
    ScrnInfoPtr scrn = crtc->scrn;
    ScreenPtr screen = scrn->pScreen;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    xf86CursorScreenPtr ScreenPriv =
384 385
        (xf86CursorScreenPtr) dixLookupPrivate(&screen->devPrivates,
                                               xf86CursorScreenKey);
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 423 424
    int dx, dy, t;
    Bool swap_reflection = FALSE;

    *x = *x - crtc->x + ScreenPriv->HotX;
    *y = *y - crtc->y + ScreenPriv->HotY;

    switch (crtc->rotation & 0xf) {
    case RR_Rotate_0:
        break;
    case RR_Rotate_90:
        t = *x;
        *x = *y;
        *y = crtc->mode.VDisplay - t - 1;
        swap_reflection = TRUE;
        break;
    case RR_Rotate_180:
        *x = crtc->mode.HDisplay - *x - 1;
        *y = crtc->mode.VDisplay - *y - 1;
        break;
    case RR_Rotate_270:
        t = *x;
        *x = crtc->mode.HDisplay - *y - 1;
        *y = t;
        swap_reflection = TRUE;
        break;
    }

    if (swap_reflection) {
        if (crtc->rotation & RR_Reflect_Y)
            *x = crtc->mode.HDisplay - *x - 1;
        if (crtc->rotation & RR_Reflect_X)
            *y = crtc->mode.VDisplay - *y - 1;
    } else {
        if (crtc->rotation & RR_Reflect_X)
            *x = crtc->mode.HDisplay - *x - 1;
        if (crtc->rotation & RR_Reflect_Y)
            *y = crtc->mode.VDisplay - *y - 1;
    }

425 426 427
    /*
     * Transform position of cursor upper left corner
     */
428 429 430
    xf86_crtc_rotate_coord_back(crtc->rotation, cursor_info->MaxWidth,
                                cursor_info->MaxHeight, ScreenPriv->HotX,
                                ScreenPriv->HotY, &dx, &dy);
431 432 433 434
    *x -= dx;
    *y -= dy;
}

435
static void
436
xf86_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
437
{
438 439 440 441
    ScrnInfoPtr scrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    DisplayModePtr mode = &crtc->mode;
442
    int crtc_x = x, crtc_y = y;
443 444

    /*
Keith Packard's avatar
Keith Packard committed
445
     * Transform position of cursor on screen
446
     */
447
    if (crtc->rotation != RR_Rotate_0)
448
        xf86_crtc_transform_cursor_position(crtc, &crtc_x, &crtc_y);
449
    else {
450 451
        crtc_x -= crtc->x;
        crtc_y -= crtc->y;
452 453 454 455 456
    }

    /*
     * Disable the cursor when it is outside the viewport
     */
457 458
    if (crtc_x >= mode->HDisplay || crtc_y >= mode->VDisplay ||
        crtc_x <= -cursor_info->MaxWidth || crtc_y <= -cursor_info->MaxHeight) {
459 460 461 462
        crtc->cursor_in_range = FALSE;
        xf86_crtc_hide_cursor(crtc);
    } else {
        crtc->cursor_in_range = TRUE;
463
        if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorPosition)
464 465 466
            crtc->funcs->set_cursor_position(crtc, x, y);
        else
            crtc->funcs->set_cursor_position(crtc, crtc_x, crtc_y);
467
        xf86_crtc_show_cursor(crtc);
468 469 470 471
    }
}

static void
472
xf86_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
473
{
474 475
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
476 477 478 479

    /* undo what xf86HWCurs did to the coordinates */
    x += scrn->frameX0;
    y += scrn->frameY0;
480 481
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];
482

483 484
        if (crtc->enabled)
            xf86_crtc_set_cursor_position(crtc, x, y);
485 486
    }
}
487

488 489 490
/*
 * Load a two-color cursor into a crtc, performing rotation as needed
 */
491
static Bool
492
xf86_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *src)
493
{
494 495 496 497 498
    ScrnInfoPtr scrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    CARD8 *cursor_image;
    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
499 500 501

    crtc->cursor_argb = FALSE;

502
    if (rotation == RR_Rotate_0)
503 504
        cursor_image = src;
    else {
505
        int x, y;
506 507 508 509 510 511
        int xin, yin;
        int stride = cursor_info->MaxWidth >> 2;

        cursor_image = xf86_config->cursor_image;
        memset(cursor_image, 0, cursor_info->MaxHeight * stride);

512
        for (y = 0; y < cursor_info->MaxHeight; y++)
513 514 515 516 517 518 519 520 521 522
            for (x = 0; x < cursor_info->MaxWidth; x++) {
                xf86_crtc_rotate_coord(rotation,
                                       cursor_info->MaxWidth,
                                       cursor_info->MaxHeight,
                                       x, y, &xin, &yin);
                if (get_bit(src, cursor_info, xin, yin, FALSE))
                    set_bit(cursor_image, cursor_info, x, y, FALSE);
                if (get_bit(src, cursor_info, xin, yin, TRUE))
                    set_bit(cursor_image, cursor_info, x, y, TRUE);
            }
523
    }
524
    return xf86_driver_load_cursor_image(crtc, cursor_image);
525
}
526

527 528 529
/*
 * Load a cursor image into all active CRTCs
 */
530
static Bool
531
xf86_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
532
{
533 534 535
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;

536
    xf86_config->cursor = xf86CurrentCursor(scrn->pScreen);
537 538 539 540
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];

        if (crtc->enabled) {
541
            if (xf86_driver_has_load_cursor_image(crtc)) {
542 543
                if (!xf86_crtc_load_cursor_image(crtc, src))
                    return FALSE;
544
            } else if (xf86_driver_has_load_cursor_argb(crtc)) {
545 546 547 548
                if (!xf86_crtc_convert_cursor_to_argb(crtc, src))
                    return FALSE;
            } else
                return FALSE;
549
        }
550
    }
551
    return TRUE;
552 553 554
}

static Bool
555
xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
556
{
557
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
558 559
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
560
    int c;
561 562

    if (cursor->bits->width > cursor_info->MaxWidth ||
563 564
        cursor->bits->height > cursor_info->MaxHeight)
        return FALSE;
565

566 567 568 569 570 571 572 573 574 575
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];

        if (!crtc->enabled)
            continue;

        if (crtc->transformPresent)
            return FALSE;
    }

576 577 578 579
    return TRUE;
}

static Bool
580
xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor)
581
{
582
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
583 584 585
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;

586 587
    if (!xf86_use_hw_cursor(screen, cursor))
        return FALSE;
588

589 590
    /* Make sure ARGB support is available */
    if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0)
591 592
        return FALSE;

593 594 595
    return TRUE;
}

596
static Bool
597
xf86_crtc_load_cursor_argb(xf86CrtcPtr crtc, CursorPtr cursor)
598
{
599 600 601 602 603 604 605 606 607 608 609 610 611
    ScrnInfoPtr scrn = crtc->scrn;
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
    CARD32 *cursor_source = (CARD32 *) cursor->bits->argb;
    int x, y;
    int xin, yin;
    CARD32 bits;
    int source_width = cursor->bits->width;
    int source_height = cursor->bits->height;
    int image_width = cursor_info->MaxWidth;
    int image_height = cursor_info->MaxHeight;
    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
612

613
    for (y = 0; y < image_height; y++)
614 615 616 617 618 619 620 621 622 623
        for (x = 0; x < image_width; x++) {
            xf86_crtc_rotate_coord(rotation, image_width, image_height, x, y,
                                   &xin, &yin);
            if (xin < source_width && yin < source_height)
                bits = cursor_source[yin * source_width + xin];
            else
                bits = 0;
            cursor_image[y * image_width + x] = bits;
        }

624
    return xf86_driver_load_cursor_argb(crtc, cursor_image);
625 626
}

627
static Bool
628
xf86_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
629
{
630 631
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    int c;
632

633
    xf86_config->cursor = cursor;
634 635
    for (c = 0; c < xf86_config->num_crtc; c++) {
        xf86CrtcPtr crtc = xf86_config->crtc[c];
636

637
        if (crtc->enabled)
638 639
            if (!xf86_crtc_load_cursor_argb(crtc, cursor))
                return FALSE;
640
    }
641
    return TRUE;
642 643
}

644
Bool
645
xf86_cursors_init(ScreenPtr screen, int max_width, int max_height, int flags)
646
{
647
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
648 649
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    xf86CursorInfoPtr cursor_info;
650 651 652

    cursor_info = xf86CreateCursorInfoRec();
    if (!cursor_info)
653
        return FALSE;
654

655
    xf86_config->cursor_image = malloc(max_width * max_height * 4);
656

657 658 659
    if (!xf86_config->cursor_image) {
        xf86DestroyCursorInfoRec(cursor_info);
        return FALSE;
660
    }
661

662 663 664 665 666 667 668 669
    xf86_config->cursor_info = cursor_info;

    cursor_info->MaxWidth = max_width;
    cursor_info->MaxHeight = max_height;
    cursor_info->Flags = flags;

    cursor_info->SetCursorColors = xf86_set_cursor_colors;
    cursor_info->SetCursorPosition = xf86_set_cursor_position;
670
    cursor_info->LoadCursorImageCheck = xf86_load_cursor_image;
671
    cursor_info->HideCursor = xf86_hide_cursors;
672
    cursor_info->ShowCursorCheck = xf86_show_cursors;
673
    cursor_info->UseHWCursor = xf86_use_hw_cursor;
674 675
    if (flags & HARDWARE_CURSOR_ARGB) {
        cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb;
676
        cursor_info->LoadCursorARGBCheck = xf86_load_cursor_argb;
677
    }
678 679 680 681

    xf86_hide_cursors(scrn);

    return xf86InitCursor(screen, cursor_info);
682 683 684 685 686
}

/**
 * Clean up CRTC-based cursor code
 */
687
void
688
xf86_cursors_fini(ScreenPtr screen)
689
{
690
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
691 692 693 694 695
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);

    if (xf86_config->cursor_info) {
        xf86DestroyCursorInfoRec(xf86_config->cursor_info);
        xf86_config->cursor_info = NULL;
696
    }
697 698
    free(xf86_config->cursor_image);
    xf86_config->cursor_image = NULL;
699
    xf86_config->cursor = NULL;
700
}