xenocara/xserver/composite/compext.c

764 lines
21 KiB
C

/*
* Copyright © 2006 Sun Microsystems
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Sun Microsystems not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Sun Microsystems makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* Copyright © 2003 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "compint.h"
#include "xace.h"
#define SERVER_COMPOSITE_MAJOR 0
#define SERVER_COMPOSITE_MINOR 4
static CARD8 CompositeReqCode;
static DevPrivateKey CompositeClientPrivateKey = &CompositeClientPrivateKey;
RESTYPE CompositeClientWindowType;
RESTYPE CompositeClientSubwindowsType;
static RESTYPE CompositeClientOverlayType;
static void deleteCompOverlayClient (CompOverlayClientPtr pOcToDel,
ScreenPtr pScreen);
typedef struct _CompositeClient {
int major_version;
int minor_version;
} CompositeClientRec, *CompositeClientPtr;
#define GetCompositeClient(pClient) ((CompositeClientPtr) \
dixLookupPrivate(&(pClient)->devPrivates, CompositeClientPrivateKey))
static void
CompositeClientCallback (CallbackListPtr *list,
pointer closure,
pointer data)
{
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
ClientPtr pClient = clientinfo->client;
CompositeClientPtr pCompositeClient = GetCompositeClient (pClient);
pCompositeClient->major_version = 0;
pCompositeClient->minor_version = 0;
}
static void
CompositeResetProc (ExtensionEntry *extEntry)
{
}
static int
FreeCompositeClientWindow (pointer value, XID ccwid)
{
WindowPtr pWin = value;
compFreeClientWindow (pWin, ccwid);
return Success;
}
static int
FreeCompositeClientSubwindows (pointer value, XID ccwid)
{
WindowPtr pWin = value;
compFreeClientSubwindows (pWin, ccwid);
return Success;
}
static int
FreeCompositeClientOverlay (pointer value, XID ccwid)
{
CompOverlayClientPtr pOc = (CompOverlayClientPtr) value;
ScreenPtr pScreen = pOc->pScreen;
CompScreenPtr cs;
deleteCompOverlayClient(pOc, pScreen);
/* Unmap overlay window when there are no more clients using it */
cs = GetCompScreen(pScreen);
if (cs->pOverlayClients == NULL) {
if (cs->pOverlayWin != NULL) {
UnmapWindow(cs->pOverlayWin, FALSE);
}
}
return Success;
}
static int
ProcCompositeQueryVersion (ClientPtr client)
{
CompositeClientPtr pCompositeClient = GetCompositeClient (client);
xCompositeQueryVersionReply rep;
register int n;
REQUEST(xCompositeQueryVersionReq);
REQUEST_SIZE_MATCH(xCompositeQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (stuff->majorVersion < SERVER_COMPOSITE_MAJOR) {
rep.majorVersion = stuff->majorVersion;
rep.minorVersion = stuff->minorVersion;
} else {
rep.majorVersion = SERVER_COMPOSITE_MAJOR;
rep.minorVersion = SERVER_COMPOSITE_MINOR;
}
pCompositeClient->major_version = rep.majorVersion;
pCompositeClient->minor_version = rep.minorVersion;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.majorVersion, n);
swapl(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xCompositeQueryVersionReply), (char *)&rep);
return(client->noClientException);
}
static int
ProcCompositeRedirectWindow (ClientPtr client)
{
WindowPtr pWin;
int rc;
REQUEST(xCompositeRedirectWindowReq);
REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq);
rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client,
DixSetAttrAccess|DixManageAccess|DixBlendAccess);
if (rc != Success)
{
client->errorValue = stuff->window;
return (rc == BadValue) ? BadWindow : rc;
}
return compRedirectWindow (client, pWin, stuff->update);
}
static int
ProcCompositeRedirectSubwindows (ClientPtr client)
{
WindowPtr pWin;
int rc;
REQUEST(xCompositeRedirectSubwindowsReq);
REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq);
rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client,
DixSetAttrAccess|DixManageAccess|DixBlendAccess);
if (rc != Success)
{
client->errorValue = stuff->window;
return (rc == BadValue) ? BadWindow : rc;
}
return compRedirectSubwindows (client, pWin, stuff->update);
}
static int
ProcCompositeUnredirectWindow (ClientPtr client)
{
WindowPtr pWin;
REQUEST(xCompositeUnredirectWindowReq);
REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq);
pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW);
if (!pWin)
{
client->errorValue = stuff->window;
return BadWindow;
}
return compUnredirectWindow (client, pWin, stuff->update);
}
static int
ProcCompositeUnredirectSubwindows (ClientPtr client)
{
WindowPtr pWin;
REQUEST(xCompositeUnredirectSubwindowsReq);
REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq);
pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW);
if (!pWin)
{
client->errorValue = stuff->window;
return BadWindow;
}
return compUnredirectSubwindows (client, pWin, stuff->update);
}
static int
ProcCompositeCreateRegionFromBorderClip (ClientPtr client)
{
WindowPtr pWin;
CompWindowPtr cw;
RegionPtr pBorderClip, pRegion;
int rc;
REQUEST(xCompositeCreateRegionFromBorderClipReq);
REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq);
rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client,
DixGetAttrAccess);
if (rc != Success)
{
client->errorValue = stuff->window;
return (rc == BadValue) ? BadWindow : rc;
}
LEGAL_NEW_RESOURCE (stuff->region, client);
cw = GetCompWindow (pWin);
if (cw)
pBorderClip = &cw->borderClip;
else
pBorderClip = &pWin->borderClip;
pRegion = XFixesRegionCopy (pBorderClip);
if (!pRegion)
return BadAlloc;
REGION_TRANSLATE (pScreen, pRegion, -pWin->drawable.x, -pWin->drawable.y);
if (!AddResource (stuff->region, RegionResType, (pointer) pRegion))
return BadAlloc;
return(client->noClientException);
}
static int
ProcCompositeNameWindowPixmap (ClientPtr client)
{
WindowPtr pWin;
CompWindowPtr cw;
PixmapPtr pPixmap;
int rc;
REQUEST(xCompositeNameWindowPixmapReq);
REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq);
rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client,
DixGetAttrAccess);
if (rc != Success)
{
client->errorValue = stuff->window;
return (rc == BadValue) ? BadWindow : rc;
}
if (!pWin->viewable)
return BadMatch;
LEGAL_NEW_RESOURCE (stuff->pixmap, client);
cw = GetCompWindow (pWin);
if (!cw)
return BadMatch;
pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
if (!pPixmap)
return BadMatch;
/* security creation/labeling check */
rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
pPixmap, RT_WINDOW, pWin, DixCreateAccess);
if (rc != Success)
return rc;
++pPixmap->refcnt;
if (!AddResource (stuff->pixmap, RT_PIXMAP, (pointer) pPixmap))
return BadAlloc;
return(client->noClientException);
}
/*
* Routines for manipulating the per-screen overlay clients list.
* This list indicates which clients have called GetOverlayWindow
* for this screen.
*/
/* Return the screen's overlay client list element for the given client */
static CompOverlayClientPtr
findCompOverlayClient (ClientPtr pClient, ScreenPtr pScreen)
{
CompScreenPtr cs = GetCompScreen(pScreen);
CompOverlayClientPtr pOc;
for (pOc = cs->pOverlayClients; pOc != NULL; pOc = pOc->pNext) {
if (pOc->pClient == pClient) {
return pOc;
}
}
return NULL;
}
static int
createCompOverlayClient (ClientPtr pClient, ScreenPtr pScreen)
{
CompScreenPtr cs = GetCompScreen(pScreen);
CompOverlayClientPtr pOc;
pOc = (CompOverlayClientPtr) xalloc(sizeof(CompOverlayClientRec));
if (pOc == NULL) {
return BadAlloc;
}
pOc->pClient = pClient;
pOc->pScreen = pScreen;
pOc->resource = FakeClientID(pClient->index);
pOc->pNext = cs->pOverlayClients;
cs->pOverlayClients = pOc;
/*
* Create a resource for this element so it can be deleted
* when the client goes away.
*/
if (!AddResource (pOc->resource, CompositeClientOverlayType,
(pointer) pOc)) {
xfree(pOc);
return BadAlloc;
}
return Success;
}
/*
* Delete the given overlay client list element from its screen list.
*/
static void
deleteCompOverlayClient (CompOverlayClientPtr pOcToDel, ScreenPtr pScreen)
{
CompScreenPtr cs = GetCompScreen(pScreen);
CompOverlayClientPtr pOc, pNext;
CompOverlayClientPtr pOcLast = NULL;
pOc = cs->pOverlayClients;
while (pOc != NULL) {
pNext = pOc->pNext;
if (pOc == pOcToDel) {
xfree(pOc);
if (pOcLast == NULL) {
cs->pOverlayClients = pNext;
} else {
pOcLast->pNext = pNext;
}
break;
}
pOcLast = pOc;
pOc = pNext;
}
}
/*
* Delete all the hide-counts list elements for this screen.
*/
void
deleteCompOverlayClientsForScreen (ScreenPtr pScreen)
{
CompScreenPtr cs = GetCompScreen(pScreen);
CompOverlayClientPtr pOc, pTmp;
pOc = cs->pOverlayClients;
while (pOc != NULL) {
pTmp = pOc->pNext;
FreeResource(pOc->resource, 0);
pOc = pTmp;
}
cs->pOverlayClients = NULL;
}
/*
** If necessary, create the overlay window. And map it
** Note: I found it excessively difficult to destroy this window
** during compCloseScreen; DeleteWindow can't be called because
** the input devices are already shut down. So we are going to
** just allocate an overlay window once per screen per X server
** invocation.
*/
static WindowPtr
createOverlayWindow (ScreenPtr pScreen)
{
int wid = FakeClientID(0);
WindowPtr pWin;
XID overrideRedirect = TRUE;
int result;
pWin = CreateWindow (
wid, WindowTable[pScreen->myNum],
0, 0, pScreen->width, pScreen->height, 0,
InputOutput, CWOverrideRedirect, &overrideRedirect,
WindowTable[pScreen->myNum]->drawable.depth,
serverClient, pScreen->rootVisual, &result);
if (pWin == NULL) {
return NULL;
}
if (!AddResource(wid, RT_WINDOW, (pointer)pWin)) {
DeleteWindow(pWin, None);
return NULL;
}
return pWin;
}
static int
ProcCompositeGetOverlayWindow (ClientPtr client)
{
REQUEST(xCompositeGetOverlayWindowReq);
xCompositeGetOverlayWindowReply rep;
WindowPtr pWin;
ScreenPtr pScreen;
CompScreenPtr cs;
CompOverlayClientPtr pOc;
int rc;
REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq);
rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client,
DixGetAttrAccess);
if (rc != Success)
{
client->errorValue = stuff->window;
return (rc == BadValue) ? BadWindow : rc;
}
pScreen = pWin->drawable.pScreen;
cs = GetCompScreen(pScreen);
if (cs->pOverlayWin == NULL) {
cs->pOverlayWin = createOverlayWindow(pScreen);
if (cs->pOverlayWin == NULL) {
return BadAlloc;
}
}
rc = XaceHook(XACE_RESOURCE_ACCESS, client, cs->pOverlayWin->drawable.id,
RT_WINDOW, cs->pOverlayWin, RT_NONE, NULL, DixGetAttrAccess);
if (rc != Success)
return rc;
MapWindow(cs->pOverlayWin, serverClient);
/* Record that client is using this overlay window */
pOc = findCompOverlayClient(client, pScreen);
if (pOc == NULL) {
int ret = createCompOverlayClient(client, pScreen);
if (ret != Success) {
return ret;
}
}
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.length = 0;
rep.overlayWin = cs->pOverlayWin->drawable.id;
if (client->swapped)
{
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.overlayWin, n);
}
(void) WriteToClient(client, sz_xCompositeGetOverlayWindowReply, (char *)&rep);
return client->noClientException;
}
static int
ProcCompositeReleaseOverlayWindow (ClientPtr client)
{
REQUEST(xCompositeReleaseOverlayWindowReq);
WindowPtr pWin;
ScreenPtr pScreen;
CompOverlayClientPtr pOc;
CompScreenPtr cs;
REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq);
pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW);
if (!pWin)
{
client->errorValue = stuff->window;
return BadWindow;
}
pScreen = pWin->drawable.pScreen;
/*
* Has client queried a reference to the overlay window
* on this screen? If not, generate an error.
*/
pOc = findCompOverlayClient(client, pWin->drawable.pScreen);
if (pOc == NULL) {
return BadMatch;
}
/* The delete function will free the client structure */
FreeResource (pOc->resource, 0);
cs = GetCompScreen(pScreen);
if (cs->pOverlayClients == NULL) {
UnmapWindow(cs->pOverlayWin, FALSE);
}
return client->noClientException;
}
static int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = {
ProcCompositeQueryVersion,
ProcCompositeRedirectWindow,
ProcCompositeRedirectSubwindows,
ProcCompositeUnredirectWindow,
ProcCompositeUnredirectSubwindows,
ProcCompositeCreateRegionFromBorderClip,
ProcCompositeNameWindowPixmap,
ProcCompositeGetOverlayWindow,
ProcCompositeReleaseOverlayWindow,
};
static int
ProcCompositeDispatch (ClientPtr client)
{
REQUEST(xReq);
if (stuff->data < CompositeNumberRequests)
return (*ProcCompositeVector[stuff->data]) (client);
else
return BadRequest;
}
static int
SProcCompositeQueryVersion (ClientPtr client)
{
int n;
REQUEST(xCompositeQueryVersionReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeQueryVersionReq);
swapl(&stuff->majorVersion, n);
swapl(&stuff->minorVersion, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeRedirectWindow (ClientPtr client)
{
int n;
REQUEST(xCompositeRedirectWindowReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq);
swapl (&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeRedirectSubwindows (ClientPtr client)
{
int n;
REQUEST(xCompositeRedirectSubwindowsReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq);
swapl (&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeUnredirectWindow (ClientPtr client)
{
int n;
REQUEST(xCompositeUnredirectWindowReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq);
swapl (&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeUnredirectSubwindows (ClientPtr client)
{
int n;
REQUEST(xCompositeUnredirectSubwindowsReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq);
swapl (&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeCreateRegionFromBorderClip (ClientPtr client)
{
int n;
REQUEST(xCompositeCreateRegionFromBorderClipReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq);
swapl (&stuff->region, n);
swapl (&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeNameWindowPixmap (ClientPtr client)
{
int n;
REQUEST(xCompositeNameWindowPixmapReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq);
swapl (&stuff->window, n);
swapl (&stuff->pixmap, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeGetOverlayWindow (ClientPtr client)
{
int n;
REQUEST(xCompositeGetOverlayWindowReq);
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq);
swapl(&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int
SProcCompositeReleaseOverlayWindow (ClientPtr client)
{
int n;
REQUEST(xCompositeReleaseOverlayWindowReq);
swaps (&stuff->length, n);
REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq);
swapl(&stuff->window, n);
return (*ProcCompositeVector[stuff->compositeReqType]) (client);
}
static int (*SProcCompositeVector[CompositeNumberRequests])(ClientPtr) = {
SProcCompositeQueryVersion,
SProcCompositeRedirectWindow,
SProcCompositeRedirectSubwindows,
SProcCompositeUnredirectWindow,
SProcCompositeUnredirectSubwindows,
SProcCompositeCreateRegionFromBorderClip,
SProcCompositeNameWindowPixmap,
SProcCompositeGetOverlayWindow,
SProcCompositeReleaseOverlayWindow,
};
static int
SProcCompositeDispatch (ClientPtr client)
{
REQUEST(xReq);
if (stuff->data < CompositeNumberRequests)
return (*SProcCompositeVector[stuff->data]) (client);
else
return BadRequest;
}
void
CompositeExtensionInit (void)
{
ExtensionEntry *extEntry;
int s;
/* Assume initialization is going to fail */
noCompositeExtension = TRUE;
for (s = 0; s < screenInfo.numScreens; s++) {
ScreenPtr pScreen = screenInfo.screens[s];
VisualPtr vis;
/* Composite on 8bpp pseudocolor root windows appears to fail, so
* just disable it on anything pseudocolor for safety.
*/
for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++)
;
if ((vis->class | DynamicClass) == PseudoColor)
return;
/* Ensure that Render is initialized, which is required for automatic
* compositing.
*/
if (GetPictureScreenIfSet(pScreen) == NULL)
return;
}
#ifdef PANORAMIX
/* Xinerama's rewriting of window drawing before Composite gets to it
* breaks Composite.
*/
if (!noPanoramiXExtension)
return;
#endif
CompositeClientWindowType = CreateNewResourceType (FreeCompositeClientWindow);
if (!CompositeClientWindowType)
return;
CompositeClientSubwindowsType = CreateNewResourceType (FreeCompositeClientSubwindows);
if (!CompositeClientSubwindowsType)
return;
CompositeClientOverlayType = CreateNewResourceType (FreeCompositeClientOverlay);
if (!CompositeClientOverlayType)
return;
if (!dixRequestPrivate(CompositeClientPrivateKey,
sizeof(CompositeClientRec)))
return;
if (!AddCallback (&ClientStateCallback, CompositeClientCallback, 0))
return;
extEntry = AddExtension (COMPOSITE_NAME, 0, 0,
ProcCompositeDispatch, SProcCompositeDispatch,
CompositeResetProc, StandardMinorOpcode);
if (!extEntry)
return;
CompositeReqCode = (CARD8) extEntry->base;
for (s = 0; s < screenInfo.numScreens; s++)
if (!compScreenInit (screenInfo.screens[s]))
return;
miRegisterRedirectBorderClipProc (compSetRedirectBorderClip,
compGetRedirectBorderClip);
/* Initialization succeeded */
noCompositeExtension = FALSE;
}