Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | 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 | ||
72 | typedef 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 | ||
145 | static void | |
146 | miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) | |
147 | { | |
148 | if (pScreenPriv->damageRegistered) { | |
149 | DamageUnregister(pScreenPriv->pDamage); | |
150 | pScreenPriv->damageRegistered = 0; | |
151 | } | |
152 | } | |
153 | ||
154 | static void | |
155 | miSpriteEnableDamage(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 | ||
164 | static void | |
165 | miSpriteIsUp(miCursorInfoPtr pDevCursor) | |
166 | { | |
167 | pDevCursor->isUp = TRUE; | |
168 | } | |
169 | ||
170 | static void | |
171 | miSpriteIsDown(miCursorInfoPtr pDevCursor) | |
172 | { | |
173 | pDevCursor->isUp = FALSE; | |
174 | } | |
175 | ||
176 | /* | |
177 | * screen wrappers | |
178 | */ | |
179 | ||
180 | static DevPrivateKeyRec miSpriteScreenKeyRec; | |
181 | ||
182 | #define miSpriteScreenKey (&miSpriteScreenKeyRec) | |
183 | #define GetSpriteScreen(pScreen) \ | |
184 | (dixLookupPrivate(&(pScreen)->devPrivates, miSpriteScreenKey)) | |
185 | static DevPrivateKeyRec miSpriteDevPrivatesKeyRec; | |
186 | ||
187 | #define miSpriteDevPrivatesKey (&miSpriteDevPrivatesKeyRec) | |
188 | ||
189 | static Bool miSpriteCloseScreen(ScreenPtr pScreen); | |
190 | static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, | |
191 | int w, int h, unsigned int format, | |
192 | unsigned long planemask, char *pdstLine); | |
193 | static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, | |
194 | DDXPointPtr ppt, int *pwidth, int nspans, | |
195 | char *pdstStart); | |
196 | static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, | |
197 | int width, int height, | |
198 | unsigned int subWindowMode); | |
199 | static void miSpriteCopyWindow(WindowPtr pWindow, | |
200 | DDXPointRec ptOldOrg, RegionPtr prgnSrc); | |
201 | static void miSpriteBlockHandler(ScreenPtr pScreen, | |
202 | pointer pTimeout, pointer pReadMask); | |
203 | static void miSpriteInstallColormap(ColormapPtr pMap); | |
204 | static void miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef); | |
205 | ||
206 | static void miSpriteComputeSaved(DeviceIntPtr pDev, ScreenPtr pScreen); | |
207 | ||
208 | static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, | |
209 | ScreenPtr pScreen); | |
210 | static 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 | ||
221 | static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
222 | CursorPtr pCursor); | |
223 | static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
224 | CursorPtr pCursor); | |
225 | static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
226 | CursorPtr pCursor, int x, int y); | |
227 | static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
228 | int x, int y); | |
229 | ||
230 | miPointerSpriteFuncRec miSpritePointerFuncs = { | |
231 | miSpriteRealizeCursor, | |
232 | miSpriteUnrealizeCursor, | |
233 | miSpriteSetCursor, | |
234 | miSpriteMoveCursor, | |
235 | miSpriteDeviceCursorInitialize, | |
236 | miSpriteDeviceCursorCleanup, | |
237 | }; | |
238 | ||
239 | /* | |
240 | * other misc functions | |
241 | */ | |
242 | ||
243 | static void miSpriteRemoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen); | |
244 | static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen); | |
245 | static void miSpriteRestoreCursor(DeviceIntPtr pDev, ScreenPtr pScreen); | |
246 | ||
247 | static void | |
248 | miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) | |
249 | { | |
250 | if (!pScreenPriv->BlockHandler) { | |
251 | pScreenPriv->BlockHandler = pScreen->BlockHandler; | |
252 | pScreen->BlockHandler = miSpriteBlockHandler; | |
253 | } | |
254 | } | |
255 | ||
256 | static void | |
257 | miSpriteReportDamage(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 | ||
283 | Bool | |
284 | miSpriteInitialize(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 | ||
361 | static Bool | |
362 | miSpriteCloseScreen(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 | ||
380 | static void | |
381 | miSpriteGetImage(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 | ||
410 | static void | |
411 | miSpriteGetSpans(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 | ||
454 | static void | |
455 | miSpriteSourceValidate(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 | ||
486 | static void | |
487 | miSpriteCopyWindow(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 | ||
514 | static void | |
515 | miSpriteBlockHandler(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 | ||
556 | static void | |
557 | miSpriteInstallColormap(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 | ||
586 | static void | |
587 | miSpriteStoreColors(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 | ||
656 | static void | |
657 | miSpriteFindColors(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 | ||
697 | static Bool | |
698 | miSpriteRealizeCursor(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 | ||
713 | static Bool | |
714 | miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
715 | { | |
716 | return miDCUnrealizeCursor(pScreen, pCursor); | |
717 | } | |
718 | ||
719 | static void | |
720 | miSpriteSetCursor(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 | ||
774 | static void | |
775 | miSpriteMoveCursor(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 | ||
787 | static Bool | |
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, 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 | ||
811 | static void | |
812 | miSpriteDeviceCursorCleanup(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 | ||
827 | static void | |
828 | miSpriteRemoveCursor(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 | ||
863 | static void | |
864 | miSpriteSaveUnderCursor(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 | ||
897 | static void | |
898 | miSpriteRestoreCursor(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 | ||
936 | static void | |
937 | miSpriteComputeSaved(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 | } |