1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Copyright © 2003 Keith Packard
24 *
25 * Permission to use, copy, modify, distribute, and sell this software and its
26 * documentation for any purpose is hereby granted without fee, provided that
27 * the above copyright notice appear in all copies and that both that
28 * copyright notice and this permission notice appear in supporting
29 * documentation, and that the name of Keith Packard not be used in
30 * advertising or publicity pertaining to distribution of the software without
31 * specific, written prior permission.  Keith Packard makes no
32 * representations about the suitability of this software for any purpose.  It
33 * is provided "as is" without express or implied warranty.
34 *
35 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
39 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
40 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41 * PERFORMANCE OF THIS SOFTWARE.
42 */
43
44#ifdef HAVE_DIX_CONFIG_H
45#include <dix-config.h>
46#endif
47
48#include "compint.h"
49#include "compositeext.h"
50
51DevPrivateKeyRec CompScreenPrivateKeyRec;
52DevPrivateKeyRec CompWindowPrivateKeyRec;
53DevPrivateKeyRec CompSubwindowsPrivateKeyRec;
54
55static Bool
56compCloseScreen (int index, ScreenPtr pScreen)
57{
58    CompScreenPtr   cs = GetCompScreen (pScreen);
59    Bool	    ret;
60
61    free(cs->alternateVisuals);
62
63    pScreen->CloseScreen = cs->CloseScreen;
64    pScreen->InstallColormap = cs->InstallColormap;
65    pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes;
66    pScreen->ReparentWindow = cs->ReparentWindow;
67    pScreen->ConfigNotify = cs->ConfigNotify;
68    pScreen->MoveWindow = cs->MoveWindow;
69    pScreen->ResizeWindow = cs->ResizeWindow;
70    pScreen->ChangeBorderWidth = cs->ChangeBorderWidth;
71
72    pScreen->ClipNotify = cs->ClipNotify;
73    pScreen->UnrealizeWindow = cs->UnrealizeWindow;
74    pScreen->RealizeWindow = cs->RealizeWindow;
75    pScreen->DestroyWindow = cs->DestroyWindow;
76    pScreen->CreateWindow = cs->CreateWindow;
77    pScreen->CopyWindow = cs->CopyWindow;
78    pScreen->PositionWindow = cs->PositionWindow;
79
80    pScreen->GetImage = cs->GetImage;
81    pScreen->SourceValidate = cs->SourceValidate;
82
83    free(cs);
84    dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, NULL);
85    ret = (*pScreen->CloseScreen) (index, pScreen);
86
87    return ret;
88}
89
90static void
91compInstallColormap (ColormapPtr pColormap)
92{
93    VisualPtr	    pVisual = pColormap->pVisual;
94    ScreenPtr	    pScreen = pColormap->pScreen;
95    CompScreenPtr   cs = GetCompScreen (pScreen);
96    int		    a;
97
98    for (a = 0; a < cs->numAlternateVisuals; a++)
99	if (pVisual->vid == cs->alternateVisuals[a])
100	    return;
101    pScreen->InstallColormap = cs->InstallColormap;
102    (*pScreen->InstallColormap) (pColormap);
103    cs->InstallColormap = pScreen->InstallColormap;
104    pScreen->InstallColormap = compInstallColormap;
105}
106
107/* Fake backing store via automatic redirection */
108static Bool
109compChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
110{
111    ScreenPtr pScreen = pWin->drawable.pScreen;
112    CompScreenPtr cs = GetCompScreen (pScreen);
113    Bool ret;
114
115    pScreen->ChangeWindowAttributes = cs->ChangeWindowAttributes;
116    ret = pScreen->ChangeWindowAttributes(pWin, mask);
117
118    if (ret && (mask & CWBackingStore) &&
119	    pScreen->backingStoreSupport != NotUseful) {
120	if (pWin->backingStore != NotUseful) {
121	    compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic);
122	    pWin->backStorage = (pointer) (intptr_t) 1;
123	} else {
124	    compUnredirectWindow(serverClient, pWin,
125				 CompositeRedirectAutomatic);
126	    pWin->backStorage = NULL;
127	}
128    }
129
130    pScreen->ChangeWindowAttributes = compChangeWindowAttributes;
131
132    return ret;
133}
134
135static void
136compGetImage (DrawablePtr pDrawable,
137	      int sx, int sy,
138	      int w, int h,
139	      unsigned int format,
140	      unsigned long planemask,
141	      char *pdstLine)
142{
143    ScreenPtr pScreen = pDrawable->pScreen;
144    CompScreenPtr cs = GetCompScreen (pScreen);
145
146    pScreen->GetImage = cs->GetImage;
147    if (pDrawable->type == DRAWABLE_WINDOW)
148	compPaintChildrenToWindow ((WindowPtr) pDrawable);
149    (*pScreen->GetImage) (pDrawable, sx, sy, w, h, format, planemask, pdstLine);
150    cs->GetImage = pScreen->GetImage;
151    pScreen->GetImage = compGetImage;
152}
153
154static void compSourceValidate(DrawablePtr pDrawable,
155			       int x, int y,
156			       int width, int height,
157			       unsigned int subWindowMode)
158{
159    ScreenPtr pScreen = pDrawable->pScreen;
160    CompScreenPtr cs = GetCompScreen (pScreen);
161
162    pScreen->SourceValidate = cs->SourceValidate;
163    if (pDrawable->type == DRAWABLE_WINDOW && subWindowMode == IncludeInferiors)
164	compPaintChildrenToWindow ((WindowPtr) pDrawable);
165    if (pScreen->SourceValidate)
166	(*pScreen->SourceValidate) (pDrawable, x, y, width, height,
167				    subWindowMode);
168    cs->SourceValidate = pScreen->SourceValidate;
169    pScreen->SourceValidate = compSourceValidate;
170}
171
172/*
173 * Add alternate visuals -- always expose an ARGB32 and RGB24 visual
174 */
175
176static DepthPtr
177compFindVisuallessDepth (ScreenPtr pScreen, int d)
178{
179    int		i;
180
181    for (i = 0; i < pScreen->numDepths; i++)
182    {
183	DepthPtr    depth = &pScreen->allowedDepths[i];
184	if (depth->depth == d)
185	{
186	    /*
187	     * Make sure it doesn't have visuals already
188	     */
189	    if (depth->numVids)
190		return 0;
191	    /*
192	     * looks fine
193	     */
194	    return depth;
195	}
196    }
197    /*
198     * If there isn't one, then it's gonna be hard to have
199     * an associated visual
200     */
201    return 0;
202}
203
204/*
205 * Add a list of visual IDs to the list of visuals to implicitly redirect.
206 */
207static Bool
208compRegisterAlternateVisuals (CompScreenPtr cs, VisualID *vids, int nVisuals)
209{
210    VisualID *p;
211
212    p = realloc(cs->alternateVisuals,
213		 sizeof(VisualID) * (cs->numAlternateVisuals + nVisuals));
214    if(p == NULL)
215	return FALSE;
216
217    memcpy(&p[cs->numAlternateVisuals], vids, sizeof(VisualID) * nVisuals);
218
219    cs->alternateVisuals = p;
220    cs->numAlternateVisuals += nVisuals;
221
222    return TRUE;
223}
224
225Bool CompositeRegisterAlternateVisuals (ScreenPtr pScreen, VisualID *vids,
226					int nVisuals)
227{
228    CompScreenPtr cs = GetCompScreen (pScreen);
229    return compRegisterAlternateVisuals(cs, vids, nVisuals);
230}
231
232typedef struct _alternateVisual {
233    int		depth;
234    CARD32	format;
235} CompAlternateVisual;
236
237static CompAlternateVisual  altVisuals[] = {
238#if COMP_INCLUDE_RGB24_VISUAL
239    {	24,	PICT_r8g8b8 },
240#endif
241    {	32,	PICT_a8r8g8b8 },
242};
243
244static const int NUM_COMP_ALTERNATE_VISUALS = sizeof(altVisuals) /
245					      sizeof(CompAlternateVisual);
246
247static Bool
248compAddAlternateVisual(ScreenPtr pScreen, CompScreenPtr cs,
249		       CompAlternateVisual *alt)
250{
251    VisualPtr	    visual;
252    DepthPtr	    depth;
253    PictFormatPtr   pPictFormat;
254    unsigned long   alphaMask;
255
256    /*
257     * The ARGB32 visual is always available.  Other alternate depth visuals
258     * are only provided if their depth is less than the root window depth.
259     * There's no deep reason for this.
260     */
261    if (alt->depth >= pScreen->rootDepth && alt->depth != 32)
262	return FALSE;
263
264    depth = compFindVisuallessDepth (pScreen, alt->depth);
265    if (!depth)
266	/* alt->depth doesn't exist or already has alternate visuals. */
267	return TRUE;
268
269    pPictFormat = PictureMatchFormat (pScreen, alt->depth, alt->format);
270    if (!pPictFormat)
271	return FALSE;
272
273    if (ResizeVisualArray(pScreen, 1, depth) == FALSE) {
274        return FALSE;
275    }
276
277    visual = pScreen->visuals + (pScreen->numVisuals - 1); /* the new one */
278
279    /* Initialize the visual */
280    visual->bitsPerRGBValue = 8;
281    if (PICT_FORMAT_TYPE(alt->format) == PICT_TYPE_COLOR) {
282	visual->class = PseudoColor;
283	visual->nplanes = PICT_FORMAT_BPP(alt->format);
284	visual->ColormapEntries = 1 << visual->nplanes;
285    } else {
286	DirectFormatRec *direct = &pPictFormat->direct;
287	visual->class = TrueColor;
288	visual->redMask   = ((unsigned long)direct->redMask) << direct->red;
289	visual->greenMask = ((unsigned long)direct->greenMask) << direct->green;
290	visual->blueMask  = ((unsigned long)direct->blueMask) << direct->blue;
291	alphaMask = ((unsigned long)direct->alphaMask) << direct->alpha;
292	visual->offsetRed   = direct->red;
293	visual->offsetGreen = direct->green;
294	visual->offsetBlue  = direct->blue;
295	/*
296	 * Include A bits in this (unlike GLX which includes only RGB)
297	 * This lets DIX compute suitable masks for colormap allocations
298	 */
299	visual->nplanes = Ones (visual->redMask |
300		visual->greenMask |
301		visual->blueMask |
302		alphaMask);
303	/* find widest component */
304	visual->ColormapEntries = (1 << max (Ones (visual->redMask),
305		    max (Ones (visual->greenMask),
306			Ones (visual->blueMask))));
307    }
308
309    /* remember the visual ID to detect auto-update windows */
310    compRegisterAlternateVisuals(cs, &visual->vid, 1);
311
312    return TRUE;
313}
314
315static Bool
316compAddAlternateVisuals (ScreenPtr pScreen, CompScreenPtr cs)
317{
318    int alt, ret = 0;
319
320    for (alt = 0; alt < NUM_COMP_ALTERNATE_VISUALS; alt++)
321	ret |= compAddAlternateVisual(pScreen, cs, altVisuals + alt);
322
323    return !!ret;
324}
325
326Bool
327compScreenInit (ScreenPtr pScreen)
328{
329    CompScreenPtr   cs;
330
331    if (!dixRegisterPrivateKey(&CompScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
332	return FALSE;
333    if (!dixRegisterPrivateKey(&CompWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
334	return FALSE;
335    if (!dixRegisterPrivateKey(&CompSubwindowsPrivateKeyRec, PRIVATE_WINDOW, 0))
336	return FALSE;
337
338    if (GetCompScreen (pScreen))
339	return TRUE;
340    cs = (CompScreenPtr) malloc(sizeof (CompScreenRec));
341    if (!cs)
342	return FALSE;
343
344    cs->overlayWid = FakeClientID(0);
345    cs->pOverlayWin = NULL;
346    cs->pOverlayClients = NULL;
347
348    cs->numAlternateVisuals = 0;
349    cs->alternateVisuals = NULL;
350
351    if (!compAddAlternateVisuals (pScreen, cs))
352    {
353	free(cs);
354	return FALSE;
355    }
356
357    cs->PositionWindow = pScreen->PositionWindow;
358    pScreen->PositionWindow = compPositionWindow;
359
360    cs->CopyWindow = pScreen->CopyWindow;
361    pScreen->CopyWindow = compCopyWindow;
362
363    cs->CreateWindow = pScreen->CreateWindow;
364    pScreen->CreateWindow = compCreateWindow;
365
366    cs->DestroyWindow = pScreen->DestroyWindow;
367    pScreen->DestroyWindow = compDestroyWindow;
368
369    cs->RealizeWindow = pScreen->RealizeWindow;
370    pScreen->RealizeWindow = compRealizeWindow;
371
372    cs->UnrealizeWindow = pScreen->UnrealizeWindow;
373    pScreen->UnrealizeWindow = compUnrealizeWindow;
374
375    cs->ClipNotify = pScreen->ClipNotify;
376    pScreen->ClipNotify = compClipNotify;
377
378    cs->ConfigNotify = pScreen->ConfigNotify;
379    pScreen->ConfigNotify = compConfigNotify;
380
381    cs->MoveWindow = pScreen->MoveWindow;
382    pScreen->MoveWindow = compMoveWindow;
383
384    cs->ResizeWindow = pScreen->ResizeWindow;
385    pScreen->ResizeWindow = compResizeWindow;
386
387    cs->ChangeBorderWidth = pScreen->ChangeBorderWidth;
388    pScreen->ChangeBorderWidth = compChangeBorderWidth;
389
390    cs->ReparentWindow = pScreen->ReparentWindow;
391    pScreen->ReparentWindow = compReparentWindow;
392
393    cs->InstallColormap = pScreen->InstallColormap;
394    pScreen->InstallColormap = compInstallColormap;
395
396    cs->ChangeWindowAttributes = pScreen->ChangeWindowAttributes;
397    pScreen->ChangeWindowAttributes = compChangeWindowAttributes;
398
399    cs->BlockHandler = NULL;
400
401    cs->CloseScreen = pScreen->CloseScreen;
402    pScreen->CloseScreen = compCloseScreen;
403
404    cs->GetImage = pScreen->GetImage;
405    pScreen->GetImage = compGetImage;
406
407    cs->SourceValidate = pScreen->SourceValidate;
408    pScreen->SourceValidate = compSourceValidate;
409
410    dixSetPrivate(&pScreen->devPrivates, CompScreenPrivateKey, cs);
411
412    RegisterRealChildHeadProc(CompositeRealChildHead);
413
414    return TRUE;
415}
416