1 /*
2 * misprite.c
3 *
4 * machine independent software sprite routines
5 */
6
7 /*
8
9 Copyright 1989, 1998 The Open Group
10
11 Permission to use, copy, modify, distribute, and sell this software and its
12 documentation for any purpose is hereby granted without fee, provided that
13 the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
15 documentation.
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 Except as contained in this notice, the name of The Open Group shall not be
28 used in advertising or otherwise to promote the sale, use or other dealings
29 in this Software without prior written authorization from The Open Group.
30 */
31
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35
36 #include <X11/X.h>
37 #include <X11/Xproto.h>
38 #include "misc.h"
39 #include "pixmapstr.h"
40 #include "input.h"
41 #include "mi.h"
42 #include "cursorstr.h"
43 #include <X11/fonts/font.h>
44 #include "scrnintstr.h"
45 #include "colormapst.h"
46 #include "windowstr.h"
47 #include "gcstruct.h"
48 #include "mipointer.h"
49 #include "misprite.h"
50 #include "dixfontstr.h"
51 #include <X11/fonts/fontstruct.h>
52 #include "inputstr.h"
53 #include "damage.h"
54
55 typedef struct {
56 CursorPtr pCursor;
57 int x; /* cursor hotspot */
58 int y;
59 BoxRec saved; /* saved area from the screen */
60 Bool isUp; /* cursor in frame buffer */
61 Bool shouldBeUp; /* cursor should be displayed */
62 Bool checkPixels; /* check colormap collision */
63 ScreenPtr pScreen;
64 } miCursorInfoRec, *miCursorInfoPtr;
65
66 /*
67 * per screen information
68 */
69
70 typedef struct {
71 /* screen procedures */
72 CloseScreenProcPtr CloseScreen;
73 GetImageProcPtr GetImage;
74 GetSpansProcPtr GetSpans;
75 SourceValidateProcPtr SourceValidate;
76
77 /* window procedures */
78 CopyWindowProcPtr CopyWindow;
79
80 /* colormap procedures */
81 InstallColormapProcPtr InstallColormap;
82 StoreColorsProcPtr StoreColors;
83
84 /* os layer procedures */
85 ScreenBlockHandlerProcPtr BlockHandler;
86
87 xColorItem colors[2];
88 ColormapPtr pInstalledMap;
89 ColormapPtr pColormap;
90 VisualPtr pVisual;
91 DamagePtr pDamage; /* damage tracking structure */
92 Bool damageRegistered;
93 int numberOfCursors;
94 } miSpriteScreenRec, *miSpriteScreenPtr;
95
96 #define SOURCE_COLOR 0
97 #define MASK_COLOR 1
98
99 /*
100 * Overlap BoxPtr and Box elements
101 */
102 #define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
103 (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
104 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
105
106 /*
107 * Overlap BoxPtr, origins, and rectangle
108 */
109 #define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
110 BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
111
112 /*
113 * Overlap BoxPtr, origins and RectPtr
114 */
115 #define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
116 ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
117 (int)((pRect)->width), (int)((pRect)->height))
118 /*
119 * Overlap BoxPtr and horizontal span
120 */
121 #define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
122
123 #define LINE_SORT(x1,y1,x2,y2) \
124 { int _t; \
125 if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
126 if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
127
128 #define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
129 BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
130
131 #define SPRITE_DEBUG_ENABLE 0
132 #if SPRITE_DEBUG_ENABLE
133 #define SPRITE_DEBUG(x) ErrorF x
134 #else
135 #define SPRITE_DEBUG(x)
136 #endif
137
138 static DevPrivateKeyRec miSpriteScreenKeyRec;
139 static DevPrivateKeyRec miSpriteDevPrivatesKeyRec;
140
141 static miSpriteScreenPtr
GetSpriteScreen(ScreenPtr pScreen)142 GetSpriteScreen(ScreenPtr pScreen)
143 {
144 return dixLookupPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec);
145 }
146
147 static miCursorInfoPtr
GetSprite(DeviceIntPtr dev)148 GetSprite(DeviceIntPtr dev)
149 {
150 if (IsFloating(dev))
151 return dixLookupPrivate(&dev->devPrivates, &miSpriteDevPrivatesKeyRec);
152
153 return dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates,
154 &miSpriteDevPrivatesKeyRec);
155 }
156
157 static void
miSpriteDisableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)158 miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
159 {
160 if (pScreenPriv->damageRegistered) {
161 DamageUnregister(pScreenPriv->pDamage);
162 pScreenPriv->damageRegistered = 0;
163 }
164 }
165
166 static void
miSpriteEnableDamage(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)167 miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
168 {
169 if (!pScreenPriv->damageRegistered) {
170 pScreenPriv->damageRegistered = 1;
171 DamageRegister(&(pScreen->GetScreenPixmap(pScreen)->drawable),
172 pScreenPriv->pDamage);
173 }
174 }
175
176 static void
miSpriteIsUp(miCursorInfoPtr pDevCursor)177 miSpriteIsUp(miCursorInfoPtr pDevCursor)
178 {
179 pDevCursor->isUp = TRUE;
180 }
181
182 static void
miSpriteIsDown(miCursorInfoPtr pDevCursor)183 miSpriteIsDown(miCursorInfoPtr pDevCursor)
184 {
185 pDevCursor->isUp = FALSE;
186 }
187
188 /*
189 * screen wrappers
190 */
191
192 static Bool miSpriteCloseScreen(ScreenPtr pScreen);
193 static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
194 int w, int h, unsigned int format,
195 unsigned long planemask, char *pdstLine);
196 static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
197 DDXPointPtr ppt, int *pwidth, int nspans,
198 char *pdstStart);
199 static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
200 int width, int height,
201 unsigned int subWindowMode);
202 static void miSpriteCopyWindow(WindowPtr pWindow,
203 DDXPointRec ptOldOrg, RegionPtr prgnSrc);
204 static void miSpriteBlockHandler(ScreenPtr pScreen, void *timeout);
205 static void miSpriteInstallColormap(ColormapPtr pMap);
206 static void miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef);
207
208 static void miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen);
209
210 static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,
211 ScreenPtr pScreen);
212 static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
213
214 #define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \
215 (pPriv)->field)
216 #define SCREEN_EPILOGUE(pPriv, pScreen, field)\
217 ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field)
218
219 /*
220 * pointer-sprite method table
221 */
222
223 static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
224 CursorPtr pCursor);
225 static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
226 CursorPtr pCursor);
227 static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
228 CursorPtr pCursor, int x, int y);
229 static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
230 int x, int y);
231
232 miPointerSpriteFuncRec miSpritePointerFuncs = {
233 miSpriteRealizeCursor,
234 miSpriteUnrealizeCursor,
235 miSpriteSetCursor,
236 miSpriteMoveCursor,
237 miSpriteDeviceCursorInitialize,
238 miSpriteDeviceCursorCleanup,
239 };
240
241 /*
242 * other misc functions
243 */
244
245 static void miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
246 static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
247 static void miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen);
248
249 static void
miSpriteRegisterBlockHandler(ScreenPtr pScreen,miSpriteScreenPtr pScreenPriv)250 miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
251 {
252 if (!pScreenPriv->BlockHandler) {
253 pScreenPriv->BlockHandler = pScreen->BlockHandler;
254 pScreen->BlockHandler = miSpriteBlockHandler;
255 }
256 }
257
258 static void
miSpriteReportDamage(DamagePtr pDamage,RegionPtr pRegion,void * closure)259 miSpriteReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure)
260 {
261 ScreenPtr pScreen = closure;
262 miCursorInfoPtr pCursorInfo;
263 DeviceIntPtr pDev;
264
265 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
266 if (DevHasCursor(pDev)) {
267 pCursorInfo = GetSprite(pDev);
268
269 if (pCursorInfo->isUp &&
270 pCursorInfo->pScreen == pScreen &&
271 RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) {
272 SPRITE_DEBUG(("Damage remove\n"));
273 miSpriteRemoveCursor(pDev, pScreen);
274 }
275 }
276 }
277 }
278
279 /*
280 * miSpriteInitialize -- called from device-dependent screen
281 * initialization proc after all of the function pointers have
282 * been stored in the screen structure.
283 */
284
285 Bool
miSpriteInitialize(ScreenPtr pScreen,miPointerScreenFuncPtr screenFuncs)286 miSpriteInitialize(ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
287 {
288 miSpriteScreenPtr pScreenPriv;
289 VisualPtr pVisual;
290
291 if (!DamageSetup(pScreen))
292 return FALSE;
293
294 if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0))
295 return FALSE;
296
297 if (!dixRegisterPrivateKey
298 (&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, sizeof(miCursorInfoRec)))
299 return FALSE;
300
301 pScreenPriv = malloc(sizeof(miSpriteScreenRec));
302 if (!pScreenPriv)
303 return FALSE;
304
305 pScreenPriv->pDamage = DamageCreate(miSpriteReportDamage,
306 NULL,
307 DamageReportRawRegion,
308 TRUE, pScreen, pScreen);
309
310 if (!miPointerInitialize(pScreen, &miSpritePointerFuncs, screenFuncs, TRUE)) {
311 free(pScreenPriv);
312 return FALSE;
313 }
314 for (pVisual = pScreen->visuals;
315 pVisual->vid != pScreen->rootVisual; pVisual++);
316 pScreenPriv->pVisual = pVisual;
317 pScreenPriv->CloseScreen = pScreen->CloseScreen;
318 pScreenPriv->GetImage = pScreen->GetImage;
319 pScreenPriv->GetSpans = pScreen->GetSpans;
320 pScreenPriv->SourceValidate = pScreen->SourceValidate;
321
322 pScreenPriv->CopyWindow = pScreen->CopyWindow;
323
324 pScreenPriv->InstallColormap = pScreen->InstallColormap;
325 pScreenPriv->StoreColors = pScreen->StoreColors;
326
327 pScreenPriv->BlockHandler = NULL;
328
329 pScreenPriv->pInstalledMap = NULL;
330 pScreenPriv->pColormap = NULL;
331 pScreenPriv->colors[SOURCE_COLOR].red = 0;
332 pScreenPriv->colors[SOURCE_COLOR].green = 0;
333 pScreenPriv->colors[SOURCE_COLOR].blue = 0;
334 pScreenPriv->colors[MASK_COLOR].red = 0;
335 pScreenPriv->colors[MASK_COLOR].green = 0;
336 pScreenPriv->colors[MASK_COLOR].blue = 0;
337 pScreenPriv->damageRegistered = 0;
338 pScreenPriv->numberOfCursors = 0;
339
340 dixSetPrivate(&pScreen->devPrivates, &miSpriteScreenKeyRec, pScreenPriv);
341
342 pScreen->CloseScreen = miSpriteCloseScreen;
343 pScreen->GetImage = miSpriteGetImage;
344 pScreen->GetSpans = miSpriteGetSpans;
345 pScreen->SourceValidate = miSpriteSourceValidate;
346
347 pScreen->CopyWindow = miSpriteCopyWindow;
348 pScreen->InstallColormap = miSpriteInstallColormap;
349 pScreen->StoreColors = miSpriteStoreColors;
350
351 return TRUE;
352 }
353
354 /*
355 * Screen wrappers
356 */
357
358 /*
359 * CloseScreen wrapper -- unwrap everything, free the private data
360 * and call the wrapped function
361 */
362
363 static Bool
miSpriteCloseScreen(ScreenPtr pScreen)364 miSpriteCloseScreen(ScreenPtr pScreen)
365 {
366 miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
367
368 pScreen->CloseScreen = pScreenPriv->CloseScreen;
369 pScreen->GetImage = pScreenPriv->GetImage;
370 pScreen->GetSpans = pScreenPriv->GetSpans;
371 pScreen->SourceValidate = pScreenPriv->SourceValidate;
372 pScreen->InstallColormap = pScreenPriv->InstallColormap;
373 pScreen->StoreColors = pScreenPriv->StoreColors;
374
375 DamageDestroy(pScreenPriv->pDamage);
376
377 free(pScreenPriv);
378
379 return (*pScreen->CloseScreen) (pScreen);
380 }
381
382 static void
miSpriteGetImage(DrawablePtr pDrawable,int sx,int sy,int w,int h,unsigned int format,unsigned long planemask,char * pdstLine)383 miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
384 unsigned int format, unsigned long planemask, char *pdstLine)
385 {
386 ScreenPtr pScreen = pDrawable->pScreen;
387 DeviceIntPtr pDev;
388 miCursorInfoPtr pCursorInfo;
389 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
390
391 SCREEN_PROLOGUE(pPriv, pScreen, GetImage);
392
393 if (pDrawable->type == DRAWABLE_WINDOW) {
394 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
395 if (DevHasCursor(pDev)) {
396 pCursorInfo = GetSprite(pDev);
397 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
398 ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
399 sx, sy, w, h)) {
400 SPRITE_DEBUG(("GetImage remove\n"));
401 miSpriteRemoveCursor(pDev, pScreen);
402 }
403 }
404 }
405 }
406
407 (*pScreen->GetImage) (pDrawable, sx, sy, w, h, format, planemask, pdstLine);
408
409 SCREEN_EPILOGUE(pPriv, pScreen, GetImage);
410 }
411
412 static void
miSpriteGetSpans(DrawablePtr pDrawable,int wMax,DDXPointPtr ppt,int * pwidth,int nspans,char * pdstStart)413 miSpriteGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
414 int *pwidth, int nspans, char *pdstStart)
415 {
416 ScreenPtr pScreen = pDrawable->pScreen;
417 DeviceIntPtr pDev;
418 miCursorInfoPtr pCursorInfo;
419 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
420
421 SCREEN_PROLOGUE(pPriv, pScreen, GetSpans);
422
423 if (pDrawable->type == DRAWABLE_WINDOW) {
424 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
425 if (DevHasCursor(pDev)) {
426 pCursorInfo = GetSprite(pDev);
427
428 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) {
429 DDXPointPtr pts;
430 int *widths;
431 int nPts;
432 int xorg, yorg;
433
434 xorg = pDrawable->x;
435 yorg = pDrawable->y;
436
437 for (pts = ppt, widths = pwidth, nPts = nspans;
438 nPts--; pts++, widths++) {
439 if (SPN_OVERLAP(&pCursorInfo->saved, pts->y + yorg,
440 pts->x + xorg, *widths)) {
441 SPRITE_DEBUG(("GetSpans remove\n"));
442 miSpriteRemoveCursor(pDev, pScreen);
443 break;
444 }
445 }
446 }
447 }
448 }
449 }
450
451 (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
452
453 SCREEN_EPILOGUE(pPriv, pScreen, GetSpans);
454 }
455
456 static void
miSpriteSourceValidate(DrawablePtr pDrawable,int x,int y,int width,int height,unsigned int subWindowMode)457 miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, int width,
458 int height, unsigned int subWindowMode)
459 {
460 ScreenPtr pScreen = pDrawable->pScreen;
461 DeviceIntPtr pDev;
462 miCursorInfoPtr pCursorInfo;
463 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
464
465 SCREEN_PROLOGUE(pPriv, pScreen, SourceValidate);
466
467 if (pDrawable->type == DRAWABLE_WINDOW) {
468 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
469 if (DevHasCursor(pDev)) {
470 pCursorInfo = GetSprite(pDev);
471 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
472 ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
473 x, y, width, height)) {
474 SPRITE_DEBUG(("SourceValidate remove\n"));
475 miSpriteRemoveCursor(pDev, pScreen);
476 }
477 }
478 }
479 }
480
481 if (pScreen->SourceValidate)
482 (*pScreen->SourceValidate) (pDrawable, x, y, width, height,
483 subWindowMode);
484
485 SCREEN_EPILOGUE(pPriv, pScreen, SourceValidate);
486 }
487
488 static void
miSpriteCopyWindow(WindowPtr pWindow,DDXPointRec ptOldOrg,RegionPtr prgnSrc)489 miSpriteCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
490 {
491 ScreenPtr pScreen = pWindow->drawable.pScreen;
492 DeviceIntPtr pDev;
493 miCursorInfoPtr pCursorInfo;
494 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
495
496 SCREEN_PROLOGUE(pPriv, pScreen, CopyWindow);
497
498 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
499 if (DevHasCursor(pDev)) {
500 pCursorInfo = GetSprite(pDev);
501 /*
502 * Damage will take care of destination check
503 */
504 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
505 RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) {
506 SPRITE_DEBUG(("CopyWindow remove\n"));
507 miSpriteRemoveCursor(pDev, pScreen);
508 }
509 }
510 }
511
512 (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
513 SCREEN_EPILOGUE(pPriv, pScreen, CopyWindow);
514 }
515
516 static void
miSpriteBlockHandler(ScreenPtr pScreen,void * timeout)517 miSpriteBlockHandler(ScreenPtr pScreen, void *timeout)
518 {
519 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
520 DeviceIntPtr pDev;
521 miCursorInfoPtr pCursorInfo;
522 Bool WorkToDo = FALSE;
523
524 SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler);
525
526 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
527 if (DevHasCursor(pDev)) {
528 pCursorInfo = GetSprite(pDev);
529 if (pCursorInfo && !pCursorInfo->isUp
530 && pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
531 SPRITE_DEBUG(("BlockHandler save"));
532 miSpriteSaveUnderCursor(pDev, pScreen);
533 }
534 }
535 }
536 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
537 if (DevHasCursor(pDev)) {
538 pCursorInfo = GetSprite(pDev);
539 if (pCursorInfo && !pCursorInfo->isUp &&
540 pCursorInfo->pScreen == pScreen && pCursorInfo->shouldBeUp) {
541 SPRITE_DEBUG(("BlockHandler restore\n"));
542 miSpriteRestoreCursor(pDev, pScreen);
543 if (!pCursorInfo->isUp)
544 WorkToDo = TRUE;
545 }
546 }
547 }
548
549 (*pScreen->BlockHandler) (pScreen, timeout);
550
551 if (WorkToDo)
552 SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler);
553 else
554 pPriv->BlockHandler = NULL;
555 }
556
557 static void
miSpriteInstallColormap(ColormapPtr pMap)558 miSpriteInstallColormap(ColormapPtr pMap)
559 {
560 ScreenPtr pScreen = pMap->pScreen;
561 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
562
563 SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap);
564
565 (*pScreen->InstallColormap) (pMap);
566
567 SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap);
568
569 /* InstallColormap can be called before devices are initialized. */
570 pPriv->pInstalledMap = pMap;
571 if (pPriv->pColormap != pMap) {
572 DeviceIntPtr pDev;
573 miCursorInfoPtr pCursorInfo;
574
575 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
576 if (DevHasCursor(pDev)) {
577 pCursorInfo = GetSprite(pDev);
578 pCursorInfo->checkPixels = TRUE;
579 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
580 miSpriteRemoveCursor(pDev, pScreen);
581 }
582 }
583
584 }
585 }
586
587 static void
miSpriteStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)588 miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
589 {
590 ScreenPtr pScreen = pMap->pScreen;
591 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
592 int i;
593 int updated;
594 VisualPtr pVisual;
595 DeviceIntPtr pDev;
596 miCursorInfoPtr pCursorInfo;
597
598 SCREEN_PROLOGUE(pPriv, pScreen, StoreColors);
599
600 (*pScreen->StoreColors) (pMap, ndef, pdef);
601
602 SCREEN_EPILOGUE(pPriv, pScreen, StoreColors);
603
604 if (pPriv->pColormap == pMap) {
605 updated = 0;
606 pVisual = pMap->pVisual;
607 if (pVisual->class == DirectColor) {
608 /* Direct color - match on any of the subfields */
609
610 #define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
611
612 #define UpdateDAC(dev, plane,dac,mask) {\
613 if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\
614 dev->colors[plane].dac = pdef[i].dac; \
615 updated = 1; \
616 } \
617 }
618
619 #define CheckDirect(dev, plane) \
620 UpdateDAC(dev, plane,red,redMask) \
621 UpdateDAC(dev, plane,green,greenMask) \
622 UpdateDAC(dev, plane,blue,blueMask)
623
624 for (i = 0; i < ndef; i++) {
625 CheckDirect(pPriv, SOURCE_COLOR)
626 CheckDirect(pPriv, MASK_COLOR)
627 }
628 }
629 else {
630 /* PseudoColor/GrayScale - match on exact pixel */
631 for (i = 0; i < ndef; i++) {
632 if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) {
633 pPriv->colors[SOURCE_COLOR] = pdef[i];
634 if (++updated == 2)
635 break;
636 }
637 if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) {
638 pPriv->colors[MASK_COLOR] = pdef[i];
639 if (++updated == 2)
640 break;
641 }
642 }
643 }
644 if (updated) {
645 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
646 if (DevHasCursor(pDev)) {
647 pCursorInfo = GetSprite(pDev);
648 pCursorInfo->checkPixels = TRUE;
649 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
650 miSpriteRemoveCursor(pDev, pScreen);
651 }
652 }
653 }
654 }
655 }
656
657 static void
miSpriteFindColors(miCursorInfoPtr pDevCursor,ScreenPtr pScreen)658 miSpriteFindColors(miCursorInfoPtr pDevCursor, ScreenPtr pScreen)
659 {
660 miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
661 CursorPtr pCursor;
662 xColorItem *sourceColor, *maskColor;
663
664 pCursor = pDevCursor->pCursor;
665 sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
666 maskColor = &pScreenPriv->colors[MASK_COLOR];
667 if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
668 !(pCursor->foreRed == sourceColor->red &&
669 pCursor->foreGreen == sourceColor->green &&
670 pCursor->foreBlue == sourceColor->blue &&
671 pCursor->backRed == maskColor->red &&
672 pCursor->backGreen == maskColor->green &&
673 pCursor->backBlue == maskColor->blue)) {
674 pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
675 sourceColor->red = pCursor->foreRed;
676 sourceColor->green = pCursor->foreGreen;
677 sourceColor->blue = pCursor->foreBlue;
678 FakeAllocColor(pScreenPriv->pColormap, sourceColor);
679 maskColor->red = pCursor->backRed;
680 maskColor->green = pCursor->backGreen;
681 maskColor->blue = pCursor->backBlue;
682 FakeAllocColor(pScreenPriv->pColormap, maskColor);
683 /* "free" the pixels right away, don't let this confuse you */
684 FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
685 FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
686 }
687
688 pDevCursor->checkPixels = FALSE;
689
690 }
691
692 /*
693 * miPointer interface routines
694 */
695
696 #define SPRITE_PAD 8
697
698 static Bool
miSpriteRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)699 miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
700 {
701 miCursorInfoPtr pCursorInfo;
702
703 if (IsFloating(pDev))
704 return FALSE;
705
706 pCursorInfo = GetSprite(pDev);
707
708 if (pCursor == pCursorInfo->pCursor)
709 pCursorInfo->checkPixels = TRUE;
710
711 return miDCRealizeCursor(pScreen, pCursor);
712 }
713
714 static Bool
miSpriteUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)715 miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
716 {
717 return miDCUnrealizeCursor(pScreen, pCursor);
718 }
719
720 static void
miSpriteSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)721 miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
722 CursorPtr pCursor, int x, int y)
723 {
724 miCursorInfoPtr pPointer;
725 miSpriteScreenPtr pScreenPriv;
726
727 if (IsFloating(pDev))
728 return;
729
730 pPointer = GetSprite(pDev);
731 pScreenPriv = GetSpriteScreen(pScreen);
732
733 if (!pCursor) {
734 if (pPointer->shouldBeUp)
735 --pScreenPriv->numberOfCursors;
736 pPointer->shouldBeUp = FALSE;
737 if (pPointer->isUp)
738 miSpriteRemoveCursor(pDev, pScreen);
739 if (pScreenPriv->numberOfCursors == 0)
740 miSpriteDisableDamage(pScreen, pScreenPriv);
741 pPointer->pCursor = 0;
742 return;
743 }
744 if (!pPointer->shouldBeUp)
745 pScreenPriv->numberOfCursors++;
746 pPointer->shouldBeUp = TRUE;
747 if (!pPointer->isUp)
748 miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
749 if (pPointer->x == x &&
750 pPointer->y == y &&
751 pPointer->pCursor == pCursor && !pPointer->checkPixels) {
752 return;
753 }
754 pPointer->x = x;
755 pPointer->y = y;
756 if (pPointer->checkPixels || pPointer->pCursor != pCursor) {
757 pPointer->pCursor = pCursor;
758 miSpriteFindColors(pPointer, pScreen);
759 }
760 if (pPointer->isUp) {
761 /* TODO: reimplement flicker-free MoveCursor */
762 SPRITE_DEBUG(("SetCursor remove %d\n", pDev->id));
763 miSpriteRemoveCursor(pDev, pScreen);
764 }
765
766 if (!pPointer->isUp && pPointer->pCursor) {
767 SPRITE_DEBUG(("SetCursor restore %d\n", pDev->id));
768 miSpriteSaveUnderCursor(pDev, pScreen);
769 miSpriteRestoreCursor(pDev, pScreen);
770 }
771
772 }
773
774 static void
miSpriteMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)775 miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
776 {
777 CursorPtr pCursor;
778
779 if (IsFloating(pDev))
780 return;
781
782 pCursor = GetSprite(pDev)->pCursor;
783
784 miSpriteSetCursor(pDev, pScreen, pCursor, x, y);
785 }
786
787 static Bool
miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)788 miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
789 {
790 int ret = miDCDeviceInitialize(pDev, pScreen);
791
792 if (ret) {
793 miCursorInfoPtr pCursorInfo;
794
795 pCursorInfo =
796 dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
797 pCursorInfo->pCursor = NULL;
798 pCursorInfo->x = 0;
799 pCursorInfo->y = 0;
800 pCursorInfo->isUp = FALSE;
801 pCursorInfo->shouldBeUp = FALSE;
802 pCursorInfo->checkPixels = TRUE;
803 pCursorInfo->pScreen = FALSE;
804 }
805
806 return ret;
807 }
808
809 static void
miSpriteDeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)810 miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
811 {
812 miCursorInfoPtr pCursorInfo =
813 dixLookupPrivate(&pDev->devPrivates, &miSpriteDevPrivatesKeyRec);
814
815 if (DevHasCursor(pDev))
816 miDCDeviceCleanup(pDev, pScreen);
817
818 memset(pCursorInfo, 0, sizeof(miCursorInfoRec));
819 }
820
821 /*
822 * undraw/draw cursor
823 */
824
825 static void
miSpriteRemoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen)826 miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
827 {
828 miSpriteScreenPtr pScreenPriv;
829 miCursorInfoPtr pCursorInfo;
830
831 if (IsFloating(pDev))
832 return;
833
834 DamageDrawInternal(pScreen, TRUE);
835 pScreenPriv = GetSpriteScreen(pScreen);
836 pCursorInfo = GetSprite(pDev);
837
838 miSpriteIsDown(pCursorInfo);
839 miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
840 miSpriteDisableDamage(pScreen, pScreenPriv);
841 if (!miDCRestoreUnderCursor(pDev,
842 pScreen,
843 pCursorInfo->saved.x1,
844 pCursorInfo->saved.y1,
845 pCursorInfo->saved.x2 -
846 pCursorInfo->saved.x1,
847 pCursorInfo->saved.y2 -
848 pCursorInfo->saved.y1)) {
849 miSpriteIsUp(pCursorInfo);
850 }
851 miSpriteEnableDamage(pScreen, pScreenPriv);
852 DamageDrawInternal(pScreen, FALSE);
853 }
854
855 /*
856 * Called from the block handler, saves area under cursor
857 * before waiting for something to do.
858 */
859
860 static void
miSpriteSaveUnderCursor(DeviceIntPtr pDev,ScreenPtr pScreen)861 miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
862 {
863 miSpriteScreenPtr pScreenPriv;
864 miCursorInfoPtr pCursorInfo;
865
866 if (IsFloating(pDev))
867 return;
868
869 DamageDrawInternal(pScreen, TRUE);
870 pScreenPriv = GetSpriteScreen(pScreen);
871 pCursorInfo = GetSprite(pDev);
872
873 miSpriteComputeSaved(pDev, pScreen);
874
875 miSpriteDisableDamage(pScreen, pScreenPriv);
876
877 miDCSaveUnderCursor(pDev,
878 pScreen,
879 pCursorInfo->saved.x1,
880 pCursorInfo->saved.y1,
881 pCursorInfo->saved.x2 -
882 pCursorInfo->saved.x1,
883 pCursorInfo->saved.y2 - pCursorInfo->saved.y1);
884 SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id));
885 miSpriteEnableDamage(pScreen, pScreenPriv);
886 DamageDrawInternal(pScreen, FALSE);
887 }
888
889 /*
890 * Called from the block handler, restores the cursor
891 * before waiting for something to do.
892 */
893
894 static void
miSpriteRestoreCursor(DeviceIntPtr pDev,ScreenPtr pScreen)895 miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
896 {
897 miSpriteScreenPtr pScreenPriv;
898 int x, y;
899 CursorPtr pCursor;
900 miCursorInfoPtr pCursorInfo;
901
902 if (IsFloating(pDev))
903 return;
904
905 DamageDrawInternal(pScreen, TRUE);
906 pScreenPriv = GetSpriteScreen(pScreen);
907 pCursorInfo = GetSprite(pDev);
908
909 miSpriteComputeSaved(pDev, pScreen);
910 pCursor = pCursorInfo->pCursor;
911
912 x = pCursorInfo->x - (int) pCursor->bits->xhot;
913 y = pCursorInfo->y - (int) pCursor->bits->yhot;
914 miSpriteDisableDamage(pScreen, pScreenPriv);
915 SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id));
916 if (pCursorInfo->checkPixels)
917 miSpriteFindColors(pCursorInfo, pScreen);
918 if (miDCPutUpCursor(pDev, pScreen,
919 pCursor, x, y,
920 pScreenPriv->colors[SOURCE_COLOR].pixel,
921 pScreenPriv->colors[MASK_COLOR].pixel)) {
922 miSpriteIsUp(pCursorInfo);
923 pCursorInfo->pScreen = pScreen;
924 }
925 miSpriteEnableDamage(pScreen, pScreenPriv);
926 DamageDrawInternal(pScreen, FALSE);
927 }
928
929 /*
930 * compute the desired area of the screen to save
931 */
932
933 static void
miSpriteComputeSaved(DeviceIntPtr pDev,ScreenPtr pScreen)934 miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen)
935 {
936 int x, y, w, h;
937 int wpad, hpad;
938 CursorPtr pCursor;
939 miCursorInfoPtr pCursorInfo;
940
941 if (IsFloating(pDev))
942 return;
943
944 pCursorInfo = GetSprite(pDev);
945
946 pCursor = pCursorInfo->pCursor;
947 x = pCursorInfo->x - (int) pCursor->bits->xhot;
948 y = pCursorInfo->y - (int) pCursor->bits->yhot;
949 w = pCursor->bits->width;
950 h = pCursor->bits->height;
951 wpad = SPRITE_PAD;
952 hpad = SPRITE_PAD;
953 pCursorInfo->saved.x1 = x - wpad;
954 pCursorInfo->saved.y1 = y - hpad;
955 pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2;
956 pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2;
957 }
958