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
20 DevPrivateKeyRec xf86CursorScreenKeyRec;
21
22 /* sprite functions */
23
24 static Bool xf86CursorRealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr);
25 static Bool xf86CursorUnrealizeCursor(DeviceIntPtr, ScreenPtr, CursorPtr);
26 static void xf86CursorSetCursor(DeviceIntPtr, ScreenPtr, CursorPtr, int, int);
27 static void xf86CursorMoveCursor(DeviceIntPtr, ScreenPtr, int, int);
28 static Bool xf86DeviceCursorInitialize(DeviceIntPtr, ScreenPtr);
29 static void xf86DeviceCursorCleanup(DeviceIntPtr, ScreenPtr);
30
31 static miPointerSpriteFuncRec xf86CursorSpriteFuncs = {
32 xf86CursorRealizeCursor,
33 xf86CursorUnrealizeCursor,
34 xf86CursorSetCursor,
35 xf86CursorMoveCursor,
36 xf86DeviceCursorInitialize,
37 xf86DeviceCursorCleanup
38 };
39
40 /* Screen functions */
41
42 static void xf86CursorInstallColormap(ColormapPtr);
43 static void xf86CursorRecolorCursor(DeviceIntPtr pDev, ScreenPtr, CursorPtr,
44 Bool);
45 static Bool xf86CursorCloseScreen(ScreenPtr);
46 static void xf86CursorQueryBestSize(int, unsigned short *, unsigned short *,
47 ScreenPtr);
48
49 /* ScrnInfoRec functions */
50
51 static void xf86CursorEnableDisableFBAccess(ScrnInfoPtr, Bool);
52 static Bool xf86CursorSwitchMode(ScrnInfoPtr, DisplayModePtr);
53
54 Bool
xf86InitCursor(ScreenPtr pScreen,xf86CursorInfoPtr infoPtr)55 xf86InitCursor(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
119 static Bool
xf86CursorCloseScreen(ScreenPtr pScreen)120 xf86CursorCloseScreen(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
154 static void
xf86CursorQueryBestSize(int class,unsigned short * width,unsigned short * height,ScreenPtr pScreen)155 xf86CursorQueryBestSize(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
173 static void
xf86CursorInstallColormap(ColormapPtr pMap)174 xf86CursorInstallColormap(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
185 static void
xf86CursorRecolorCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCurs,Bool displayed)186 xf86CursorRecolorCursor(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
204 static void
xf86CursorEnableDisableFBAccess(ScrnInfoPtr pScrn,Bool enable)205 xf86CursorEnableDisableFBAccess(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
239 static Bool
xf86CursorSwitchMode(ScrnInfoPtr pScrn,DisplayModePtr mode)240 xf86CursorSwitchMode(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
268 static Bool
xf86CursorRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCurs)269 xf86CursorRealizeCursor(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
282 static Bool
xf86CursorUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCurs)283 xf86CursorUnrealizeCursor(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
299 static void
xf86CursorSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCurs,int x,int y)300 xf86CursorSetCursor(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 */
389 void
xf86CursorResetCursor(ScreenPtr pScreen)390 xf86CursorResetCursor(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
409 static void
xf86CursorMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)410 xf86CursorMoveCursor(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
434 void
xf86ForceHWCursor(ScreenPtr pScreen,Bool on)435 xf86ForceHWCursor(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
462 CursorPtr
xf86CurrentCursor(ScreenPtr pScreen)463 xf86CurrentCursor(ScreenPtr pScreen)
464 {
465 xf86CursorScreenPtr ScreenPriv;
466
467 if (pScreen->is_output_slave)
468 pScreen = pScreen->current_master;
469
470 ScreenPriv = dixLookupPrivate(&pScreen->devPrivates, xf86CursorScreenKey);
471 return ScreenPriv->CurrentCursor;
472 }
473
474 xf86CursorInfoPtr
xf86CreateCursorInfoRec(void)475 xf86CreateCursorInfoRec(void)
476 {
477 return calloc(1, sizeof(xf86CursorInfoRec));
478 }
479
480 void
xf86DestroyCursorInfoRec(xf86CursorInfoPtr infoPtr)481 xf86DestroyCursorInfoRec(xf86CursorInfoPtr infoPtr)
482 {
483 free(infoPtr);
484 }
485
486 /**
487 * New cursor has been created. Do your initalizations here.
488 */
489 static Bool
xf86DeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)490 xf86DeviceCursorInitialize(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 */
506 static void
xf86DeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)507 xf86DeviceCursorCleanup(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