1
2#ifdef HAVE_XORG_CONFIG_H
3#include <xorg-config.h>
4#endif
5
6#include "xf86.h"
7#include "xf86CursorPriv.h"
8#include "colormapst.h"
9#include "cursorstr.h"
10
11/* FIXME: This was added with the ABI change of the miPointerSpriteFuncs for
12 * MPX.
13 * inputInfo is needed to pass the core pointer as the default argument into
14 * the cursor functions.
15 *
16 * Externing inputInfo is not the nice way to do it but it works.
17 */
18#include "inputstr.h"
19
20DevPrivateKeyRec xf86CursorScreenKeyRec;
21
22/* sprite functions */
23
24static Bool xf86CursorRealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr);
25static Bool xf86CursorUnrealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr);
26static void xf86CursorSetCursor(DeviceIntPtr, ScreenPtr, CursorPtr, int, int);
27static void xf86CursorMoveCursor(DeviceIntPtr, ScreenPtr, int, int);
28static Bool xf86DeviceCursorInitialize(DeviceIntPtr, ScreenPtr);
29static void xf86DeviceCursorCleanup(DeviceIntPtr, ScreenPtr);
30
31static miPointerSpriteFuncRec xf86CursorSpriteFuncs = {
32    xf86CursorRealizeCursor,
33    xf86CursorUnrealizeCursor,
34    xf86CursorSetCursor,
35    xf86CursorMoveCursor,
36    xf86DeviceCursorInitialize,
37    xf86DeviceCursorCleanup
38};
39
40/* Screen functions */
41
42static void xf86CursorInstallColormap(ColormapPtr);
43static void xf86CursorRecolorCursor(DeviceIntPtr pDev, ScreenPtr, CursorPtr,
44                                    Bool);
45static Bool xf86CursorCloseScreen(ScreenPtr);
46static void xf86CursorQueryBestSize(int, unsigned short *, unsigned short *,
47                                    ScreenPtr);
48
49/* ScrnInfoRec functions */
50
51static void xf86CursorEnableDisableFBAccess(ScrnInfoPtr, Bool);
52static Bool xf86CursorSwitchMode(ScrnInfoPtr, DisplayModePtr);
53
54Bool
55xf86InitCursor(ScreenPtr pScreen, xf86CursorInfoPtr infoPtr)
56{
57    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
58    xf86CursorScreenPtr ScreenPriv;
59    miPointerScreenPtr PointPriv;
60
61    if (!xf86InitHardwareCursor(pScreen, infoPtr))
62        return FALSE;
63
64    if (!dixRegisterPrivateKey(&xf86CursorScreenKeyRec, PRIVATE_SCREEN, 0))
65        return FALSE;
66
67    ScreenPriv = calloc(1, sizeof(xf86CursorScreenRec));
68    if (!ScreenPriv)
69        return FALSE;
70
71    dixSetPrivate(&pScreen->devPrivates, xf86CursorScreenKey, ScreenPriv);
72
73    ScreenPriv->SWCursor = TRUE;
74    ScreenPriv->isUp = FALSE;
75    ScreenPriv->CurrentCursor = NULL;
76    ScreenPriv->CursorInfoPtr = infoPtr;
77    ScreenPriv->PalettedCursor = FALSE;
78    ScreenPriv->pInstalledMap = NULL;
79
80    ScreenPriv->CloseScreen = pScreen->CloseScreen;
81    pScreen->CloseScreen = xf86CursorCloseScreen;
82    ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
83    pScreen->QueryBestSize = xf86CursorQueryBestSize;
84    ScreenPriv->RecolorCursor = pScreen->RecolorCursor;
85    pScreen->RecolorCursor = xf86CursorRecolorCursor;
86
87    if ((infoPtr->pScrn->bitsPerPixel == 8) &&
88        !(infoPtr->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP)) {
89        ScreenPriv->InstallColormap = pScreen->InstallColormap;
90        pScreen->InstallColormap = xf86CursorInstallColormap;
91        ScreenPriv->PalettedCursor = TRUE;
92    }
93
94    PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
95
96    ScreenPriv->showTransparent = PointPriv->showTransparent;
97    if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT)
98        PointPriv->showTransparent = TRUE;
99    else
100        PointPriv->showTransparent = FALSE;
101    ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
102    PointPriv->spriteFuncs = &xf86CursorSpriteFuncs;
103
104    ScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
105    ScreenPriv->SwitchMode = pScrn->SwitchMode;
106
107    ScreenPriv->ForceHWCursorCount = 0;
108    ScreenPriv->HWCursorForced = FALSE;
109
110    pScrn->EnableDisableFBAccess = xf86CursorEnableDisableFBAccess;
111    if (pScrn->SwitchMode)
112        pScrn->SwitchMode = xf86CursorSwitchMode;
113
114    return TRUE;
115}
116
117/***** Screen functions *****/
118
119static Bool
120xf86CursorCloseScreen(ScreenPtr pScreen)
121{
122    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
123    miPointerScreenPtr PointPriv =
124        (miPointerScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
125                                              miPointerScreenKey);
126    xf86CursorScreenPtr ScreenPriv =
127        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
128                                               xf86CursorScreenKey);
129
130    if (ScreenPriv->isUp && pScrn->vtSema)
131        xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y);
132
133    if (ScreenPriv->CurrentCursor)
134        FreeCursor(ScreenPriv->CurrentCursor, None);
135
136    pScreen->CloseScreen = ScreenPriv->CloseScreen;
137    pScreen->QueryBestSize = ScreenPriv->QueryBestSize;
138    pScreen->RecolorCursor = ScreenPriv->RecolorCursor;
139    if (ScreenPriv->InstallColormap)
140        pScreen->InstallColormap = ScreenPriv->InstallColormap;
141
142    PointPriv->spriteFuncs = ScreenPriv->spriteFuncs;
143    PointPriv->showTransparent = ScreenPriv->showTransparent;
144
145    pScrn->EnableDisableFBAccess = ScreenPriv->EnableDisableFBAccess;
146    pScrn->SwitchMode = ScreenPriv->SwitchMode;
147
148    free(ScreenPriv->transparentData);
149    free(ScreenPriv);
150
151    return (*pScreen->CloseScreen) (pScreen);
152}
153
154static void
155xf86CursorQueryBestSize(int class,
156                        unsigned short *width,
157                        unsigned short *height, ScreenPtr pScreen)
158{
159    xf86CursorScreenPtr ScreenPriv =
160        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
161                                               xf86CursorScreenKey);
162
163    if (class == CursorShape) {
164        if (*width > ScreenPriv->CursorInfoPtr->MaxWidth)
165            *width = ScreenPriv->CursorInfoPtr->MaxWidth;
166        if (*height > ScreenPriv->CursorInfoPtr->MaxHeight)
167            *height = ScreenPriv->CursorInfoPtr->MaxHeight;
168    }
169    else
170        (*ScreenPriv->QueryBestSize) (class, width, height, pScreen);
171}
172
173static void
174xf86CursorInstallColormap(ColormapPtr pMap)
175{
176    xf86CursorScreenPtr ScreenPriv =
177        (xf86CursorScreenPtr) dixLookupPrivate(&pMap->pScreen->devPrivates,
178                                               xf86CursorScreenKey);
179
180    ScreenPriv->pInstalledMap = pMap;
181
182    (*ScreenPriv->InstallColormap) (pMap);
183}
184
185static void
186xf86CursorRecolorCursor(DeviceIntPtr pDev,
187                        ScreenPtr pScreen, CursorPtr pCurs, Bool displayed)
188{
189    xf86CursorScreenPtr ScreenPriv =
190        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
191                                               xf86CursorScreenKey);
192
193    if (!displayed)
194        return;
195
196    if (ScreenPriv->SWCursor)
197        (*ScreenPriv->RecolorCursor) (pDev, pScreen, pCurs, displayed);
198    else
199        xf86RecolorCursor(pScreen, pCurs, displayed);
200}
201
202/***** ScrnInfoRec functions *********/
203
204static void
205xf86CursorEnableDisableFBAccess(ScrnInfoPtr pScrn, Bool enable)
206{
207    DeviceIntPtr pDev = inputInfo.pointer;
208
209    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
210    xf86CursorScreenPtr ScreenPriv =
211        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
212                                               xf86CursorScreenKey);
213
214    if (!enable && ScreenPriv->CurrentCursor != NullCursor) {
215        CursorPtr currentCursor = RefCursor(ScreenPriv->CurrentCursor);
216
217        xf86CursorSetCursor(pDev, pScreen, NullCursor, ScreenPriv->x,
218                            ScreenPriv->y);
219        ScreenPriv->isUp = FALSE;
220        ScreenPriv->SWCursor = TRUE;
221        ScreenPriv->SavedCursor = currentCursor;
222    }
223
224    if (ScreenPriv->EnableDisableFBAccess)
225        (*ScreenPriv->EnableDisableFBAccess) (pScrn, enable);
226
227    if (enable && ScreenPriv->SavedCursor) {
228        /*
229         * Re-set current cursor so drivers can react to FB access having been
230         * temporarily disabled.
231         */
232        xf86CursorSetCursor(pDev, pScreen, ScreenPriv->SavedCursor,
233                            ScreenPriv->x, ScreenPriv->y);
234        UnrefCursor(ScreenPriv->SavedCursor);
235        ScreenPriv->SavedCursor = NULL;
236    }
237}
238
239static Bool
240xf86CursorSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
241{
242    Bool ret;
243    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
244    xf86CursorScreenPtr ScreenPriv =
245        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
246                                               xf86CursorScreenKey);
247
248    if (ScreenPriv->isUp) {
249        xf86SetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y);
250        ScreenPriv->isUp = FALSE;
251    }
252
253    ret = (*ScreenPriv->SwitchMode) (pScrn, mode);
254
255    /*
256     * Cannot restore cursor here because the new frame[XY][01] haven't been
257     * calculated yet.  However, because the hardware cursor was removed above,
258     * ensure the cursor is repainted by miPointerWarpCursor().
259     */
260    ScreenPriv->CursorToRestore = ScreenPriv->CurrentCursor;
261    miPointerSetWaitForUpdate(pScreen, FALSE);  /* Force cursor repaint */
262
263    return ret;
264}
265
266/****** miPointerSpriteFunctions *******/
267
268static Bool
269xf86CursorRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs)
270{
271    xf86CursorScreenPtr ScreenPriv =
272        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
273                                               xf86CursorScreenKey);
274
275    if (CursorRefCount(pCurs) <= 1)
276        dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen,
277                            NULL);
278
279    return (*ScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCurs);
280}
281
282static Bool
283xf86CursorUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs)
284{
285    xf86CursorScreenPtr ScreenPriv =
286        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
287                                               xf86CursorScreenKey);
288
289    if (CursorRefCount(pCurs) <= 1) {
290        free(dixLookupScreenPrivate
291             (&pCurs->devPrivates, CursorScreenKey, pScreen));
292        dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen,
293                            NULL);
294    }
295
296    return (*ScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCurs);
297}
298
299static void
300xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs,
301                    int x, int y)
302{
303    xf86CursorScreenPtr ScreenPriv =
304        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
305                                               xf86CursorScreenKey);
306    xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr;
307
308    if (pCurs == NullCursor) {  /* means we're supposed to remove the cursor */
309        if (ScreenPriv->SWCursor ||
310            !(GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer))
311            (*ScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, NullCursor, x,
312                                                   y);
313        else if (ScreenPriv->isUp) {
314            xf86SetCursor(pScreen, NullCursor, x, y);
315            ScreenPriv->isUp = FALSE;
316        }
317        if (ScreenPriv->CurrentCursor)
318            FreeCursor(ScreenPriv->CurrentCursor, None);
319        ScreenPriv->CurrentCursor = NullCursor;
320        return;
321    }
322
323    /* only update for VCP, otherwise we get cursor jumps when removing a
324       sprite. The second cursor is never HW rendered anyway. */
325    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer) {
326        CursorPtr cursor = RefCursor(pCurs);
327        if (ScreenPriv->CurrentCursor)
328            FreeCursor(ScreenPriv->CurrentCursor, None);
329        ScreenPriv->CurrentCursor = cursor;
330        ScreenPriv->x = x;
331        ScreenPriv->y = y;
332        ScreenPriv->CursorToRestore = NULL;
333        ScreenPriv->HotX = cursor->bits->xhot;
334        ScreenPriv->HotY = cursor->bits->yhot;
335
336        if (!infoPtr->pScrn->vtSema) {
337            cursor = RefCursor(cursor);
338            if (ScreenPriv->SavedCursor)
339                FreeCursor(ScreenPriv->SavedCursor, None);
340            ScreenPriv->SavedCursor = cursor;
341            return;
342        }
343
344        if (infoPtr->pScrn->vtSema &&
345            (ScreenPriv->ForceHWCursorCount ||
346             xf86CheckHWCursor(pScreen, cursor, infoPtr))) {
347
348            if (ScreenPriv->SWCursor)   /* remove the SW cursor */
349                (*ScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen,
350                                                       NullCursor, x, y);
351
352            if (xf86SetCursor(pScreen, cursor, x, y)) {
353                ScreenPriv->SWCursor = FALSE;
354                ScreenPriv->isUp = TRUE;
355
356                miPointerSetWaitForUpdate(pScreen, !infoPtr->pScrn->silkenMouse);
357                return;
358            }
359        }
360
361        miPointerSetWaitForUpdate(pScreen, TRUE);
362
363        if (ScreenPriv->isUp) {
364            /* Remove the HW cursor, or make it transparent */
365            if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT) {
366                xf86SetTransparentCursor(pScreen);
367            }
368            else {
369                xf86SetCursor(pScreen, NullCursor, x, y);
370                ScreenPriv->isUp = FALSE;
371            }
372        }
373
374        if (!ScreenPriv->SWCursor)
375            ScreenPriv->SWCursor = TRUE;
376
377    }
378
379    if (pCurs->bits->emptyMask && !ScreenPriv->showTransparent)
380        pCurs = NullCursor;
381
382    (*ScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCurs, x, y);
383}
384
385/* Re-set the current cursor. This will switch between hardware and software
386 * cursor depending on whether hardware cursor is currently supported
387 * according to the driver.
388 */
389void
390xf86CursorResetCursor(ScreenPtr pScreen)
391{
392    xf86CursorScreenPtr ScreenPriv;
393
394    if (!inputInfo.pointer)
395        return;
396
397    if (!dixPrivateKeyRegistered(xf86CursorScreenKey))
398        return;
399
400    ScreenPriv = (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
401                                                        xf86CursorScreenKey);
402    if (!ScreenPriv)
403        return;
404
405    xf86CursorSetCursor(inputInfo.pointer, pScreen, ScreenPriv->CurrentCursor,
406                        ScreenPriv->x, ScreenPriv->y);
407}
408
409static void
410xf86CursorMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
411{
412    xf86CursorScreenPtr ScreenPriv =
413        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
414                                               xf86CursorScreenKey);
415
416    /* only update coordinate state for first sprite, otherwise we get jumps
417       when removing a sprite. The second sprite is never HW rendered anyway */
418    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer) {
419        ScreenPriv->x = x;
420        ScreenPriv->y = y;
421
422        if (ScreenPriv->CursorToRestore)
423            xf86CursorSetCursor(pDev, pScreen, ScreenPriv->CursorToRestore, x,
424                                y);
425        else if (ScreenPriv->SWCursor)
426            (*ScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
427        else if (ScreenPriv->isUp)
428            xf86MoveCursor(pScreen, x, y);
429    }
430    else
431        (*ScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
432}
433
434void
435xf86ForceHWCursor(ScreenPtr pScreen, Bool on)
436{
437    DeviceIntPtr pDev = inputInfo.pointer;
438    xf86CursorScreenPtr ScreenPriv =
439        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
440                                               xf86CursorScreenKey);
441
442    if (on) {
443        if (ScreenPriv->ForceHWCursorCount++ == 0) {
444            if (ScreenPriv->SWCursor && ScreenPriv->CurrentCursor) {
445                ScreenPriv->HWCursorForced = TRUE;
446                xf86CursorSetCursor(pDev, pScreen, ScreenPriv->CurrentCursor,
447                                    ScreenPriv->x, ScreenPriv->y);
448            }
449            else
450                ScreenPriv->HWCursorForced = FALSE;
451        }
452    }
453    else {
454        if (--ScreenPriv->ForceHWCursorCount == 0) {
455            if (ScreenPriv->HWCursorForced && ScreenPriv->CurrentCursor)
456                xf86CursorSetCursor(pDev, pScreen, ScreenPriv->CurrentCursor,
457                                    ScreenPriv->x, ScreenPriv->y);
458        }
459    }
460}
461
462CursorPtr
463xf86CurrentCursor(ScreenPtr pScreen)
464{
465    xf86CursorScreenPtr ScreenPriv;
466
467    if (pScreen->is_output_secondary)
468        pScreen = pScreen->current_primary;
469
470    ScreenPriv = dixLookupPrivate(&pScreen->devPrivates, xf86CursorScreenKey);
471    return ScreenPriv->CurrentCursor;
472}
473
474xf86CursorInfoPtr
475xf86CreateCursorInfoRec(void)
476{
477    return calloc(1, sizeof(xf86CursorInfoRec));
478}
479
480void
481xf86DestroyCursorInfoRec(xf86CursorInfoPtr infoPtr)
482{
483    free(infoPtr);
484}
485
486/**
487 * New cursor has been created. Do your initalizations here.
488 */
489static Bool
490xf86DeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
491{
492    int ret;
493    xf86CursorScreenPtr ScreenPriv =
494        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
495                                               xf86CursorScreenKey);
496
497    /* Init SW cursor */
498    ret = (*ScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen);
499
500    return ret;
501}
502
503/**
504 * Cursor has been removed. Clean up after yourself.
505 */
506static void
507xf86DeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
508{
509    xf86CursorScreenPtr ScreenPriv =
510        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
511                                               xf86CursorScreenKey);
512
513    /* Clean up SW cursor */
514    (*ScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen);
515}
516