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