xf86Cursors.c revision f7df2e56
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#else
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30#endif
31
32#include <stddef.h>
33#include <string.h>
34#include <stdio.h>
35
36#include <X11/Xarch.h>
37#include "xf86.h"
38#include "xf86DDC.h"
39#include "xf86Crtc.h"
40#include "xf86Modes.h"
41#include "xf86RandR12.h"
42#include "xf86CursorPriv.h"
43#include "X11/extensions/render.h"
44#include "X11/extensions/dpmsconst.h"
45#include "X11/Xatom.h"
46#include "picturestr.h"
47#include "cursorstr.h"
48#include "inputstr.h"
49
50/*
51 * Returns the rotation being performed by the server.  If the driver indicates
52 * that it's handling the screen transform, then this returns RR_Rotate_0.
53 */
54static Rotation
55xf86_crtc_cursor_rotation(xf86CrtcPtr crtc)
56{
57    if (crtc->driverIsPerformingTransform)
58        return RR_Rotate_0;
59    return crtc->rotation;
60}
61
62/*
63 * Given a screen coordinate, rotate back to a cursor source coordinate
64 */
65static void
66xf86_crtc_rotate_coord(Rotation rotation,
67                       int width,
68                       int height, int x_dst, int y_dst, int *x_src, int *y_src)
69{
70    int t;
71
72    switch (rotation & 0xf) {
73    case RR_Rotate_0:
74        break;
75    case RR_Rotate_90:
76        t = x_dst;
77        x_dst = height - y_dst - 1;
78        y_dst = t;
79        break;
80    case RR_Rotate_180:
81        x_dst = width - x_dst - 1;
82        y_dst = height - y_dst - 1;
83        break;
84    case RR_Rotate_270:
85        t = x_dst;
86        x_dst = y_dst;
87        y_dst = width - t - 1;
88        break;
89    }
90    if (rotation & RR_Reflect_X)
91        x_dst = width - x_dst - 1;
92    if (rotation & RR_Reflect_Y)
93        y_dst = height - y_dst - 1;
94    *x_src = x_dst;
95    *y_src = y_dst;
96}
97
98/*
99 * Given a cursor source  coordinate, rotate to a screen coordinate
100 */
101static void
102xf86_crtc_rotate_coord_back(Rotation rotation,
103                            int width,
104                            int height,
105                            int x_dst, int y_dst, int *x_src, int *y_src)
106{
107    int t;
108
109    if (rotation & RR_Reflect_X)
110        x_dst = width - x_dst - 1;
111    if (rotation & RR_Reflect_Y)
112        y_dst = height - y_dst - 1;
113
114    switch (rotation & 0xf) {
115    case RR_Rotate_0:
116        break;
117    case RR_Rotate_90:
118        t = x_dst;
119        x_dst = y_dst;
120        y_dst = width - t - 1;
121        break;
122    case RR_Rotate_180:
123        x_dst = width - x_dst - 1;
124        y_dst = height - y_dst - 1;
125        break;
126    case RR_Rotate_270:
127        t = x_dst;
128        x_dst = height - y_dst - 1;
129        y_dst = t;
130        break;
131    }
132    *x_src = x_dst;
133    *y_src = y_dst;
134}
135
136struct cursor_bit {
137    CARD8 *byte;
138    char bitpos;
139};
140
141/*
142 * Convert an x coordinate to a position within the cursor bitmap
143 */
144static struct cursor_bit
145cursor_bitpos(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y,
146              Bool mask)
147{
148    const int flags = cursor_info->Flags;
149    const Bool interleaved =
150        ! !(flags & (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
151                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
152                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
153                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
154                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
155    const int width = cursor_info->MaxWidth;
156    const int height = cursor_info->MaxHeight;
157    const int stride = interleaved ? width / 4 : width / 8;
158
159    struct cursor_bit ret;
160
161    image += y * stride;
162
163    if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
164        mask = !mask;
165    if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
166        x = (x & ~3) | (3 - (x & 3));
167    if (((flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) == 0) ==
168        (X_BYTE_ORDER == X_BIG_ENDIAN))
169        x = (x & ~7) | (7 - (x & 7));
170    if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1)
171        x = (x << 1) + mask;
172    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8)
173        x = ((x & ~7) << 1) | (mask << 3) | (x & 7);
174    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16)
175        x = ((x & ~15) << 1) | (mask << 4) | (x & 15);
176    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32)
177        x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
178    else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
179        x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
180    else if (mask)
181        image += stride * height;
182
183    ret.byte = image + (x / 8);
184    ret.bitpos = x & 7;
185
186    return ret;
187}
188
189/*
190 * Fetch one bit from a cursor bitmap
191 */
192static CARD8
193get_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
194{
195    struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
196
197    return (*bit.byte >> bit.bitpos) & 1;
198}
199
200/*
201 * Set one bit in a cursor bitmap
202 */
203static void
204set_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
205{
206    struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
207
208    *bit.byte |= 1 << bit.bitpos;
209}
210
211/*
212 * Wrappers to deal with API compatibility with drivers that don't expose
213 * load_cursor_*_check
214 */
215static inline Bool
216xf86_driver_has_load_cursor_image(xf86CrtcPtr crtc)
217{
218    return crtc->funcs->load_cursor_image_check || crtc->funcs->load_cursor_image;
219}
220
221static inline Bool
222xf86_driver_has_load_cursor_argb(xf86CrtcPtr crtc)
223{
224    return crtc->funcs->load_cursor_argb_check || crtc->funcs->load_cursor_argb;
225}
226
227static inline Bool
228xf86_driver_load_cursor_image(xf86CrtcPtr crtc, CARD8 *cursor_image)
229{
230    if (crtc->funcs->load_cursor_image_check)
231        return crtc->funcs->load_cursor_image_check(crtc, cursor_image);
232    crtc->funcs->load_cursor_image(crtc, cursor_image);
233    return TRUE;
234}
235
236static inline Bool
237xf86_driver_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *cursor_argb)
238{
239    if (crtc->funcs->load_cursor_argb_check)
240        return crtc->funcs->load_cursor_argb_check(crtc, cursor_argb);
241    crtc->funcs->load_cursor_argb(crtc, cursor_argb);
242    return TRUE;
243}
244
245/*
246 * Load a two color cursor into a driver that supports only ARGB cursors
247 */
248static Bool
249xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc, unsigned char *src)
250{
251    ScrnInfoPtr scrn = crtc->scrn;
252    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
253    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
254    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
255    int x, y;
256    int xin, yin;
257    int flags = cursor_info->Flags;
258    CARD32 bits;
259    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
260
261    crtc->cursor_argb = FALSE;
262
263    for (y = 0; y < cursor_info->MaxHeight; y++)
264        for (x = 0; x < cursor_info->MaxWidth; x++) {
265            xf86_crtc_rotate_coord(rotation,
266                                   cursor_info->MaxWidth,
267                                   cursor_info->MaxHeight, x, y, &xin, &yin);
268            if (get_bit(src, cursor_info, xin, yin, TRUE) ==
269                ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) {
270                if (get_bit(src, cursor_info, xin, yin, FALSE))
271                    bits = xf86_config->cursor_fg;
272                else
273                    bits = xf86_config->cursor_bg;
274            }
275            else
276                bits = 0;
277            cursor_image[y * cursor_info->MaxWidth + x] = bits;
278        }
279    return xf86_driver_load_cursor_argb(crtc, cursor_image);
280}
281
282/*
283 * Set the colors for a two-color cursor (ignore for ARGB cursors)
284 */
285static void
286xf86_set_cursor_colors(ScrnInfoPtr scrn, int bg, int fg)
287{
288    ScreenPtr screen = scrn->pScreen;
289    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
290    CursorPtr cursor = xf86_config->cursor;
291    int c;
292    CARD8 *bits = cursor ?
293        dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey, screen)
294        : NULL;
295
296    /* Save ARGB versions of these colors */
297    xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
298    xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
299
300    for (c = 0; c < xf86_config->num_crtc; c++) {
301        xf86CrtcPtr crtc = xf86_config->crtc[c];
302
303        if (crtc->enabled && !crtc->cursor_argb) {
304            if (xf86_driver_has_load_cursor_image(crtc))
305                crtc->funcs->set_cursor_colors(crtc, bg, fg);
306            else if (bits)
307                xf86_crtc_convert_cursor_to_argb(crtc, bits);
308        }
309    }
310}
311
312static void
313xf86_crtc_hide_cursor(xf86CrtcPtr crtc)
314{
315    if (crtc->cursor_shown) {
316        crtc->funcs->hide_cursor(crtc);
317        crtc->cursor_shown = FALSE;
318    }
319}
320
321void
322xf86_hide_cursors(ScrnInfoPtr scrn)
323{
324    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
325    int c;
326
327    xf86_config->cursor_on = FALSE;
328    for (c = 0; c < xf86_config->num_crtc; c++) {
329        xf86CrtcPtr crtc = xf86_config->crtc[c];
330
331        if (crtc->enabled)
332            xf86_crtc_hide_cursor(crtc);
333    }
334}
335
336static void
337xf86_crtc_show_cursor(xf86CrtcPtr crtc)
338{
339    if (!crtc->cursor_shown && crtc->cursor_in_range) {
340        crtc->funcs->show_cursor(crtc);
341        crtc->cursor_shown = TRUE;
342    }
343}
344
345void
346xf86_show_cursors(ScrnInfoPtr scrn)
347{
348    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
349    int c;
350
351    xf86_config->cursor_on = TRUE;
352    for (c = 0; c < xf86_config->num_crtc; c++) {
353        xf86CrtcPtr crtc = xf86_config->crtc[c];
354
355        if (crtc->enabled)
356            xf86_crtc_show_cursor(crtc);
357    }
358}
359
360void
361xf86CrtcTransformCursorPos(xf86CrtcPtr crtc, int *x, int *y)
362{
363    ScrnInfoPtr scrn = crtc->scrn;
364    ScreenPtr screen = scrn->pScreen;
365    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
366    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
367    xf86CursorScreenPtr ScreenPriv =
368        (xf86CursorScreenPtr) dixLookupPrivate(&screen->devPrivates,
369                                               xf86CursorScreenKey);
370    struct pict_f_vector v;
371    int dx, dy;
372
373    v.v[0] = (*x + ScreenPriv->HotX) + 0.5;
374    v.v[1] = (*y + ScreenPriv->HotY) + 0.5;
375    v.v[2] = 1;
376    pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &v);
377    /* cursor will have 0.5 added to it already so floor is sufficent */
378    *x = floor(v.v[0]);
379    *y = floor(v.v[1]);
380    /*
381     * Transform position of cursor upper left corner
382     */
383    xf86_crtc_rotate_coord_back(crtc->rotation, cursor_info->MaxWidth,
384                                cursor_info->MaxHeight, ScreenPriv->HotX,
385                                ScreenPriv->HotY, &dx, &dy);
386    *x -= dx;
387    *y -= dy;
388}
389
390static void
391xf86_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
392{
393    ScrnInfoPtr scrn = crtc->scrn;
394    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
395    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
396    DisplayModePtr mode = &crtc->mode;
397    Bool in_range;
398
399    /*
400     * Transform position of cursor on screen
401     */
402    if (crtc->transform_in_use && !crtc->driverIsPerformingTransform)
403        xf86CrtcTransformCursorPos(crtc, &x, &y);
404    else {
405        x -= crtc->x;
406        y -= crtc->y;
407    }
408
409    /*
410     * Disable the cursor when it is outside the viewport
411     */
412    in_range = TRUE;
413    if (x >= mode->HDisplay || y >= mode->VDisplay ||
414        x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight) {
415        in_range = FALSE;
416        x = 0;
417        y = 0;
418    }
419
420    crtc->cursor_in_range = in_range;
421
422    if (in_range) {
423        crtc->funcs->set_cursor_position(crtc, x, y);
424        xf86_crtc_show_cursor(crtc);
425    }
426    else
427        xf86_crtc_hide_cursor(crtc);
428}
429
430static void
431xf86_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
432{
433    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
434    int c;
435
436    /* undo what xf86HWCurs did to the coordinates */
437    x += scrn->frameX0;
438    y += scrn->frameY0;
439    for (c = 0; c < xf86_config->num_crtc; c++) {
440        xf86CrtcPtr crtc = xf86_config->crtc[c];
441
442        if (crtc->enabled)
443            xf86_crtc_set_cursor_position(crtc, x, y);
444    }
445}
446
447/*
448 * Load a two-color cursor into a crtc, performing rotation as needed
449 */
450static Bool
451xf86_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *src)
452{
453    ScrnInfoPtr scrn = crtc->scrn;
454    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
455    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
456    CARD8 *cursor_image;
457    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
458
459    crtc->cursor_argb = FALSE;
460
461    if (rotation == RR_Rotate_0)
462        cursor_image = src;
463    else {
464        int x, y;
465        int xin, yin;
466        int stride = cursor_info->MaxWidth >> 2;
467
468        cursor_image = xf86_config->cursor_image;
469        memset(cursor_image, 0, cursor_info->MaxHeight * stride);
470
471        for (y = 0; y < cursor_info->MaxHeight; y++)
472            for (x = 0; x < cursor_info->MaxWidth; x++) {
473                xf86_crtc_rotate_coord(rotation,
474                                       cursor_info->MaxWidth,
475                                       cursor_info->MaxHeight,
476                                       x, y, &xin, &yin);
477                if (get_bit(src, cursor_info, xin, yin, FALSE))
478                    set_bit(cursor_image, cursor_info, x, y, FALSE);
479                if (get_bit(src, cursor_info, xin, yin, TRUE))
480                    set_bit(cursor_image, cursor_info, x, y, TRUE);
481            }
482    }
483    return xf86_driver_load_cursor_image(crtc, cursor_image);
484}
485
486/*
487 * Load a cursor image into all active CRTCs
488 */
489static Bool
490xf86_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
491{
492    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
493    int c;
494
495    for (c = 0; c < xf86_config->num_crtc; c++) {
496        xf86CrtcPtr crtc = xf86_config->crtc[c];
497
498        if (crtc->enabled) {
499            if (xf86_driver_has_load_cursor_image(crtc)) {
500                if (!xf86_crtc_load_cursor_image(crtc, src))
501                    return FALSE;
502            } else if (xf86_driver_has_load_cursor_argb(crtc)) {
503                if (!xf86_crtc_convert_cursor_to_argb(crtc, src))
504                    return FALSE;
505            } else
506                return FALSE;
507        }
508    }
509    return TRUE;
510}
511
512static Bool
513xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
514{
515    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
516    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
517    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
518    int c;
519
520    cursor = RefCursor(cursor);
521    if (xf86_config->cursor)
522        FreeCursor(xf86_config->cursor, None);
523    xf86_config->cursor = cursor;
524
525    if (cursor->bits->width > cursor_info->MaxWidth ||
526        cursor->bits->height > cursor_info->MaxHeight)
527        return FALSE;
528
529    for (c = 0; c < xf86_config->num_crtc; c++) {
530        xf86CrtcPtr crtc = xf86_config->crtc[c];
531
532        if (!crtc->enabled)
533            continue;
534
535        if (crtc->transformPresent)
536            return FALSE;
537    }
538
539    return TRUE;
540}
541
542static Bool
543xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor)
544{
545    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
546    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
547    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
548
549    if (!xf86_use_hw_cursor(screen, cursor))
550        return FALSE;
551
552    /* Make sure ARGB support is available */
553    if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0)
554        return FALSE;
555
556    return TRUE;
557}
558
559static Bool
560xf86_crtc_load_cursor_argb(xf86CrtcPtr crtc, CursorPtr cursor)
561{
562    ScrnInfoPtr scrn = crtc->scrn;
563    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
564    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
565    CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
566    CARD32 *cursor_source = (CARD32 *) cursor->bits->argb;
567    int x, y;
568    int xin, yin;
569    CARD32 bits;
570    int source_width = cursor->bits->width;
571    int source_height = cursor->bits->height;
572    int image_width = cursor_info->MaxWidth;
573    int image_height = cursor_info->MaxHeight;
574    const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
575
576    for (y = 0; y < image_height; y++)
577        for (x = 0; x < image_width; x++) {
578            xf86_crtc_rotate_coord(rotation, image_width, image_height, x, y,
579                                   &xin, &yin);
580            if (xin < source_width && yin < source_height)
581                bits = cursor_source[yin * source_width + xin];
582            else
583                bits = 0;
584            cursor_image[y * image_width + x] = bits;
585        }
586
587    return xf86_driver_load_cursor_argb(crtc, cursor_image);
588}
589
590static Bool
591xf86_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
592{
593    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
594    int c;
595
596    for (c = 0; c < xf86_config->num_crtc; c++) {
597        xf86CrtcPtr crtc = xf86_config->crtc[c];
598
599        if (crtc->enabled)
600            if (!xf86_crtc_load_cursor_argb(crtc, cursor))
601                return FALSE;
602    }
603    return TRUE;
604}
605
606Bool
607xf86_cursors_init(ScreenPtr screen, int max_width, int max_height, int flags)
608{
609    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
610    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
611    xf86CursorInfoPtr cursor_info;
612
613    cursor_info = xf86CreateCursorInfoRec();
614    if (!cursor_info)
615        return FALSE;
616
617    xf86_config->cursor_image = malloc(max_width * max_height * 4);
618
619    if (!xf86_config->cursor_image) {
620        xf86DestroyCursorInfoRec(cursor_info);
621        return FALSE;
622    }
623
624    xf86_config->cursor_info = cursor_info;
625
626    cursor_info->MaxWidth = max_width;
627    cursor_info->MaxHeight = max_height;
628    cursor_info->Flags = flags;
629
630    cursor_info->SetCursorColors = xf86_set_cursor_colors;
631    cursor_info->SetCursorPosition = xf86_set_cursor_position;
632    cursor_info->LoadCursorImageCheck = xf86_load_cursor_image;
633    cursor_info->HideCursor = xf86_hide_cursors;
634    cursor_info->ShowCursor = xf86_show_cursors;
635    cursor_info->UseHWCursor = xf86_use_hw_cursor;
636    if (flags & HARDWARE_CURSOR_ARGB) {
637        cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb;
638        cursor_info->LoadCursorARGBCheck = xf86_load_cursor_argb;
639    }
640
641    xf86_config->cursor = NULL;
642    xf86_hide_cursors(scrn);
643
644    return xf86InitCursor(screen, cursor_info);
645}
646
647/**
648 * Called when anything on the screen is reconfigured.
649 *
650 * Reloads cursor images as needed, then adjusts cursor positions
651 * @note We assume that all hardware cursors to be loaded have already been
652 *       found to be usable by the hardware.
653 */
654
655void
656xf86_reload_cursors(ScreenPtr screen)
657{
658    ScrnInfoPtr scrn;
659    xf86CrtcConfigPtr xf86_config;
660    xf86CursorInfoPtr cursor_info;
661    CursorPtr cursor;
662    int x, y;
663    xf86CursorScreenPtr cursor_screen_priv;
664
665    /* initial mode setting will not have set a screen yet.
666       May be called before the devices are initialised.
667     */
668    if (!screen || !inputInfo.pointer)
669        return;
670    cursor_screen_priv = dixLookupPrivate(&screen->devPrivates,
671                                          xf86CursorScreenKey);
672    /* return if HW cursor is inactive, to avoid displaying two cursors */
673    if (!cursor_screen_priv || !cursor_screen_priv->isUp)
674        return;
675
676    scrn = xf86ScreenToScrn(screen);
677    xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
678
679    /* make sure the cursor code has been initialized */
680    cursor_info = xf86_config->cursor_info;
681    if (!cursor_info)
682        return;
683
684    cursor = xf86_config->cursor;
685    GetSpritePosition(inputInfo.pointer, &x, &y);
686    if (!(cursor_info->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN))
687        (*cursor_info->HideCursor) (scrn);
688
689    if (cursor) {
690        void *src =
691            dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey,
692                                   screen);
693        if (cursor->bits->argb && xf86DriverHasLoadCursorARGB(cursor_info))
694            xf86DriverLoadCursorARGB(cursor_info, cursor);
695        else if (src)
696            xf86DriverLoadCursorImage(cursor_info, src);
697
698        x += scrn->frameX0 + cursor_screen_priv->HotX;
699        y += scrn->frameY0 + cursor_screen_priv->HotY;
700        (*cursor_info->SetCursorPosition) (scrn, x, y);
701    }
702}
703
704/**
705 * Clean up CRTC-based cursor code
706 */
707void
708xf86_cursors_fini(ScreenPtr screen)
709{
710    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
711    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
712
713    if (xf86_config->cursor_info) {
714        xf86DestroyCursorInfoRec(xf86_config->cursor_info);
715        xf86_config->cursor_info = NULL;
716    }
717    free(xf86_config->cursor_image);
718    xf86_config->cursor_image = NULL;
719    if (xf86_config->cursor) {
720        FreeCursor(xf86_config->cursor, None);
721        xf86_config->cursor = NULL;
722    }
723}
724