2
* Screen routines for generic rootless X server
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.
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:
16
* The above copyright notice and this permission notice shall be included in
17
* all copies or substantial portions of the Software.
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.
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.
32
#ifdef HAVE_DIX_CONFIG_H
33
#include <dix-config.h>
37
#include "scrnintstr.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"
46
#include <sys/types.h>
51
#include "rootlessCommon.h"
52
#include "rootlessWindow.h"
55
#ifndef ROOTLESS_REDISPLAY_DELAY
56
#define ROOTLESS_REDISPLAY_DELAY 10
59
extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
61
extern Bool RootlessCreateGC(GCPtr pGC);
64
DevPrivateKeyRec rootlessGCPrivateKeyRec;
65
DevPrivateKeyRec rootlessScreenPrivateKeyRec;
66
DevPrivateKeyRec rootlessWindowPrivateKeyRec;
67
DevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec;
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).
79
RootlessUpdateScreenPixmap(ScreenPtr pScreen)
81
RootlessScreenRec *s = SCREENREC(pScreen);
83
unsigned int rowbytes;
85
pPix = (*pScreen->GetScreenPixmap) (pScreen);
87
pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
88
(*pScreen->SetScreenPixmap) (pPix);
91
rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
93
if (s->pixmap_data_size < rowbytes) {
96
s->pixmap_data_size = rowbytes;
97
s->pixmap_data = malloc(s->pixmap_data_size);
98
if (s->pixmap_data == NULL)
101
memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
103
pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
105
BitsPerPixel(pScreen->rootDepth),
107
/* ModifyPixmapHeader ignores zero arguments, so install rowbytes
114
* RootlessCreateScreenResources
115
* Rootless implementations typically set a null framebuffer pointer, which
116
* causes problems with miCreateScreenResources. We fix things up here.
119
RootlessCreateScreenResources(ScreenPtr pScreen)
123
SCREEN_UNWRAP(pScreen, CreateScreenResources);
125
if (pScreen->CreateScreenResources != NULL)
126
ret = (*pScreen->CreateScreenResources) (pScreen);
128
SCREEN_WRAP(pScreen, CreateScreenResources);
133
/* Make sure we have a valid screen pixmap. */
135
RootlessUpdateScreenPixmap(pScreen);
141
RootlessCloseScreen(ScreenPtr pScreen)
143
RootlessScreenRec *s;
145
s = SCREENREC(pScreen);
147
// fixme unwrap everything that was wrapped?
148
pScreen->CloseScreen = s->CloseScreen;
150
if (s->pixmap_data != NULL) {
151
free(s->pixmap_data);
152
s->pixmap_data = NULL;
153
s->pixmap_data_size = 0;
157
return pScreen->CloseScreen(pScreen);
161
RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
162
unsigned int format, unsigned long planeMask, char *pdstLine)
164
ScreenPtr pScreen = pDrawable->pScreen;
166
SCREEN_UNWRAP(pScreen, GetImage);
168
if (pDrawable->type == DRAWABLE_WINDOW) {
170
RootlessWindowRec *winRec;
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);
176
// RedisplayScreen stops drawing, so we need to start it again
177
RootlessStartDrawing((WindowPtr) pDrawable);
179
/* Check that we have some place to read from. */
180
winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
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. */
189
x0 = pDrawable->x + sx;
190
y0 = pDrawable->y + sy;
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);
199
sx = x0 - pDrawable->x;
200
sy = y0 - pDrawable->y;
204
if (w <= 0 || h <= 0)
208
pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
211
SCREEN_WRAP(pScreen, GetImage);
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.
222
RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h,
223
unsigned int subWindowMode)
225
SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
226
if (pDrawable->type == DRAWABLE_WINDOW) {
227
WindowPtr pWin = (WindowPtr) pDrawable;
229
RootlessStartDrawing(pWin);
231
if (pDrawable->pScreen->SourceValidate) {
232
pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h,
235
SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
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)
243
ScreenPtr pScreen = pDst->pDrawable->pScreen;
244
PictureScreenPtr ps = GetPictureScreen(pScreen);
245
WindowPtr srcWin, dstWin, maskWin = NULL;
247
if (pMask) { // pMask can be NULL
248
maskWin = (pMask->pDrawable &&
249
pMask->pDrawable->type ==
250
DRAWABLE_WINDOW) ? (WindowPtr) pMask->pDrawable : NULL;
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;
257
// SCREEN_UNWRAP(ps, Composite);
258
ps->Composite = SCREENREC(pScreen)->Composite;
260
if (srcWin && IsFramedWindow(srcWin))
261
RootlessStartDrawing(srcWin);
262
if (maskWin && IsFramedWindow(maskWin))
263
RootlessStartDrawing(maskWin);
264
if (dstWin && IsFramedWindow(dstWin))
265
RootlessStartDrawing(dstWin);
267
ps->Composite(op, pSrc, pMask, pDst,
268
xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
270
if (dstWin && IsFramedWindow(dstWin)) {
271
RootlessDamageRect(dstWin, xDst, yDst, width, height);
274
ps->Composite = RootlessComposite;
275
// SCREEN_WRAP(ps, Composite);
279
RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
280
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
281
int nlist, GlyphListPtr list, GlyphPtr * glyphs)
283
ScreenPtr pScreen = pDst->pDrawable->pScreen;
284
PictureScreenPtr ps = GetPictureScreen(pScreen);
288
WindowPtr srcWin, dstWin;
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;
295
if (srcWin && IsFramedWindow(srcWin))
296
RootlessStartDrawing(srcWin);
297
if (dstWin && IsFramedWindow(dstWin))
298
RootlessStartDrawing(dstWin);
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);
306
if (dstWin && IsFramedWindow(dstWin)) {
315
/* Calling DamageRect for the bounding box of each glyph is
316
inefficient. So compute the union of all glyphs in a list
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;
329
x += glyph->info.xOff;
330
y += glyph->info.yOff;
333
short x1, y1, x2, y2;
337
x1 = x - glyph->info.x;
338
y1 = y - glyph->info.y;
339
x2 = x1 + glyph->info.width;
340
y2 = y1 + glyph->info.height;
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);
347
x += glyph->info.xOff;
348
y += glyph->info.yOff;
351
RootlessDamageBox(dstWin, &box);
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.
366
RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
370
ScreenPtr pScreen = pParent->drawable.pScreen;
372
SCREEN_UNWRAP(pScreen, ValidateTree);
373
RL_DEBUG_MSG("VALIDATETREE start ");
375
// Use our custom version to validate from root
376
if (IsRoot(pParent)) {
377
RL_DEBUG_MSG("custom ");
378
result = RootlessMiValidateTree(pParent, pChild, kind);
382
result = pScreen->ValidateTree(pParent, pChild, kind);
383
NORMAL_ROOT(pParent);
386
SCREEN_WRAP(pScreen, ValidateTree);
387
RL_DEBUG_MSG("VALIDATETREE end\n");
393
* RootlessMarkOverlappedWindows
394
* MarkOverlappedWindows is modified to ignore overlapping
398
RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
399
WindowPtr *ppLayerWin)
403
ScreenPtr pScreen = pWin->drawable.pScreen;
405
SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
406
RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
410
// root - mark nothing
411
RL_DEBUG_MSG("is root not marking ");
414
else if (!IsTopLevel(pWin)) {
415
// not top-level window - mark normally
416
result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
419
//top-level window - mark children ONLY - NO overlaps with sibs (?)
420
// This code copied from miMarkOverlappedWindows()
422
register WindowPtr pChild;
423
Bool anyMarked = FALSE;
424
MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
426
RL_DEBUG_MSG("is top level! ");
427
/* single layered systems are easy */
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.
438
if (pChild->viewable) {
439
if (RegionBroken(&pChild->winSize))
441
if (RegionBroken(&pChild->borderSize))
442
SetBorderSize(pChild);
443
(*MarkWindow) (pChild);
444
if (pChild->firstChild) {
445
pChild = pChild->firstChild;
449
while (!pChild->nextSib && (pChild != pWin))
450
pChild = pChild->parent;
453
pChild = pChild->nextSib;
458
(*MarkWindow) (pWin->parent);
462
SCREEN_WRAP(pScreen, MarkOverlappedWindows);
463
RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
469
expose_1(WindowPtr pWin)
476
miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
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.. */
482
miSendExposures(pWin, &pWin->borderClip,
483
pWin->drawable.x, pWin->drawable.y);
485
for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
490
RootlessScreenExpose(ScreenPtr pScreen)
492
expose_1(pScreen->root);
496
RootlessGetColormap(ScreenPtr pScreen)
498
RootlessScreenRec *s = SCREENREC(pScreen);
504
RootlessInstallColormap(ColormapPtr pMap)
506
ScreenPtr pScreen = pMap->pScreen;
507
RootlessScreenRec *s = SCREENREC(pScreen);
509
SCREEN_UNWRAP(pScreen, InstallColormap);
511
if (s->colormap != pMap) {
513
s->colormap_changed = TRUE;
514
RootlessQueueRedisplay(pScreen);
517
pScreen->InstallColormap(pMap);
519
SCREEN_WRAP(pScreen, InstallColormap);
523
RootlessUninstallColormap(ColormapPtr pMap)
525
ScreenPtr pScreen = pMap->pScreen;
526
RootlessScreenRec *s = SCREENREC(pScreen);
528
SCREEN_UNWRAP(pScreen, UninstallColormap);
530
if (s->colormap == pMap)
533
pScreen->UninstallColormap(pMap);
535
SCREEN_WRAP(pScreen, UninstallColormap);
539
RootlessStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
541
ScreenPtr pScreen = pMap->pScreen;
542
RootlessScreenRec *s = SCREENREC(pScreen);
544
SCREEN_UNWRAP(pScreen, StoreColors);
546
if (s->colormap == pMap && ndef > 0) {
547
s->colormap_changed = TRUE;
548
RootlessQueueRedisplay(pScreen);
551
pScreen->StoreColors(pMap, ndef, pdef);
553
SCREEN_WRAP(pScreen, StoreColors);
557
RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
559
RootlessScreenRec *screenRec = arg;
561
if (!screenRec->redisplay_queued) {
562
/* No update needed. Stop the timer. */
564
screenRec->redisplay_timer_set = FALSE;
568
screenRec->redisplay_queued = FALSE;
570
/* Mark that we should redisplay before waiting for I/O next time */
571
screenRec->redisplay_expired = TRUE;
573
/* Reinstall the timer immediately, so we get as close to our
574
redisplay interval as possible. */
576
return ROOTLESS_REDISPLAY_DELAY;
580
* RootlessQueueRedisplay
581
* Queue a redisplay after a timer delay to ensure we do not redisplay
585
RootlessQueueRedisplay(ScreenPtr pScreen)
587
RootlessScreenRec *screenRec = SCREENREC(pScreen);
589
screenRec->redisplay_queued = TRUE;
591
if (screenRec->redisplay_timer_set)
594
screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
595
0, ROOTLESS_REDISPLAY_DELAY,
596
RootlessRedisplayCallback, screenRec);
597
screenRec->redisplay_timer_set = TRUE;
601
* RootlessBlockHandler
602
* If the redisplay timer has expired, flush drawing before blocking
606
RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
608
ScreenPtr pScreen = pbdata;
609
RootlessScreenRec *screenRec = SCREENREC(pScreen);
611
if (screenRec->redisplay_expired) {
612
screenRec->redisplay_expired = FALSE;
614
RootlessRedisplayScreen(pScreen);
619
RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
625
RootlessAllocatePrivates(ScreenPtr pScreen)
627
RootlessScreenRec *s;
629
if (!dixRegisterPrivateKey
630
(&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
632
if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
634
if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
636
if (!dixRegisterPrivateKey
637
(&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
640
s = malloc(sizeof(RootlessScreenRec));
643
SETSCREENREC(pScreen, s);
645
s->pixmap_data = NULL;
646
s->pixmap_data_size = 0;
648
s->redisplay_timer = NULL;
649
s->redisplay_timer_set = FALSE;
655
RootlessWrap(ScreenPtr pScreen)
657
RootlessScreenRec *s = SCREENREC(pScreen);
663
RL_DEBUG_MSG("null screen fn " #a "\n"); \
666
pScreen->a = Rootless##a
668
WRAP(CreateScreenResources);
673
WRAP(SourceValidate);
677
WRAP(UnrealizeWindow);
679
WRAP(PositionWindow);
682
WRAP(ReparentWindow);
683
WRAP(ChangeBorderWidth);
684
WRAP(MarkOverlappedWindows);
686
WRAP(ChangeWindowAttributes);
687
WRAP(InstallColormap);
688
WRAP(UninstallColormap);
694
// Composite and Glyphs don't use normal screen wrapping
695
PictureScreenPtr ps = GetPictureScreen(pScreen);
697
s->Composite = ps->Composite;
698
ps->Composite = RootlessComposite;
699
s->Glyphs = ps->Glyphs;
700
ps->Glyphs = RootlessGlyphs;
703
// WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
710
* Called by the rootless implementation to initialize the rootless layer.
711
* Rootless wraps lots of stuff and needs a bunch of devPrivates.
714
RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
716
RootlessScreenRec *s;
718
if (!RootlessAllocatePrivates(pScreen))
721
s = SCREENREC(pScreen);
725
s->redisplay_expired = FALSE;
727
RootlessWrap(pScreen);
729
if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
730
RootlessWakeupHandler,
731
(pointer) pScreen)) {
739
RootlessUpdateRooted(Bool state)
744
for (i = 0; i < screenInfo.numScreens; i++)
745
RootlessDisableRoot(screenInfo.screens[i]);
748
for (i = 0; i < screenInfo.numScreens; i++)
749
RootlessEnableRoot(screenInfo.screens[i]);