1/*
2 * Copyright © 2007 Keith Packard
3 * Copyright © 2010-2011 Aaron Plattner
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission.  The copyright holders make no representations
12 * about the suitability of this software for any purpose.  It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_XORG_CONFIG_H
25#include <xorg-config.h>
26#endif
27
28#include <stddef.h>
29#include <string.h>
30#include <stdio.h>
31
32#include <X11/Xarch.h>
33#include "xf86.h"
34#include "xf86DDC.h"
35#include "xf86Crtc.h"
36#include "xf86Modes.h"
37#include "xf86RandR12.h"
38#include "xf86CursorPriv.h"
39#include "X11/extensions/render.h"
40#include "X11/extensions/dpmsconst.h"
41#include "X11/Xatom.h"
42#include "picturestr.h"
43#include "cursorstr.h"
44#include "inputstr.h"
45
46/*
47 * Returns the rotation being performed by the server.  If the driver indicates
48 * that it's handling the screen transform, then this returns RR_Rotate_0.
49 */
50static Rotation
51xf86_crtc_cursor_rotation(xf86CrtcPtr crtc)
52{
53    if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorImage)
54        return RR_Rotate_0;
55    return crtc->rotation;
56}
57
58/*
59 * Given a screen coordinate, rotate back to a cursor source coordinate
60 */
61static void
62xf86_crtc_rotate_coord(Rotation rotation,
63                       int width,
64                       int height, int x_dst, int y_dst, int *x_src, int *y_src)
65{
66    int t;
67
68    switch (rotation & 0xf) {
69    case RR_Rotate_0:
70        break;
71    case RR_Rotate_90:
72        t = x_dst;
73        x_dst = width - y_dst - 1;
74        y_dst = t;
75        break;
76    case RR_Rotate_180:
77        x_dst = width - x_dst - 1;
78        y_dst = height - y_dst - 1;
79        break;
80    case RR_Rotate_270:
81        t = x_dst;
82        x_dst = y_dst;
83        y_dst = height - t - 1;
84        break;
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;
90    *x_src = x_dst;
91    *y_src = y_dst;
92}
93
94/*
95 * Given a cursor source  coordinate, rotate to a screen coordinate
96 */
97static void
98xf86_crtc_rotate_coord_back(Rotation rotation,
99                            int width,
100                            int height,
101                            int x_dst, int y_dst, int *x_src, int *y_src)
102{
103    int t;
104
105    if (rotation & RR_Reflect_X)
106        x_dst = width - x_dst - 1;
107    if (rotation & RR_Reflect_Y)
108        y_dst = height - y_dst - 1;
109
110    switch (rotation & 0xf) {
111    case RR_Rotate_0:
112        break;
113    case RR_Rotate_90:
114        t = x_dst;
115        x_dst = y_dst;
116        y_dst = width - t - 1;
117        break;
118    case RR_Rotate_180:
119        x_dst = width - x_dst - 1;
120        y_dst = height - y_dst - 1;
121        break;
122    case RR_Rotate_270:
123        t = x_dst;
124        x_dst = height - y_dst - 1;
125        y_dst = t;
126        break;
127    }
128    *x_src = x_dst;
129    *y_src = y_dst;
130}
131
132struct cursor_bit {
133    CARD8 *byte;
134    char bitpos;
135};
136
137/*
138 * Convert an x coordinate to a position within the cursor bitmap
139 */
140static struct cursor_bit
141cursor_bitpos(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y,
142              Bool mask)
143{
144    const int flags = cursor_info->Flags;
145    const Bool interleaved =
146        ! !(flags & (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
147                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
148                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
149                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
150                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
151    const int width = cursor_info->MaxWidth;
152    const int height = cursor_info->MaxHeight;
153    const int stride = interleaved ? width / 4 : width / 8;
154
155    struct cursor_bit ret;
156
157    image += y * stride;
158
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        (X_BYTE_ORDER == X_BIG_ENDIAN))
165        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    ret.byte = image + (x / 8);
180    ret.bitpos = x & 7;
181
182    return ret;
183}
184
185/*
186 * Fetch one bit from a cursor bitmap
187 */
188static CARD8
189get_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 * Set one bit in a cursor bitmap
198 */
199static void
200set_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 */
211static inline Bool
212xf86_driver_has_show_cursor(xf86CrtcPtr crtc)
213{
214    return crtc->funcs->show_cursor_check || crtc->funcs->show_cursor;
215}
216
217static inline Bool
218xf86_driver_has_load_cursor_image(xf86CrtcPtr crtc)
219{
220    return crtc->funcs->load_cursor_image_check || crtc->funcs->load_cursor_image;
221}
222
223static inline Bool
224xf86_driver_has_load_cursor_argb(xf86CrtcPtr crtc)
225{
226    return crtc->funcs->load_cursor_argb_check || crtc->funcs->load_cursor_argb;
227}
228
229static inline Bool
230xf86_driver_show_cursor(xf86CrtcPtr crtc)
231{
232    if (crtc->funcs->show_cursor_check)
233        return crtc->funcs->show_cursor_check(crtc);
234    crtc->funcs->show_cursor(crtc);
235    return TRUE;
236}
237
238static inline Bool
239xf86_driver_load_cursor_image(xf86CrtcPtr crtc, CARD8 *cursor_image)
240{
241    if (crtc->funcs->load_cursor_image_check)
242        return crtc->funcs->load_cursor_image_check(crtc, cursor_image);
243    crtc->funcs->load_cursor_image(crtc, cursor_image);
244    return TRUE;
245}
246
247static inline Bool
248xf86_driver_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *cursor_argb)
249{
250    if (crtc->funcs->load_cursor_argb_check)
251        return crtc->funcs->load_cursor_argb_check(crtc, cursor_argb);
252    crtc->funcs->load_cursor_argb(crtc, cursor_argb);
253    return TRUE;
254}
255
256/*
257 * Load a two color cursor into a driver that supports only ARGB cursors
258 */
259static Bool
260xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc, unsigned char *src)
261{
262    ScrnInfoPtr scrn = crtc->scrn;
263    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
264    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
265    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
266    int x, y;
267    int xin, yin;
268    int flags = cursor_info->Flags;
269    CARD32 bits;
270    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
271
272    crtc->cursor_argb = FALSE;
273
274    for (y = 0; y < cursor_info->MaxHeight; y++)
275        for (x = 0; x < cursor_info->MaxWidth; x++) {
276            xf86_crtc_rotate_coord(rotation,
277                                   cursor_info->MaxWidth,
278                                   cursor_info->MaxHeight, x, y, &xin, &yin);
279            if (get_bit(src, cursor_info, xin, yin, TRUE) ==
280                ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) {
281                if (get_bit(src, cursor_info, xin, yin, FALSE))
282                    bits = xf86_config->cursor_fg;
283                else
284                    bits = xf86_config->cursor_bg;
285            }
286            else
287                bits = 0;
288            cursor_image[y * cursor_info->MaxWidth + x] = bits;
289        }
290    return xf86_driver_load_cursor_argb(crtc, cursor_image);
291}
292
293/*
294 * Set the colors for a two-color cursor (ignore for ARGB cursors)
295 */
296static void
297xf86_set_cursor_colors(ScrnInfoPtr scrn, int bg, int fg)
298{
299    ScreenPtr screen = scrn->pScreen;
300    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
301    CursorPtr cursor = xf86CurrentCursor(screen);
302    int c;
303    CARD8 *bits = cursor ?
304        dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey, screen)
305        : NULL;
306
307    /* Save ARGB versions of these colors */
308    xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
309    xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
310
311    for (c = 0; c < xf86_config->num_crtc; c++) {
312        xf86CrtcPtr crtc = xf86_config->crtc[c];
313
314        if (crtc->enabled && !crtc->cursor_argb) {
315            if (xf86_driver_has_load_cursor_image(crtc))
316                crtc->funcs->set_cursor_colors(crtc, bg, fg);
317            else if (bits)
318                xf86_crtc_convert_cursor_to_argb(crtc, bits);
319        }
320    }
321}
322
323void
324xf86_crtc_hide_cursor(xf86CrtcPtr crtc)
325{
326    if (crtc->cursor_shown) {
327        crtc->funcs->hide_cursor(crtc);
328        crtc->cursor_shown = FALSE;
329    }
330}
331
332void
333xf86_hide_cursors(ScrnInfoPtr scrn)
334{
335    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
336    int c;
337
338    xf86_config->cursor_on = FALSE;
339    for (c = 0; c < xf86_config->num_crtc; c++) {
340        xf86CrtcPtr crtc = xf86_config->crtc[c];
341
342        if (crtc->enabled)
343            xf86_crtc_hide_cursor(crtc);
344    }
345}
346
347Bool
348xf86_crtc_show_cursor(xf86CrtcPtr crtc)
349{
350    if (!crtc->cursor_in_range) {
351        crtc->funcs->hide_cursor(crtc);
352        return TRUE;
353    }
354
355    if (!crtc->cursor_shown)
356        crtc->cursor_shown = xf86_driver_show_cursor(crtc);
357
358    return crtc->cursor_shown;
359}
360
361Bool
362xf86_show_cursors(ScrnInfoPtr scrn)
363{
364    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
365    int c;
366
367    xf86_config->cursor_on = TRUE;
368    for (c = 0; c < xf86_config->num_crtc; c++) {
369        xf86CrtcPtr crtc = xf86_config->crtc[c];
370
371        if (crtc->enabled && !xf86_crtc_show_cursor(crtc))
372            return FALSE;
373    }
374
375    return TRUE;
376}
377
378static void
379xf86_crtc_transform_cursor_position(xf86CrtcPtr crtc, int *x, int *y)
380{
381    ScrnInfoPtr scrn = crtc->scrn;
382    ScreenPtr screen = scrn->pScreen;
383    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
384    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
385    xf86CursorScreenPtr ScreenPriv =
386        (xf86CursorScreenPtr) dixLookupPrivate(&screen->devPrivates,
387                                               xf86CursorScreenKey);
388    int dx, dy, t;
389    Bool swap_reflection = FALSE;
390
391    *x = *x - crtc->x + ScreenPriv->HotX;
392    *y = *y - crtc->y + ScreenPriv->HotY;
393
394    switch (crtc->rotation & 0xf) {
395    case RR_Rotate_0:
396        break;
397    case RR_Rotate_90:
398        t = *x;
399        *x = *y;
400        *y = crtc->mode.VDisplay - t - 1;
401        swap_reflection = TRUE;
402        break;
403    case RR_Rotate_180:
404        *x = crtc->mode.HDisplay - *x - 1;
405        *y = crtc->mode.VDisplay - *y - 1;
406        break;
407    case RR_Rotate_270:
408        t = *x;
409        *x = crtc->mode.HDisplay - *y - 1;
410        *y = t;
411        swap_reflection = TRUE;
412        break;
413    }
414
415    if (swap_reflection) {
416        if (crtc->rotation & RR_Reflect_Y)
417            *x = crtc->mode.HDisplay - *x - 1;
418        if (crtc->rotation & RR_Reflect_X)
419            *y = crtc->mode.VDisplay - *y - 1;
420    } else {
421        if (crtc->rotation & RR_Reflect_X)
422            *x = crtc->mode.HDisplay - *x - 1;
423        if (crtc->rotation & RR_Reflect_Y)
424            *y = crtc->mode.VDisplay - *y - 1;
425    }
426
427    /*
428     * Transform position of cursor upper left corner
429     */
430    xf86_crtc_rotate_coord_back(crtc->rotation, cursor_info->MaxWidth,
431                                cursor_info->MaxHeight, ScreenPriv->HotX,
432                                ScreenPriv->HotY, &dx, &dy);
433    *x -= dx;
434    *y -= dy;
435}
436
437static void
438xf86_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
439{
440    ScrnInfoPtr scrn = crtc->scrn;
441    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
442    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
443    DisplayModePtr mode = &crtc->mode;
444    int crtc_x = x, crtc_y = y;
445
446    /*
447     * Transform position of cursor on screen
448     */
449    if (crtc->rotation != RR_Rotate_0)
450        xf86_crtc_transform_cursor_position(crtc, &crtc_x, &crtc_y);
451    else {
452        crtc_x -= crtc->x;
453        crtc_y -= crtc->y;
454    }
455
456    /*
457     * Disable the cursor when it is outside the viewport
458     */
459    if (crtc_x >= mode->HDisplay || crtc_y >= mode->VDisplay ||
460        crtc_x <= -cursor_info->MaxWidth || crtc_y <= -cursor_info->MaxHeight) {
461        crtc->cursor_in_range = FALSE;
462        xf86_crtc_hide_cursor(crtc);
463    } else {
464        crtc->cursor_in_range = TRUE;
465        if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorPosition)
466            crtc->funcs->set_cursor_position(crtc, x, y);
467        else
468            crtc->funcs->set_cursor_position(crtc, crtc_x, crtc_y);
469        xf86_crtc_show_cursor(crtc);
470    }
471}
472
473static void
474xf86_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
475{
476    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
477    int c;
478
479    /* undo what xf86HWCurs did to the coordinates */
480    x += scrn->frameX0;
481    y += scrn->frameY0;
482    for (c = 0; c < xf86_config->num_crtc; c++) {
483        xf86CrtcPtr crtc = xf86_config->crtc[c];
484
485        if (crtc->enabled)
486            xf86_crtc_set_cursor_position(crtc, x, y);
487    }
488}
489
490/*
491 * Load a two-color cursor into a crtc, performing rotation as needed
492 */
493static Bool
494xf86_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *src)
495{
496    ScrnInfoPtr scrn = crtc->scrn;
497    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
498    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
499    CARD8 *cursor_image;
500    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
501
502    crtc->cursor_argb = FALSE;
503
504    if (rotation == RR_Rotate_0)
505        cursor_image = src;
506    else {
507        int x, y;
508        int xin, yin;
509        int stride = cursor_info->MaxWidth >> 2;
510
511        cursor_image = xf86_config->cursor_image;
512        memset(cursor_image, 0, cursor_info->MaxHeight * stride);
513
514        for (y = 0; y < cursor_info->MaxHeight; y++)
515            for (x = 0; x < cursor_info->MaxWidth; x++) {
516                xf86_crtc_rotate_coord(rotation,
517                                       cursor_info->MaxWidth,
518                                       cursor_info->MaxHeight,
519                                       x, y, &xin, &yin);
520                if (get_bit(src, cursor_info, xin, yin, FALSE))
521                    set_bit(cursor_image, cursor_info, x, y, FALSE);
522                if (get_bit(src, cursor_info, xin, yin, TRUE))
523                    set_bit(cursor_image, cursor_info, x, y, TRUE);
524            }
525    }
526    return xf86_driver_load_cursor_image(crtc, cursor_image);
527}
528
529/*
530 * Load a cursor image into all active CRTCs
531 */
532static Bool
533xf86_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
534{
535    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
536    int c;
537
538    xf86_config->cursor = xf86CurrentCursor(scrn->pScreen);
539    for (c = 0; c < xf86_config->num_crtc; c++) {
540        xf86CrtcPtr crtc = xf86_config->crtc[c];
541
542        if (crtc->enabled) {
543            if (xf86_driver_has_load_cursor_image(crtc)) {
544                if (!xf86_crtc_load_cursor_image(crtc, src))
545                    return FALSE;
546            } else if (xf86_driver_has_load_cursor_argb(crtc)) {
547                if (!xf86_crtc_convert_cursor_to_argb(crtc, src))
548                    return FALSE;
549            } else
550                return FALSE;
551        }
552    }
553    return TRUE;
554}
555
556static Bool
557xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
558{
559    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
560    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
561    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
562    int c;
563
564    if (cursor->bits->width > cursor_info->MaxWidth ||
565        cursor->bits->height > cursor_info->MaxHeight)
566        return FALSE;
567
568    for (c = 0; c < xf86_config->num_crtc; c++) {
569        xf86CrtcPtr crtc = xf86_config->crtc[c];
570
571        if (!crtc->enabled)
572            continue;
573
574        if (crtc->transformPresent)
575            return FALSE;
576    }
577
578    return TRUE;
579}
580
581static Bool
582xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor)
583{
584    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
585    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
586    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
587
588    if (!xf86_use_hw_cursor(screen, cursor))
589        return FALSE;
590
591    /* Make sure ARGB support is available */
592    if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0)
593        return FALSE;
594
595    return TRUE;
596}
597
598static Bool
599xf86_crtc_load_cursor_argb(xf86CrtcPtr crtc, CursorPtr cursor)
600{
601    ScrnInfoPtr scrn = crtc->scrn;
602    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
603    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
604    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
605    CARD32 *cursor_source = (CARD32 *) cursor->bits->argb;
606    int x, y;
607    int xin, yin;
608    CARD32 bits;
609    int source_width = cursor->bits->width;
610    int source_height = cursor->bits->height;
611    int image_width = cursor_info->MaxWidth;
612    int image_height = cursor_info->MaxHeight;
613    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
614
615    for (y = 0; y < image_height; y++)
616        for (x = 0; x < image_width; x++) {
617            xf86_crtc_rotate_coord(rotation, image_width, image_height, x, y,
618                                   &xin, &yin);
619            if (xin < source_width && yin < source_height)
620                bits = cursor_source[yin * source_width + xin];
621            else
622                bits = 0;
623            cursor_image[y * image_width + x] = bits;
624        }
625
626    return xf86_driver_load_cursor_argb(crtc, cursor_image);
627}
628
629static Bool
630xf86_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
631{
632    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
633    int c;
634
635    xf86_config->cursor = cursor;
636    for (c = 0; c < xf86_config->num_crtc; c++) {
637        xf86CrtcPtr crtc = xf86_config->crtc[c];
638
639        if (crtc->enabled)
640            if (!xf86_crtc_load_cursor_argb(crtc, cursor))
641                return FALSE;
642    }
643    return TRUE;
644}
645
646Bool
647xf86_cursors_init(ScreenPtr screen, int max_width, int max_height, int flags)
648{
649    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
650    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
651    xf86CursorInfoPtr cursor_info;
652
653    cursor_info = xf86CreateCursorInfoRec();
654    if (!cursor_info)
655        return FALSE;
656
657    xf86_config->cursor_image = malloc(max_width * max_height * 4);
658
659    if (!xf86_config->cursor_image) {
660        xf86DestroyCursorInfoRec(cursor_info);
661        return FALSE;
662    }
663
664    xf86_config->cursor_info = cursor_info;
665
666    cursor_info->MaxWidth = max_width;
667    cursor_info->MaxHeight = max_height;
668    cursor_info->Flags = flags;
669
670    cursor_info->SetCursorColors = xf86_set_cursor_colors;
671    cursor_info->SetCursorPosition = xf86_set_cursor_position;
672    cursor_info->LoadCursorImageCheck = xf86_load_cursor_image;
673    cursor_info->HideCursor = xf86_hide_cursors;
674    cursor_info->ShowCursorCheck = xf86_show_cursors;
675    cursor_info->UseHWCursor = xf86_use_hw_cursor;
676    if (flags & HARDWARE_CURSOR_ARGB) {
677        cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb;
678        cursor_info->LoadCursorARGBCheck = xf86_load_cursor_argb;
679    }
680
681    xf86_hide_cursors(scrn);
682
683    return xf86InitCursor(screen, cursor_info);
684}
685
686/**
687 * Clean up CRTC-based cursor code
688 */
689void
690xf86_cursors_fini(ScreenPtr screen)
691{
692    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
693    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
694
695    if (xf86_config->cursor_info) {
696        xf86DestroyCursorInfoRec(xf86_config->cursor_info);
697        xf86_config->cursor_info = NULL;
698    }
699    free(xf86_config->cursor_image);
700    xf86_config->cursor_image = NULL;
701    xf86_config->cursor = NULL;
702}
703