/* * 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 #endif #include "compint.h" #define SERVER_COMPOSITE_MAJOR 0 #define SERVER_COMPOSITE_MINOR 4 static CARD8 CompositeReqCode; static int CompositeClientPrivateIndex; 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) (pClient)->devPrivates[CompositeClientPrivateIndex].ptr) 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; REQUEST(xCompositeRedirectWindowReq); REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { client->errorValue = stuff->window; return BadWindow; } return compRedirectWindow (client, pWin, stuff->update); } static int ProcCompositeRedirectSubwindows (ClientPtr client) { WindowPtr pWin; REQUEST(xCompositeRedirectSubwindowsReq); REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { client->errorValue = stuff->window; return BadWindow; } 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; REQUEST(xCompositeCreateRegionFromBorderClipReq); REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { client->errorValue = stuff->window; return BadWindow; } 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; REQUEST(xCompositeNameWindowPixmapReq); REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { client->errorValue = stuff->window; return BadWindow; } 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; ++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; REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { client->errorValue = stuff->window; return BadWindow; } pScreen = pWin->drawable.pScreen; cs = GetCompScreen(pScreen); if (cs->pOverlayWin == NULL) { cs->pOverlayWin = createOverlayWindow(pScreen); if (cs->pOverlayWin == NULL) { return BadAlloc; } } 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; CompositeClientPrivateIndex = AllocateClientPrivateIndex (); if (!AllocateClientPrivate (CompositeClientPrivateIndex, 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; }