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