Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Screen routines for generic rootless X server | |
3 | */ | |
4 | /* | |
5 | * Copyright (c) 2001 Greg Parker. All Rights Reserved. | |
6 | * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. | |
7 | * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice shall be included in | |
17 | * all copies or substantial portions of the Software. | |
18 | * | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
25 | * DEALINGS IN THE SOFTWARE. | |
26 | * | |
27 | * Except as contained in this notice, the name(s) of the above copyright | |
28 | * holders shall not be used in advertising or otherwise to promote the sale, | |
29 | * use or other dealings in this Software without prior written authorization. | |
30 | */ | |
31 | ||
32 | #ifdef HAVE_DIX_CONFIG_H | |
33 | #include <dix-config.h> | |
34 | #endif | |
35 | ||
36 | #include "mi.h" | |
37 | #include "scrnintstr.h" | |
38 | #include "gcstruct.h" | |
39 | #include "pixmapstr.h" | |
40 | #include "windowstr.h" | |
41 | #include "propertyst.h" | |
42 | #include "mivalidate.h" | |
43 | #include "picturestr.h" | |
44 | #include "colormapst.h" | |
45 | ||
46 | #include <sys/types.h> | |
47 | #include <sys/stat.h> | |
48 | #include <fcntl.h> | |
49 | #include <string.h> | |
50 | ||
51 | #include "rootlessCommon.h" | |
52 | #include "rootlessWindow.h" | |
53 | ||
54 | /* In milliseconds */ | |
55 | #ifndef ROOTLESS_REDISPLAY_DELAY | |
56 | #define ROOTLESS_REDISPLAY_DELAY 10 | |
57 | #endif | |
58 | ||
59 | extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, | |
60 | VTKind kind); | |
61 | extern Bool RootlessCreateGC(GCPtr pGC); | |
62 | ||
63 | // Initialize globals | |
64 | DevPrivateKeyRec rootlessGCPrivateKeyRec; | |
65 | DevPrivateKeyRec rootlessScreenPrivateKeyRec; | |
66 | DevPrivateKeyRec rootlessWindowPrivateKeyRec; | |
67 | DevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec; | |
68 | ||
69 | /* | |
70 | * RootlessUpdateScreenPixmap | |
71 | * miCreateScreenResources does not like a null framebuffer pointer, | |
72 | * it leaves the screen pixmap with an uninitialized data pointer. | |
73 | * Thus, rootless implementations typically set the framebuffer width | |
74 | * to zero so that miCreateScreenResources does not allocate a screen | |
75 | * pixmap for us. We allocate our own screen pixmap here since we need | |
76 | * the screen pixmap to be valid (e.g. CopyArea from the root window). | |
77 | */ | |
78 | void | |
79 | RootlessUpdateScreenPixmap(ScreenPtr pScreen) | |
80 | { | |
81 | RootlessScreenRec *s = SCREENREC(pScreen); | |
82 | PixmapPtr pPix; | |
83 | unsigned int rowbytes; | |
84 | ||
85 | pPix = (*pScreen->GetScreenPixmap) (pScreen); | |
86 | if (pPix == NULL) { | |
87 | pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0); | |
88 | (*pScreen->SetScreenPixmap) (pPix); | |
89 | } | |
90 | ||
91 | rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth); | |
92 | ||
93 | if (s->pixmap_data_size < rowbytes) { | |
94 | free(s->pixmap_data); | |
95 | ||
96 | s->pixmap_data_size = rowbytes; | |
97 | s->pixmap_data = malloc(s->pixmap_data_size); | |
98 | if (s->pixmap_data == NULL) | |
99 | return; | |
100 | ||
101 | memset(s->pixmap_data, 0xFF, s->pixmap_data_size); | |
102 | ||
103 | pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height, | |
104 | pScreen->rootDepth, | |
105 | BitsPerPixel(pScreen->rootDepth), | |
106 | 0, s->pixmap_data); | |
107 | /* ModifyPixmapHeader ignores zero arguments, so install rowbytes | |
108 | by hand. */ | |
109 | pPix->devKind = 0; | |
110 | } | |
111 | } | |
112 | ||
113 | /* | |
114 | * RootlessCreateScreenResources | |
115 | * Rootless implementations typically set a null framebuffer pointer, which | |
116 | * causes problems with miCreateScreenResources. We fix things up here. | |
117 | */ | |
118 | static Bool | |
119 | RootlessCreateScreenResources(ScreenPtr pScreen) | |
120 | { | |
121 | Bool ret = TRUE; | |
122 | ||
123 | SCREEN_UNWRAP(pScreen, CreateScreenResources); | |
124 | ||
125 | if (pScreen->CreateScreenResources != NULL) | |
126 | ret = (*pScreen->CreateScreenResources) (pScreen); | |
127 | ||
128 | SCREEN_WRAP(pScreen, CreateScreenResources); | |
129 | ||
130 | if (!ret) | |
131 | return ret; | |
132 | ||
133 | /* Make sure we have a valid screen pixmap. */ | |
134 | ||
135 | RootlessUpdateScreenPixmap(pScreen); | |
136 | ||
137 | return ret; | |
138 | } | |
139 | ||
140 | static Bool | |
141 | RootlessCloseScreen(ScreenPtr pScreen) | |
142 | { | |
143 | RootlessScreenRec *s; | |
144 | ||
145 | s = SCREENREC(pScreen); | |
146 | ||
147 | // fixme unwrap everything that was wrapped? | |
148 | pScreen->CloseScreen = s->CloseScreen; | |
149 | ||
150 | if (s->pixmap_data != NULL) { | |
151 | free(s->pixmap_data); | |
152 | s->pixmap_data = NULL; | |
153 | s->pixmap_data_size = 0; | |
154 | } | |
155 | ||
156 | free(s); | |
157 | return pScreen->CloseScreen(pScreen); | |
158 | } | |
159 | ||
160 | static void | |
161 | RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, | |
162 | unsigned int format, unsigned long planeMask, char *pdstLine) | |
163 | { | |
164 | ScreenPtr pScreen = pDrawable->pScreen; | |
165 | ||
166 | SCREEN_UNWRAP(pScreen, GetImage); | |
167 | ||
168 | if (pDrawable->type == DRAWABLE_WINDOW) { | |
169 | int x0, y0, x1, y1; | |
170 | RootlessWindowRec *winRec; | |
171 | ||
172 | // Many apps use GetImage to sync with the visible frame buffer | |
173 | // FIXME: entire screen or just window or all screens? | |
174 | RootlessRedisplayScreen(pScreen); | |
175 | ||
176 | // RedisplayScreen stops drawing, so we need to start it again | |
177 | RootlessStartDrawing((WindowPtr) pDrawable); | |
178 | ||
179 | /* Check that we have some place to read from. */ | |
180 | winRec = WINREC(TopLevelParent((WindowPtr) pDrawable)); | |
181 | if (winRec == NULL) | |
182 | goto out; | |
183 | ||
184 | /* Clip to top-level window bounds. */ | |
185 | /* FIXME: fbGetImage uses the width parameter to calculate the | |
186 | stride of the destination pixmap. If w is clipped, the data | |
187 | returned will be garbage, although we will not crash. */ | |
188 | ||
189 | x0 = pDrawable->x + sx; | |
190 | y0 = pDrawable->y + sy; | |
191 | x1 = x0 + w; | |
192 | y1 = y0 + h; | |
193 | ||
194 | x0 = max(x0, winRec->x); | |
195 | y0 = max(y0, winRec->y); | |
196 | x1 = min(x1, winRec->x + winRec->width); | |
197 | y1 = min(y1, winRec->y + winRec->height); | |
198 | ||
199 | sx = x0 - pDrawable->x; | |
200 | sy = y0 - pDrawable->y; | |
201 | w = x1 - x0; | |
202 | h = y1 - y0; | |
203 | ||
204 | if (w <= 0 || h <= 0) | |
205 | goto out; | |
206 | } | |
207 | ||
208 | pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); | |
209 | ||
210 | out: | |
211 | SCREEN_WRAP(pScreen, GetImage); | |
212 | } | |
213 | ||
214 | /* | |
215 | * RootlessSourceValidate | |
216 | * CopyArea and CopyPlane use a GC tied to the destination drawable. | |
217 | * StartDrawing/StopDrawing wrappers won't be called if source is | |
218 | * a visible window but the destination isn't. So, we call StartDrawing | |
219 | * here and leave StopDrawing for the block handler. | |
220 | */ | |
221 | static void | |
222 | RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h, | |
223 | unsigned int subWindowMode) | |
224 | { | |
225 | SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate); | |
226 | if (pDrawable->type == DRAWABLE_WINDOW) { | |
227 | WindowPtr pWin = (WindowPtr) pDrawable; | |
228 | ||
229 | RootlessStartDrawing(pWin); | |
230 | } | |
231 | if (pDrawable->pScreen->SourceValidate) { | |
232 | pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h, | |
233 | subWindowMode); | |
234 | } | |
235 | SCREEN_WRAP(pDrawable->pScreen, SourceValidate); | |
236 | } | |
237 | ||
238 | static void | |
239 | RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, | |
240 | INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, | |
241 | INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) | |
242 | { | |
243 | ScreenPtr pScreen = pDst->pDrawable->pScreen; | |
244 | PictureScreenPtr ps = GetPictureScreen(pScreen); | |
245 | WindowPtr srcWin, dstWin, maskWin = NULL; | |
246 | ||
247 | if (pMask) { // pMask can be NULL | |
248 | maskWin = (pMask->pDrawable && | |
249 | pMask->pDrawable->type == | |
250 | DRAWABLE_WINDOW) ? (WindowPtr) pMask->pDrawable : NULL; | |
251 | } | |
252 | srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? | |
253 | (WindowPtr) pSrc->pDrawable : NULL; | |
254 | dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? | |
255 | (WindowPtr) pDst->pDrawable : NULL; | |
256 | ||
257 | // SCREEN_UNWRAP(ps, Composite); | |
258 | ps->Composite = SCREENREC(pScreen)->Composite; | |
259 | ||
260 | if (srcWin && IsFramedWindow(srcWin)) | |
261 | RootlessStartDrawing(srcWin); | |
262 | if (maskWin && IsFramedWindow(maskWin)) | |
263 | RootlessStartDrawing(maskWin); | |
264 | if (dstWin && IsFramedWindow(dstWin)) | |
265 | RootlessStartDrawing(dstWin); | |
266 | ||
267 | ps->Composite(op, pSrc, pMask, pDst, | |
268 | xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); | |
269 | ||
270 | if (dstWin && IsFramedWindow(dstWin)) { | |
271 | RootlessDamageRect(dstWin, xDst, yDst, width, height); | |
272 | } | |
273 | ||
274 | ps->Composite = RootlessComposite; | |
275 | // SCREEN_WRAP(ps, Composite); | |
276 | } | |
277 | ||
278 | static void | |
279 | RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, | |
280 | PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, | |
281 | int nlist, GlyphListPtr list, GlyphPtr * glyphs) | |
282 | { | |
283 | ScreenPtr pScreen = pDst->pDrawable->pScreen; | |
284 | PictureScreenPtr ps = GetPictureScreen(pScreen); | |
285 | int x, y; | |
286 | int n; | |
287 | GlyphPtr glyph; | |
288 | WindowPtr srcWin, dstWin; | |
289 | ||
290 | srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ? | |
291 | (WindowPtr) pSrc->pDrawable : NULL; | |
292 | dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? | |
293 | (WindowPtr) pDst->pDrawable : NULL; | |
294 | ||
295 | if (srcWin && IsFramedWindow(srcWin)) | |
296 | RootlessStartDrawing(srcWin); | |
297 | if (dstWin && IsFramedWindow(dstWin)) | |
298 | RootlessStartDrawing(dstWin); | |
299 | ||
300 | //SCREEN_UNWRAP(ps, Glyphs); | |
301 | ps->Glyphs = SCREENREC(pScreen)->Glyphs; | |
302 | ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); | |
303 | ps->Glyphs = RootlessGlyphs; | |
304 | //SCREEN_WRAP(ps, Glyphs); | |
305 | ||
306 | if (dstWin && IsFramedWindow(dstWin)) { | |
307 | x = xSrc; | |
308 | y = ySrc; | |
309 | ||
310 | while (nlist--) { | |
311 | x += list->xOff; | |
312 | y += list->yOff; | |
313 | n = list->len; | |
314 | ||
315 | /* Calling DamageRect for the bounding box of each glyph is | |
316 | inefficient. So compute the union of all glyphs in a list | |
317 | and damage that. */ | |
318 | ||
319 | if (n > 0) { | |
320 | BoxRec box; | |
321 | ||
322 | glyph = *glyphs++; | |
323 | ||
324 | box.x1 = x - glyph->info.x; | |
325 | box.y1 = y - glyph->info.y; | |
326 | box.x2 = box.x1 + glyph->info.width; | |
327 | box.y2 = box.y1 + glyph->info.height; | |
328 | ||
329 | x += glyph->info.xOff; | |
330 | y += glyph->info.yOff; | |
331 | ||
332 | while (--n > 0) { | |
333 | short x1, y1, x2, y2; | |
334 | ||
335 | glyph = *glyphs++; | |
336 | ||
337 | x1 = x - glyph->info.x; | |
338 | y1 = y - glyph->info.y; | |
339 | x2 = x1 + glyph->info.width; | |
340 | y2 = y1 + glyph->info.height; | |
341 | ||
342 | box.x1 = max(box.x1, x1); | |
343 | box.y1 = max(box.y1, y1); | |
344 | box.x2 = max(box.x2, x2); | |
345 | box.y2 = max(box.y2, y2); | |
346 | ||
347 | x += glyph->info.xOff; | |
348 | y += glyph->info.yOff; | |
349 | } | |
350 | ||
351 | RootlessDamageBox(dstWin, &box); | |
352 | } | |
353 | list++; | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | /* | |
359 | * RootlessValidateTree | |
360 | * ValidateTree is modified in two ways: | |
361 | * - top-level windows don't clip each other | |
362 | * - windows aren't clipped against root. | |
363 | * These only matter when validating from the root. | |
364 | */ | |
365 | static int | |
366 | RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) | |
367 | { | |
368 | int result; | |
369 | RegionRec saveRoot; | |
370 | ScreenPtr pScreen = pParent->drawable.pScreen; | |
371 | ||
372 | SCREEN_UNWRAP(pScreen, ValidateTree); | |
373 | RL_DEBUG_MSG("VALIDATETREE start "); | |
374 | ||
375 | // Use our custom version to validate from root | |
376 | if (IsRoot(pParent)) { | |
377 | RL_DEBUG_MSG("custom "); | |
378 | result = RootlessMiValidateTree(pParent, pChild, kind); | |
379 | } | |
380 | else { | |
381 | HUGE_ROOT(pParent); | |
382 | result = pScreen->ValidateTree(pParent, pChild, kind); | |
383 | NORMAL_ROOT(pParent); | |
384 | } | |
385 | ||
386 | SCREEN_WRAP(pScreen, ValidateTree); | |
387 | RL_DEBUG_MSG("VALIDATETREE end\n"); | |
388 | ||
389 | return result; | |
390 | } | |
391 | ||
392 | /* | |
393 | * RootlessMarkOverlappedWindows | |
394 | * MarkOverlappedWindows is modified to ignore overlapping | |
395 | * top-level windows. | |
396 | */ | |
397 | static Bool | |
398 | RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, | |
399 | WindowPtr *ppLayerWin) | |
400 | { | |
401 | RegionRec saveRoot; | |
402 | Bool result; | |
403 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
404 | ||
405 | SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); | |
406 | RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); | |
407 | ||
408 | HUGE_ROOT(pWin); | |
409 | if (IsRoot(pWin)) { | |
410 | // root - mark nothing | |
411 | RL_DEBUG_MSG("is root not marking "); | |
412 | result = FALSE; | |
413 | } | |
414 | else if (!IsTopLevel(pWin)) { | |
415 | // not top-level window - mark normally | |
416 | result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); | |
417 | } | |
418 | else { | |
419 | //top-level window - mark children ONLY - NO overlaps with sibs (?) | |
420 | // This code copied from miMarkOverlappedWindows() | |
421 | ||
422 | register WindowPtr pChild; | |
423 | Bool anyMarked = FALSE; | |
424 | MarkWindowProcPtr MarkWindow = pScreen->MarkWindow; | |
425 | ||
426 | RL_DEBUG_MSG("is top level! "); | |
427 | /* single layered systems are easy */ | |
428 | if (ppLayerWin) | |
429 | *ppLayerWin = pWin; | |
430 | ||
431 | if (pWin == pFirst) { | |
432 | /* Blindly mark pWin and all of its inferiors. This is a slight | |
433 | * overkill if there are mapped windows that outside pWin's border, | |
434 | * but it's better than wasting time on RectIn checks. | |
435 | */ | |
436 | pChild = pWin; | |
437 | while (1) { | |
438 | if (pChild->viewable) { | |
439 | if (RegionBroken(&pChild->winSize)) | |
440 | SetWinSize(pChild); | |
441 | if (RegionBroken(&pChild->borderSize)) | |
442 | SetBorderSize(pChild); | |
443 | (*MarkWindow) (pChild); | |
444 | if (pChild->firstChild) { | |
445 | pChild = pChild->firstChild; | |
446 | continue; | |
447 | } | |
448 | } | |
449 | while (!pChild->nextSib && (pChild != pWin)) | |
450 | pChild = pChild->parent; | |
451 | if (pChild == pWin) | |
452 | break; | |
453 | pChild = pChild->nextSib; | |
454 | } | |
455 | anyMarked = TRUE; | |
456 | } | |
457 | if (anyMarked) | |
458 | (*MarkWindow) (pWin->parent); | |
459 | result = anyMarked; | |
460 | } | |
461 | NORMAL_ROOT(pWin); | |
462 | SCREEN_WRAP(pScreen, MarkOverlappedWindows); | |
463 | RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); | |
464 | ||
465 | return result; | |
466 | } | |
467 | ||
468 | static void | |
469 | expose_1(WindowPtr pWin) | |
470 | { | |
471 | WindowPtr pChild; | |
472 | ||
473 | if (!pWin->realized) | |
474 | return; | |
475 | ||
476 | miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND); | |
477 | ||
478 | /* FIXME: comments in windowstr.h indicate that borderClip doesn't | |
479 | include subwindow visibility. But I'm not so sure.. so we may | |
480 | be exposing too much.. */ | |
481 | ||
482 | miSendExposures(pWin, &pWin->borderClip, | |
483 | pWin->drawable.x, pWin->drawable.y); | |
484 | ||
485 | for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib) | |
486 | expose_1(pChild); | |
487 | } | |
488 | ||
489 | void | |
490 | RootlessScreenExpose(ScreenPtr pScreen) | |
491 | { | |
492 | expose_1(pScreen->root); | |
493 | } | |
494 | ||
495 | ColormapPtr | |
496 | RootlessGetColormap(ScreenPtr pScreen) | |
497 | { | |
498 | RootlessScreenRec *s = SCREENREC(pScreen); | |
499 | ||
500 | return s->colormap; | |
501 | } | |
502 | ||
503 | static void | |
504 | RootlessInstallColormap(ColormapPtr pMap) | |
505 | { | |
506 | ScreenPtr pScreen = pMap->pScreen; | |
507 | RootlessScreenRec *s = SCREENREC(pScreen); | |
508 | ||
509 | SCREEN_UNWRAP(pScreen, InstallColormap); | |
510 | ||
511 | if (s->colormap != pMap) { | |
512 | s->colormap = pMap; | |
513 | s->colormap_changed = TRUE; | |
514 | RootlessQueueRedisplay(pScreen); | |
515 | } | |
516 | ||
517 | pScreen->InstallColormap(pMap); | |
518 | ||
519 | SCREEN_WRAP(pScreen, InstallColormap); | |
520 | } | |
521 | ||
522 | static void | |
523 | RootlessUninstallColormap(ColormapPtr pMap) | |
524 | { | |
525 | ScreenPtr pScreen = pMap->pScreen; | |
526 | RootlessScreenRec *s = SCREENREC(pScreen); | |
527 | ||
528 | SCREEN_UNWRAP(pScreen, UninstallColormap); | |
529 | ||
530 | if (s->colormap == pMap) | |
531 | s->colormap = NULL; | |
532 | ||
533 | pScreen->UninstallColormap(pMap); | |
534 | ||
535 | SCREEN_WRAP(pScreen, UninstallColormap); | |
536 | } | |
537 | ||
538 | static void | |
539 | RootlessStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef) | |
540 | { | |
541 | ScreenPtr pScreen = pMap->pScreen; | |
542 | RootlessScreenRec *s = SCREENREC(pScreen); | |
543 | ||
544 | SCREEN_UNWRAP(pScreen, StoreColors); | |
545 | ||
546 | if (s->colormap == pMap && ndef > 0) { | |
547 | s->colormap_changed = TRUE; | |
548 | RootlessQueueRedisplay(pScreen); | |
549 | } | |
550 | ||
551 | pScreen->StoreColors(pMap, ndef, pdef); | |
552 | ||
553 | SCREEN_WRAP(pScreen, StoreColors); | |
554 | } | |
555 | ||
556 | static CARD32 | |
557 | RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg) | |
558 | { | |
559 | RootlessScreenRec *screenRec = arg; | |
560 | ||
561 | if (!screenRec->redisplay_queued) { | |
562 | /* No update needed. Stop the timer. */ | |
563 | ||
564 | screenRec->redisplay_timer_set = FALSE; | |
565 | return 0; | |
566 | } | |
567 | ||
568 | screenRec->redisplay_queued = FALSE; | |
569 | ||
570 | /* Mark that we should redisplay before waiting for I/O next time */ | |
571 | screenRec->redisplay_expired = TRUE; | |
572 | ||
573 | /* Reinstall the timer immediately, so we get as close to our | |
574 | redisplay interval as possible. */ | |
575 | ||
576 | return ROOTLESS_REDISPLAY_DELAY; | |
577 | } | |
578 | ||
579 | /* | |
580 | * RootlessQueueRedisplay | |
581 | * Queue a redisplay after a timer delay to ensure we do not redisplay | |
582 | * too frequently. | |
583 | */ | |
584 | void | |
585 | RootlessQueueRedisplay(ScreenPtr pScreen) | |
586 | { | |
587 | RootlessScreenRec *screenRec = SCREENREC(pScreen); | |
588 | ||
589 | screenRec->redisplay_queued = TRUE; | |
590 | ||
591 | if (screenRec->redisplay_timer_set) | |
592 | return; | |
593 | ||
594 | screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer, | |
595 | 0, ROOTLESS_REDISPLAY_DELAY, | |
596 | RootlessRedisplayCallback, screenRec); | |
597 | screenRec->redisplay_timer_set = TRUE; | |
598 | } | |
599 | ||
600 | /* | |
601 | * RootlessBlockHandler | |
602 | * If the redisplay timer has expired, flush drawing before blocking | |
603 | * on select(). | |
604 | */ | |
605 | static void | |
606 | RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) | |
607 | { | |
608 | ScreenPtr pScreen = pbdata; | |
609 | RootlessScreenRec *screenRec = SCREENREC(pScreen); | |
610 | ||
611 | if (screenRec->redisplay_expired) { | |
612 | screenRec->redisplay_expired = FALSE; | |
613 | ||
614 | RootlessRedisplayScreen(pScreen); | |
615 | } | |
616 | } | |
617 | ||
618 | static void | |
619 | RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) | |
620 | { | |
621 | // nothing here | |
622 | } | |
623 | ||
624 | static Bool | |
625 | RootlessAllocatePrivates(ScreenPtr pScreen) | |
626 | { | |
627 | RootlessScreenRec *s; | |
628 | ||
629 | if (!dixRegisterPrivateKey | |
630 | (&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec))) | |
631 | return FALSE; | |
632 | if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) | |
633 | return FALSE; | |
634 | if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0)) | |
635 | return FALSE; | |
636 | if (!dixRegisterPrivateKey | |
637 | (&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0)) | |
638 | return FALSE; | |
639 | ||
640 | s = malloc(sizeof(RootlessScreenRec)); | |
641 | if (!s) | |
642 | return FALSE; | |
643 | SETSCREENREC(pScreen, s); | |
644 | ||
645 | s->pixmap_data = NULL; | |
646 | s->pixmap_data_size = 0; | |
647 | ||
648 | s->redisplay_timer = NULL; | |
649 | s->redisplay_timer_set = FALSE; | |
650 | ||
651 | return TRUE; | |
652 | } | |
653 | ||
654 | static void | |
655 | RootlessWrap(ScreenPtr pScreen) | |
656 | { | |
657 | RootlessScreenRec *s = SCREENREC(pScreen); | |
658 | ||
659 | #define WRAP(a) \ | |
660 | if (pScreen->a) { \ | |
661 | s->a = pScreen->a; \ | |
662 | } else { \ | |
663 | RL_DEBUG_MSG("null screen fn " #a "\n"); \ | |
664 | s->a = NULL; \ | |
665 | } \ | |
666 | pScreen->a = Rootless##a | |
667 | ||
668 | WRAP(CreateScreenResources); | |
669 | WRAP(CloseScreen); | |
670 | WRAP(CreateGC); | |
671 | WRAP(CopyWindow); | |
672 | WRAP(GetImage); | |
673 | WRAP(SourceValidate); | |
674 | WRAP(CreateWindow); | |
675 | WRAP(DestroyWindow); | |
676 | WRAP(RealizeWindow); | |
677 | WRAP(UnrealizeWindow); | |
678 | WRAP(MoveWindow); | |
679 | WRAP(PositionWindow); | |
680 | WRAP(ResizeWindow); | |
681 | WRAP(RestackWindow); | |
682 | WRAP(ReparentWindow); | |
683 | WRAP(ChangeBorderWidth); | |
684 | WRAP(MarkOverlappedWindows); | |
685 | WRAP(ValidateTree); | |
686 | WRAP(ChangeWindowAttributes); | |
687 | WRAP(InstallColormap); | |
688 | WRAP(UninstallColormap); | |
689 | WRAP(StoreColors); | |
690 | ||
691 | WRAP(SetShape); | |
692 | ||
693 | { | |
694 | // Composite and Glyphs don't use normal screen wrapping | |
695 | PictureScreenPtr ps = GetPictureScreen(pScreen); | |
696 | ||
697 | s->Composite = ps->Composite; | |
698 | ps->Composite = RootlessComposite; | |
699 | s->Glyphs = ps->Glyphs; | |
700 | ps->Glyphs = RootlessGlyphs; | |
701 | } | |
702 | ||
703 | // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? | |
704 | ||
705 | #undef WRAP | |
706 | } | |
707 | ||
708 | /* | |
709 | * RootlessInit | |
710 | * Called by the rootless implementation to initialize the rootless layer. | |
711 | * Rootless wraps lots of stuff and needs a bunch of devPrivates. | |
712 | */ | |
713 | Bool | |
714 | RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs) | |
715 | { | |
716 | RootlessScreenRec *s; | |
717 | ||
718 | if (!RootlessAllocatePrivates(pScreen)) | |
719 | return FALSE; | |
720 | ||
721 | s = SCREENREC(pScreen); | |
722 | ||
723 | s->imp = procs; | |
724 | s->colormap = NULL; | |
725 | s->redisplay_expired = FALSE; | |
726 | ||
727 | RootlessWrap(pScreen); | |
728 | ||
729 | if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler, | |
730 | RootlessWakeupHandler, | |
731 | (pointer) pScreen)) { | |
732 | return FALSE; | |
733 | } | |
734 | ||
735 | return TRUE; | |
736 | } | |
737 | ||
738 | void | |
739 | RootlessUpdateRooted(Bool state) | |
740 | { | |
741 | int i; | |
742 | ||
743 | if (!state) { | |
744 | for (i = 0; i < screenInfo.numScreens; i++) | |
745 | RootlessDisableRoot(screenInfo.screens[i]); | |
746 | } | |
747 | else { | |
748 | for (i = 0; i < screenInfo.numScreens; i++) | |
749 | RootlessEnableRoot(screenInfo.screens[i]); | |
750 | } | |
751 | } |