Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
DISCONTINUED:openSUSE:11.1:Update
xorg-x11-server-dmx
xserver-NOMAD.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xserver-NOMAD.diff of Package xorg-x11-server-dmx
diff --git a/Xext/panoramiX.c b/Xext/panoramiX.c index b690593..b0a16cf 100644 --- a/Xext/panoramiX.c +++ b/Xext/panoramiX.c @@ -53,9 +53,18 @@ Equipment Corporation. #include "globals.h" #include "servermd.h" #include "resource.h" +#ifdef MITSHM +#include "shmint.h" +#endif #ifdef RENDER #include "picturestr.h" #endif +#ifdef XFIXES +#include "xfixesint.h" +#endif +#ifdef COMPOSITE +#include "compint.h" +#endif #include "modinit.h" @@ -577,9 +586,19 @@ void PanoramiXExtensionInit(int argc, char *argv[]) ProcVector[X_StoreColors] = PanoramiXStoreColors; ProcVector[X_StoreNamedColor] = PanoramiXStoreNamedColor; +#ifdef MITSHM + PanoramiXShmInit (); +#endif #ifdef RENDER PanoramiXRenderInit (); #endif +#ifdef XFIXES + PanoramiXFixesInit (); +#endif +#ifdef COMPOSITE + PanoramiXCompositeInit (); +#endif + } extern Bool CreateConnectionBlock(void); @@ -888,6 +907,9 @@ static void PanoramiXResetProc(ExtensionEntry* extEntry) #ifdef RENDER PanoramiXRenderReset (); #endif +#ifdef XFIXES + PanoramiXFixesReset (); +#endif screenInfo.numScreens = PanoramiXNumScreens; for (i = 256; i--; ) ProcVector[i] = SavedProcVector[i]; diff --git a/Xext/panoramiX.h b/Xext/panoramiX.h index 89c7547..c4928b2 100644 --- a/Xext/panoramiX.h +++ b/Xext/panoramiX.h @@ -69,7 +69,8 @@ typedef struct { } pix; #ifdef RENDER struct { - Bool root; + char root; + char sourcePict; } pict; #endif char raw_data[4]; diff --git a/Xext/panoramiXprocs.c b/Xext/panoramiXprocs.c index 38199a5..7518927 100644 --- a/Xext/panoramiXprocs.c +++ b/Xext/panoramiXprocs.c @@ -981,18 +981,20 @@ int PanoramiXCopyArea(ClientPtr client) Bool srcIsRoot = FALSE; Bool dstIsRoot = FALSE; Bool srcShared, dstShared; + Bool getImageData = FALSE; + DrawablePtr srcDrawables[MAXSCREENS]; REQUEST(xCopyAreaReq); REQUEST_SIZE_MATCH(xCopyAreaReq); if(!(src = (PanoramiXRes *)SecurityLookupIDByClass( - client, stuff->srcDrawable, XRC_DRAWABLE, DixReadAccess))) + client, stuff->srcDrawable, XRC_DRAWABLE, DixReadAccess))) return BadDrawable; srcShared = IS_SHARED_PIXMAP(src); if(!(dst = (PanoramiXRes *)SecurityLookupIDByClass( - client, stuff->dstDrawable, XRC_DRAWABLE, DixWriteAccess))) + client, stuff->dstDrawable, XRC_DRAWABLE, DixWriteAccess))) return BadDrawable; dstShared = IS_SHARED_PIXMAP(dst); @@ -1000,6 +1002,17 @@ int PanoramiXCopyArea(ClientPtr client) if(dstShared && srcShared) return (* SavedProcVector[X_CopyArea])(client); + if (stuff->dstDrawable != stuff->srcDrawable) { + int rc; + + FOR_NSCREENS(j) { + rc = dixLookupDrawable(srcDrawables+j, src->info[j].id, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + } + } + if(!(gc = (PanoramiXRes *)SecurityLookupIDByType( client, stuff->gc, XRT_GC, DixReadAccess))) return BadGC; @@ -1011,32 +1024,34 @@ int PanoramiXCopyArea(ClientPtr client) srcx = stuff->srcX; srcy = stuff->srcY; dstx = stuff->dstX; dsty = stuff->dstY; + if((dst->type == XRT_PIXMAP) && (src->type == XRT_WINDOW)) { - DrawablePtr drawables[MAXSCREENS]; + WindowPtr pWin = (WindowPtr) srcDrawables[0]; + + /* no need to use GetImageData if window is redirected */ + for (getImageData = TRUE; pWin && getImageData; pWin = pWin->parent) + if (pWin->redirectDraw != RedirectDrawNone) + getImageData = FALSE; + } + + if(getImageData) { DrawablePtr pDst; GCPtr pGC; char *data; - int pitch, rc; - - FOR_NSCREENS(j) { - rc = dixLookupDrawable(drawables+j, src->info[j].id, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - } + int pitch; - pitch = PixmapBytePad(stuff->width, drawables[0]->depth); + pitch = PixmapBytePad(stuff->width, srcDrawables[0]->depth); if(!(data = xcalloc(1, stuff->height * pitch))) return BadAlloc; - XineramaGetImageData(drawables, srcx, srcy, + XineramaGetImageData(srcDrawables, srcx, srcy, stuff->width, stuff->height, ZPixmap, ~0, data, pitch, srcIsRoot); FOR_NSCREENS_BACKWARD(j) { stuff->gc = gc->info[j].id; VALIDATE_DRAWABLE_AND_GC(dst->info[j].id, pDst, DixWriteAccess); - if(drawables[0]->depth != pDst->depth) { + if(srcDrawables[0]->depth != pDst->depth) { client->errorValue = stuff->dstDrawable; xfree(data); return (BadMatch); @@ -1056,7 +1071,6 @@ int PanoramiXCopyArea(ClientPtr client) DrawablePtr pDst = NULL, pSrc = NULL; GCPtr pGC = NULL; RegionPtr pRgn[MAXSCREENS]; - int rc; FOR_NSCREENS_BACKWARD(j) { stuff->dstDrawable = dst->info[j].id; @@ -1074,11 +1088,7 @@ int PanoramiXCopyArea(ClientPtr client) VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess); if (stuff->dstDrawable != stuff->srcDrawable) { - rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - + pSrc = srcDrawables[j]; if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth)) { client->errorValue = stuff->dstDrawable; @@ -1749,6 +1759,7 @@ int PanoramiXGetImage(ClientPtr client) { DrawablePtr drawables[MAXSCREENS]; DrawablePtr pDraw; + WindowPtr pWin; PanoramiXRes *draw; xGetImageReply xgi; Bool isRoot; @@ -1782,6 +1793,11 @@ int PanoramiXGetImage(ClientPtr client) if(!((WindowPtr)pDraw)->realized) return(BadMatch); + /* bits for redirected windows are available on all screens */ + for (pWin = (WindowPtr) pDraw; pWin; pWin = pWin->parent) + if (pWin->redirectDraw != RedirectDrawNone) + return (*SavedProcVector[X_GetImage])(client); + x = stuff->x; y = stuff->y; w = stuff->width; diff --git a/Xext/shm.c b/Xext/shm.c index 6465edb..f22496c 100644 --- a/Xext/shm.c +++ b/Xext/shm.c @@ -90,16 +90,9 @@ in this Software without prior written authorization from The Open Group. #include "panoramiXsrv.h" #endif -#include "modinit.h" +int (*PanoramiXSaveShmVector[ShmNumberRequests])(ClientPtr); -typedef struct _ShmDesc { - struct _ShmDesc *next; - int shmid; - int refcnt; - char *addr; - Bool writable; - unsigned long size; -} ShmDescRec, *ShmDescPtr; +#include "modinit.h" static void miShmPutImage(XSHM_PUT_IMAGE_ARGS); static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); @@ -132,7 +125,25 @@ static DISPATCH_PROC(SProcShmGetImage); static DISPATCH_PROC(SProcShmPutImage); static DISPATCH_PROC(SProcShmQueryVersion); -static unsigned char ShmReqCode; +int (*ProcShmVector[ShmNumberRequests])(ClientPtr) = { + ProcShmQueryVersion, + ProcShmAttach, + ProcShmDetach, + ProcShmPutImage, + ProcShmGetImage, + ProcShmCreatePixmap +}; + +int (*SProcShmVector[ShmNumberRequests])(ClientPtr) = { + SProcShmQueryVersion, + SProcShmAttach, + SProcShmDetach, + SProcShmPutImage, + SProcShmGetImage, + SProcShmCreatePixmap +}; + +_X_EXPORT unsigned char ShmReqCode; _X_EXPORT int ShmCompletionCode; _X_EXPORT int BadShmSegCode; _X_EXPORT RESTYPE ShmSegType; @@ -146,37 +157,6 @@ static DevPrivateKey shmPixmapPrivate = &shmPixmapPrivate; static ShmFuncs miFuncs = {NULL, miShmPutImage}; static ShmFuncs fbFuncs = {fbShmCreatePixmap, fbShmPutImage}; -#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ -{ \ - shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \ - if (!shmdesc) \ - { \ - client->errorValue = shmseg; \ - return BadShmSegCode; \ - } \ -} - -#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ -{ \ - VERIFY_SHMSEG(shmseg, shmdesc, client); \ - if ((offset & 3) || (offset > shmdesc->size)) \ - { \ - client->errorValue = offset; \ - return BadValue; \ - } \ - if (needwrite && !shmdesc->writable) \ - return BadAccess; \ -} - -#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ -{ \ - if ((offset + len) > shmdesc->size) \ - { \ - return BadAccess; \ - } \ -} - - #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) #include <sys/signal.h> @@ -591,7 +571,7 @@ ProcPanoramiXShmPutImage(ClientPtr client) orig_y = stuff->dstY; sendEvent = stuff->sendEvent; stuff->sendEvent = 0; - FOR_NSCREENS(j) { + FOR_NSCREENS_BACKWARD(j) { if(!j) stuff->sendEvent = sendEvent; stuff->drawable = draw->info[j].id; stuff->gc = gc->info[j].id; @@ -599,7 +579,7 @@ ProcPanoramiXShmPutImage(ClientPtr client) stuff->dstX = orig_x - panoramiXdataPtr[j].x; stuff->dstY = orig_y - panoramiXdataPtr[j].y; } - result = ProcShmPutImage(client); + result = (*PanoramiXSaveShmVector[X_ShmPutImage])(client); if(result != client->noClientException) break; } return(result); @@ -611,6 +591,7 @@ ProcPanoramiXShmGetImage(ClientPtr client) PanoramiXRes *draw; DrawablePtr drawables[MAXSCREENS]; DrawablePtr pDraw; + WindowPtr pWin; xShmGetImageReply xgi; ShmDescPtr shmdesc; int i, x, y, w, h, format, rc; @@ -632,13 +613,18 @@ ProcPanoramiXShmGetImage(ClientPtr client) return BadDrawable; if (draw->type == XRT_PIXMAP) - return ProcShmGetImage(client); + return (*PanoramiXSaveShmVector[X_ShmGetImage])(client); rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; + /* bits for redirected windows are available on all screens */ + for (pWin = (WindowPtr) pDraw; pWin; pWin = pWin->parent) + if (pWin->redirectDraw != RedirectDrawNone) + return (*PanoramiXSaveShmVector[X_ShmGetImage])(client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); x = stuff->x; @@ -1160,35 +1146,11 @@ static int ProcShmDispatch (ClientPtr client) { REQUEST(xReq); - switch (stuff->data) - { - case X_ShmQueryVersion: - return ProcShmQueryVersion(client); - case X_ShmAttach: - return ProcShmAttach(client); - case X_ShmDetach: - return ProcShmDetach(client); - case X_ShmPutImage: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmPutImage(client); -#endif - return ProcShmPutImage(client); - case X_ShmGetImage: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmGetImage(client); -#endif - return ProcShmGetImage(client); - case X_ShmCreatePixmap: -#ifdef PANORAMIX - if ( !noPanoramiXExtension ) - return ProcPanoramiXShmCreatePixmap(client); -#endif - return ProcShmCreatePixmap(client); - default: + + if (stuff->data < ShmNumberRequests) + return (*ProcShmVector[stuff->data]) (client); + else return BadRequest; - } } static void @@ -1210,7 +1172,7 @@ SProcShmQueryVersion(ClientPtr client) REQUEST(xShmQueryVersionReq); swaps(&stuff->length, n); - return ProcShmQueryVersion(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int @@ -1222,7 +1184,7 @@ SProcShmAttach(ClientPtr client) REQUEST_SIZE_MATCH(xShmAttachReq); swapl(&stuff->shmseg, n); swapl(&stuff->shmid, n); - return ProcShmAttach(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int @@ -1233,7 +1195,7 @@ SProcShmDetach(ClientPtr client) swaps(&stuff->length, n); REQUEST_SIZE_MATCH(xShmDetachReq); swapl(&stuff->shmseg, n); - return ProcShmDetach(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int @@ -1255,7 +1217,7 @@ SProcShmPutImage(ClientPtr client) swaps(&stuff->dstY, n); swapl(&stuff->shmseg, n); swapl(&stuff->offset, n); - return ProcShmPutImage(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int @@ -1273,7 +1235,7 @@ SProcShmGetImage(ClientPtr client) swapl(&stuff->planeMask, n); swapl(&stuff->shmseg, n); swapl(&stuff->offset, n); - return ProcShmGetImage(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int @@ -1289,28 +1251,45 @@ SProcShmCreatePixmap(ClientPtr client) swaps(&stuff->height, n); swapl(&stuff->shmseg, n); swapl(&stuff->offset, n); - return ProcShmCreatePixmap(client); + return (*ProcShmVector[stuff->shmReqType])(client); } static int SProcShmDispatch (ClientPtr client) { REQUEST(xReq); - switch (stuff->data) - { - case X_ShmQueryVersion: - return SProcShmQueryVersion(client); - case X_ShmAttach: - return SProcShmAttach(client); - case X_ShmDetach: - return SProcShmDetach(client); - case X_ShmPutImage: - return SProcShmPutImage(client); - case X_ShmGetImage: - return SProcShmGetImage(client); - case X_ShmCreatePixmap: - return SProcShmCreatePixmap(client); - default: + + if (stuff->data < ShmNumberRequests) + return (*SProcShmVector[stuff->data]) (client); + else return BadRequest; - } } + +#ifdef PANORAMIX + +void +PanoramiXShmInit (void) +{ + int i; + + for (i = 0; i < ShmNumberRequests; i++) + PanoramiXSaveShmVector[i] = ProcShmVector[i]; + + /* + * Stuff in Xinerama aware request processing hooks + */ + ProcShmVector[X_ShmPutImage] = ProcPanoramiXShmPutImage; + ProcShmVector[X_ShmGetImage] = ProcPanoramiXShmGetImage; + ProcShmVector[X_ShmCreatePixmap] = ProcPanoramiXShmCreatePixmap; +} + +void +PanoramiXShmReset (void) +{ + int i; + + for (i = 0; i < ShmNumberRequests; i++) + ProcShmVector[i] = PanoramiXSaveShmVector[i]; +} + +#endif /* PANORAMIX */ diff --git a/Xext/shmint.h b/Xext/shmint.h index 33ab6a4..eb7c0f5 100644 --- a/Xext/shmint.h +++ b/Xext/shmint.h @@ -30,6 +30,54 @@ #include "pixmap.h" #include "gc.h" +#ifndef ShmNumberRequests +#define ShmNumberRequests (X_ShmCreatePixmap + 1) +#endif + +typedef struct _ShmDesc { + struct _ShmDesc *next; + int shmid; + int refcnt; + char *addr; + Bool writable; + unsigned long size; +} ShmDescRec, *ShmDescPtr; + +extern unsigned char ShmReqCode; +extern int ShmCompletionCode; +extern int BadShmSegCode; +extern RESTYPE ShmSegType; + +#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ +{ \ + shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \ + if (!shmdesc) \ + { \ + client->errorValue = shmseg; \ + return BadShmSegCode; \ + } \ +} + +#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ +{ \ + VERIFY_SHMSEG(shmseg, shmdesc, client); \ + if ((offset & 3) || (offset > shmdesc->size)) \ + { \ + client->errorValue = offset; \ + return BadValue; \ + } \ + if (needwrite && !shmdesc->writable) \ + return BadAccess; \ +} + +#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ +{ \ + if ((offset + len) > shmdesc->size) \ + { \ + return BadAccess; \ + } \ +} + void ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs); @@ -42,4 +90,9 @@ fbShmPutImage(XSHM_PUT_IMAGE_ARGS); void ShmRegisterFbFuncs(ScreenPtr pScreen); +#ifdef PANORAMIX +void PanoramiXShmInit (void); +void PanoramiXShmReset (void); +#endif + #endif /* _SHMINT_H_ */ diff --git a/composite/compext.c b/composite/compext.c index 154f719..341e002 100644 --- a/composite/compext.c +++ b/composite/compext.c @@ -143,6 +143,7 @@ ProcCompositeRedirectWindow (ClientPtr client) REQUEST(xCompositeRedirectWindowReq); REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client, DixSetAttrAccess|DixManageAccess|DixBlendAccess); if (rc != Success) @@ -161,6 +162,7 @@ ProcCompositeRedirectSubwindows (ClientPtr client) REQUEST(xCompositeRedirectSubwindowsReq); REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client, DixSetAttrAccess|DixManageAccess|DixBlendAccess); if (rc != Success) @@ -178,6 +180,7 @@ ProcCompositeUnredirectWindow (ClientPtr client) REQUEST(xCompositeUnredirectWindowReq); REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { @@ -194,6 +197,7 @@ ProcCompositeUnredirectSubwindows (ClientPtr client) REQUEST(xCompositeUnredirectSubwindowsReq); REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { @@ -249,6 +253,7 @@ ProcCompositeNameWindowPixmap (ClientPtr client) REQUEST(xCompositeNameWindowPixmapReq); REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client, DixGetAttrAccess); if (rc != Success) @@ -297,6 +302,7 @@ ProcCompositeGetOverlayWindow (ClientPtr client) int rc; REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); + rc = dixLookupResource((pointer *)&pWin, stuff->window, RT_WINDOW, client, DixGetAttrAccess); if (rc != Success) @@ -359,6 +365,7 @@ ProcCompositeReleaseOverlayWindow (ClientPtr client) CompOverlayClientPtr pOc; REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); if (!pWin) { @@ -381,7 +388,7 @@ ProcCompositeReleaseOverlayWindow (ClientPtr client) return client->noClientException; } -static int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { +int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { ProcCompositeQueryVersion, ProcCompositeRedirectWindow, ProcCompositeRedirectSubwindows, @@ -565,13 +572,6 @@ CompositeExtensionInit (void) 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) @@ -607,3 +607,357 @@ CompositeExtensionInit (void) /* Initialization succeeded */ noCompositeExtension = FALSE; } + +#ifdef PANORAMIX +#include "panoramiX.h" +extern unsigned long XRT_PIXMAP; +extern unsigned long XRT_WINDOW; +extern int PanoramiXNumScreens; + +int (*PanoramiXSaveCompositeVector[CompositeNumberRequests]) (ClientPtr); + +static int +PanoramiXCompositeRedirectWindow (ClientPtr client) +{ + PanoramiXRes *win; + int rc = 0, j; + REQUEST(xCompositeRedirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + return BadWindow; + + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + if (rc != Success) break; + } + + return (rc); +} + +static int +PanoramiXCompositeRedirectSubwindows (ClientPtr client) +{ + PanoramiXRes *win; + int rc = 0, j; + REQUEST(xCompositeRedirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + return BadWindow; + + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + if (rc != Success) break; + } + + return (rc); +} + +static int +PanoramiXCompositeUnredirectWindow (ClientPtr client) +{ + PanoramiXRes *win; + int rc = 0, j; + REQUEST(xCompositeUnredirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + return BadWindow; + + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + if (rc != Success) break; + } + + return (rc); +} + +static int +PanoramiXCompositeUnredirectSubwindows (ClientPtr client) +{ + PanoramiXRes *win; + int rc = 0, j; + REQUEST(xCompositeUnredirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + return BadWindow; + + FOR_NSCREENS_FORWARD(j) { + rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + if (rc != Success) break; + } + + return (rc); +} + +static int +PanoramiXCompositeNameWindowPixmap (ClientPtr client) +{ + WindowPtr pWin; + CompWindowPtr cw; + PixmapPtr pPixmap; + int rc; + PanoramiXRes *win, *newPix; + int i; + REQUEST(xCompositeNameWindowPixmapReq); + + REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + { + client->errorValue = stuff->window; + return BadWindow; + } + + if(!(newPix = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + LEGAL_NEW_RESOURCE (stuff->pixmap, client); + + newPix->type = XRT_PIXMAP; + newPix->u.pix.shared = FALSE; + newPix->info[0].id = stuff->pixmap; + + for (i = 1; i < PanoramiXNumScreens; i++) + newPix->info[i].id = FakeClientID (client->index); + + FOR_NSCREENS(i) { + rc = dixLookupResource ((pointer *) &pWin, + win->info[i].id, RT_WINDOW, client, + DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = stuff->window; + xfree (newPix); + return (rc == BadValue) ? BadWindow : rc; + } + + if (!pWin->viewable) + { + xfree (newPix); + return BadMatch; + } + + cw = GetCompWindow (pWin); + if (!cw) + { + xfree (newPix); + return BadMatch; + } + + pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + if (!pPixmap) + { + xfree (newPix); + return BadMatch; + } + + if (!AddResource (newPix->info[i].id, RT_PIXMAP, + (pointer) pPixmap)) + return BadAlloc; + + ++pPixmap->refcnt; + } + + if (!AddResource (stuff->pixmap, XRT_PIXMAP, (pointer) newPix)) + return BadAlloc; + + return (client->noClientException); +} + + +static int +PanoramiXCompositeGetOverlayWindow (ClientPtr client) +{ + REQUEST(xCompositeGetOverlayWindowReq); + xCompositeGetOverlayWindowReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + CompScreenPtr cs; + CompOverlayClientPtr pOc; + int rc; + PanoramiXRes *win, *overlayWin = NULL; + int i; + + REQUEST_SIZE_MATCH(xCompositeGetOverlayWindowReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + { + client->errorValue = stuff->window; + return BadWindow; + } + + cs = GetCompScreen(screenInfo.screens[0]); + if (!cs->pOverlayWin) + { + if(!(overlayWin = (PanoramiXRes *) xalloc(sizeof(PanoramiXRes)))) + return BadAlloc; + + overlayWin->type = XRT_WINDOW; + overlayWin->u.win.root = FALSE; + } + + FOR_NSCREENS_BACKWARD(i) { + rc = dixLookupResource((pointer *)&pWin, win->info[i].id, + RT_WINDOW, client, + DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = stuff->window; + return (rc == BadValue) ? BadWindow : rc; + } + pScreen = pWin->drawable.pScreen; + + /* + * Create an OverlayClient structure to mark this client's + * interest in the overlay window + */ + pOc = compCreateOverlayClient(pScreen, client); + if (pOc == NULL) + return BadAlloc; + + /* + * Make sure the overlay window exists + */ + cs = GetCompScreen(pScreen); + if (cs->pOverlayWin == NULL) + if (!compCreateOverlayWindow(pScreen)) + { + FreeResource (pOc->resource, RT_NONE); + return BadAlloc; + } + + rc = XaceHook(XACE_RESOURCE_ACCESS, client, + cs->pOverlayWin->drawable.id, + RT_WINDOW, cs->pOverlayWin, RT_NONE, NULL, + DixGetAttrAccess); + if (rc != Success) + { + FreeResource (pOc->resource, RT_NONE); + return rc; + } + } + + if (overlayWin) + { + FOR_NSCREENS(i) { + cs = GetCompScreen(screenInfo.screens[i]); + overlayWin->info[i].id = cs->pOverlayWin->drawable.id; + } + + AddResource(overlayWin->info[0].id, XRT_WINDOW, overlayWin); + } + + cs = GetCompScreen(screenInfo.screens[0]); + + 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 +PanoramiXCompositeReleaseOverlayWindow (ClientPtr client) +{ + REQUEST(xCompositeReleaseOverlayWindowReq); + WindowPtr pWin; + ScreenPtr pScreen; + CompOverlayClientPtr pOc; + PanoramiXRes *win; + int i; + + REQUEST_SIZE_MATCH(xCompositeReleaseOverlayWindowReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->window, XRT_WINDOW, DixUnknownAccess))) + { + client->errorValue = stuff->window; + return BadWindow; + } + + FOR_NSCREENS_BACKWARD(i) { + pWin = (WindowPtr) LookupIDByType (win->info[i].id, 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 = compFindOverlayClient (pWin->drawable.pScreen, client); + if (pOc == NULL) + return BadMatch; + + /* The delete function will free the client structure */ + FreeResource (pOc->resource, RT_NONE); + } + + return client->noClientException; +} + +void +PanoramiXCompositeInit (void) +{ + int i; + + for (i = 0; i < CompositeNumberRequests; i++) + PanoramiXSaveCompositeVector[i] = ProcCompositeVector[i]; + /* + * Stuff in Xinerama aware request processing hooks + */ + ProcCompositeVector[X_CompositeRedirectWindow] = + PanoramiXCompositeRedirectWindow; + ProcCompositeVector[X_CompositeRedirectSubwindows] = + PanoramiXCompositeRedirectSubwindows; + ProcCompositeVector[X_CompositeUnredirectWindow] = + PanoramiXCompositeUnredirectWindow; + ProcCompositeVector[X_CompositeUnredirectSubwindows] = + PanoramiXCompositeUnredirectSubwindows; + ProcCompositeVector[X_CompositeNameWindowPixmap] = + PanoramiXCompositeNameWindowPixmap; + ProcCompositeVector[X_CompositeGetOverlayWindow] = + PanoramiXCompositeGetOverlayWindow; + ProcCompositeVector[X_CompositeReleaseOverlayWindow] = + PanoramiXCompositeReleaseOverlayWindow; +} + +void +PanoramiXCompositeReset (void) +{ + int i; + + for (i = 0; i < CompositeNumberRequests; i++) + ProcCompositeVector[i] = PanoramiXSaveCompositeVector[i]; +} + +#endif diff --git a/composite/compint.h b/composite/compint.h index 1c19ccd..ee6727a 100644 --- a/composite/compint.h +++ b/composite/compint.h @@ -319,4 +319,9 @@ CompositeRealChildHead (WindowPtr pWin); int DeleteWindowNoInputDevices(pointer value, XID wid); +#ifdef PANORAMIX +void PanoramiXCompositeInit (void); +void PanoramiXCompositeReset (void); +#endif + #endif /* _COMPINT_H_ */ diff --git a/composite/compoverlay.c b/composite/compoverlay.c index 94e5b03..ed5fe38 100644 --- a/composite/compoverlay.c +++ b/composite/compoverlay.c @@ -47,6 +47,10 @@ #include "compint.h" #include "xace.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + /* * Delete the given overlay client list element from its screen list. */ @@ -127,10 +131,20 @@ compCreateOverlayWindow (ScreenPtr pScreen) WindowPtr pWin; XID overrideRedirect = TRUE; int result; + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif pWin = cs->pOverlayWin = CreateWindow (cs->overlayWid, pRoot, - 0, 0, pScreen->width, pScreen->height, 0, + 0, 0, w, h, 0, InputOutput, CWOverrideRedirect, &overrideRedirect, pRoot->drawable.depth, serverClient, pScreen->rootVisual, &result); diff --git a/composite/compwindow.c b/composite/compwindow.c index c1657bd..072f99e 100644 --- a/composite/compwindow.c +++ b/composite/compwindow.c @@ -46,6 +46,10 @@ #include "compint.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + #ifdef COMPOSITE_DEBUG static int compCheckWindow (WindowPtr pWin, pointer data) @@ -171,16 +175,26 @@ updateOverlayWindow(ScreenPtr pScreen) CompScreenPtr cs; WindowPtr pWin; /* overlay window */ XID vlist[2]; + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif cs = GetCompScreen(pScreen); if ((pWin = cs->pOverlayWin) != NULL) { - if ((pWin->drawable.width == pScreen->width) && - (pWin->drawable.height == pScreen->height)) + if ((pWin->drawable.width == w) && + (pWin->drawable.height == h)) return Success; /* Let's resize the overlay window. */ - vlist[0] = pScreen->width; - vlist[1] = pScreen->height; + vlist[0] = w; + vlist[1] = h; return ConfigureWindow(pWin, CWWidth | CWHeight, vlist, wClient(pWin)); } diff --git a/config/dbus-core.c b/config/dbus-core.c index b349c6e..8b97e24 100644 --- a/config/dbus-core.c +++ b/config/dbus-core.c @@ -85,7 +85,7 @@ teardown(void) * completeness. But then it gets awkward, given that you can't * guarantee that they'll be called ... */ if (bus_info.connection) - dbus_connection_unref(bus_info.connection); + dbus_connection_close(bus_info.connection); RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, &bus_info); if (bus_info.fd != -1) @@ -140,7 +140,7 @@ connect_to_bus(void) struct config_dbus_core_hook *hook; dbus_error_init(&error); - bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + bus_info.connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); if (!bus_info.connection || dbus_error_is_set(&error)) { DebugF("[config/dbus-core] error connecting to system bus: %s (%s)\n", error.name, error.message); diff --git a/configure.ac b/configure.ac index 570a688..d816561 100644 --- a/configure.ac +++ b/configure.ac @@ -544,6 +544,7 @@ AC_ARG_ENABLE(dpms, AS_HELP_STRING([--disable-dpms], [Build DPMS exten AC_ARG_ENABLE(config-dbus, AS_HELP_STRING([--enable-config-dbus], [Build D-BUS API support (default: no)]), [CONFIG_DBUS_API=$enableval], [CONFIG_DBUS_API=no]) AC_ARG_ENABLE(config-hal, AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto]) AC_ARG_ENABLE(xfree86-utils, AS_HELP_STRING([--enable-xfree86-utils], [Build xfree86 DDX utilities (default: enabled)]), [XF86UTILS=$enableval], [XF86UTILS=yes]) +AC_ARG_ENABLE(avahi, AS_HELP_STRING([--disable-avahi], [Build Avahi support (default: auto)]), [AVAHI=$enableval], [AVAHI=no]) dnl DDXes. AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto]) @@ -707,6 +708,12 @@ fi AM_CONDITIONAL(CONFIG_NEED_DBUS, [test "x$CONFIG_NEED_DBUS" = xyes]) CONFIG_LIB='$(top_builddir)/config/libconfig.a' +PKG_CHECK_MODULES(AVAHI, avahi-client, [HAVE_AVAHI=yes], [HAVE_AVAHI=no]) +if test "x$HAVE_AVAHI" = xyes; then + AC_DEFINE(HAVE_AVAHI, 1, [Have Avahi suppport]) +fi +AM_CONDITIONAL(HAVE_AVAHI, [test "x$HAVE_AVAHI" = xyes]) + AC_MSG_CHECKING([for glibc...]) AC_PREPROC_IFELSE([ #include <features.h> @@ -1565,8 +1572,7 @@ AM_CONDITIONAL(XQUARTZ, [test "x$XQUARTZ" = xyes]) dnl DMX DDX -PKG_CHECK_MODULES([DMXMODULES], [xmuu xext x11 xrender xfixes xfont xi dmxproto xau $XDMCP_MODULES], [have_dmx=yes], [have_dmx=no]) -AC_MSG_CHECKING([whether to build Xdmx DDX]) +PKG_CHECK_MODULES([DMXMODULES], [xmuu xext x11 xrender xfixes xfont xi >= 1.1.99.1 dmxproto xau xcomposite xrandr xv x11-xcb xcb-randr xcb-xinput xcb-aux >= 0.2.1 xcb-image xcb-shape $XDMCP_MODULES], [have_dmx=yes], [have_dmx=no]) if test "x$DMX" = xauto; then DMX="$have_dmx" case $host_os in @@ -1584,24 +1590,14 @@ if test "x$DMX" = xyes; then fi DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC" XDMX_CFLAGS="$DMXMODULES_CFLAGS" - XDMX_LIBS="$XEXT_LIB $FB_LIB $CONFIG_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB" + XDMX_LIBS="$DIX_LIB $CONFIG_LIB $COMPOSITE_LIB $FIXES_LIB $XEXT_LIB $FB_LIB $RENDER_LIB $RANDR_LIB $RECORD_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $OS_LIB $MI_LIB" XDMX_SYS_LIBS="$DMXMODULES_LIBS" AC_SUBST([XDMX_CFLAGS]) AC_SUBST([XDMX_LIBS]) AC_SUBST([XDMX_SYS_LIBS]) - -dnl USB sources in DMX require <linux/input.h> - AC_CHECK_HEADER([linux/input.h], DMX_BUILD_USB="yes", - DMX_BUILD_USB="no") -dnl Linux sources in DMX require <linux/keyboard.h> - AC_CHECK_HEADER([linux/keyboard.h], DMX_BUILD_LNX="yes", - DMX_BUILD_LNX="no") if test "x$GLX" = xyes; then PKG_CHECK_MODULES([GL], [glproto]) fi - PKG_CHECK_MODULES([XDMXCONFIG_DEP], [xaw7 xmu xt xpm x11]) - AC_SUBST(XDMXCONFIG_DEP_CFLAGS) - AC_SUBST(XDMXCONFIG_DEP_LIBS) PKG_CHECK_MODULES([DMXEXAMPLES_DEP], [dmx xext x11]) AC_SUBST(DMXEXAMPLES_DEP_LIBS) PKG_CHECK_MODULES([DMXXMUEXAMPLES_DEP], [dmx xmu xext x11]) @@ -1614,9 +1610,10 @@ dnl Linux sources in DMX require <linux/keyboard.h> AC_SUBST(XRESEXAMPLES_DEP_LIBS) PKG_CHECK_MODULES([X11EXAMPLES_DEP], [xext x11]) AC_SUBST(X11EXAMPLES_DEP_LIBS) + PKG_CHECK_MODULES([DBUSEXAMPLES_DEP], [dbus-1 xcb]) + AC_SUBST(DBUSEXAMPLES_DEP_CFLAGS) + AC_SUBST(DBUSEXAMPLES_DEP_LIBS) fi -AM_CONDITIONAL([DMX_BUILD_LNX], [test "x$DMX_BUILD_LNX" = xyes]) -AM_CONDITIONAL([DMX_BUILD_USB], [test "x$DMX_BUILD_USB" = xyes]) dnl kdrive DDX @@ -1864,10 +1861,8 @@ hw/xfree86/xf8_16bpp/Makefile hw/xfree86/utils/Makefile hw/xfree86/utils/cvt/Makefile hw/xfree86/utils/gtf/Makefile -hw/dmx/config/Makefile hw/dmx/doc/Makefile hw/dmx/examples/Makefile -hw/dmx/input/Makefile hw/dmx/glxProxy/Makefile hw/dmx/Makefile hw/vfb/Makefile diff --git a/dix/events.c b/dix/events.c index d6b3ecb..d4e5a35 100644 --- a/dix/events.c +++ b/dix/events.c @@ -647,6 +647,7 @@ XineramaCheckVirtualMotion( static Bool XineramaCheckMotion(xEvent *xE, DeviceIntPtr pDev) { + INT16 *rootX, *rootY; WindowPtr prevSpriteWin; SpritePtr pSprite = pDev->spriteInfo->sprite; @@ -654,15 +655,38 @@ XineramaCheckMotion(xEvent *xE, DeviceIntPtr pDev) if (xE && !syncEvents.playingEvents) { + /* GetPointerEvents() guarantees that pointer events have the correct + rootX/Y set already. */ + switch(xE->u.u.type) + { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + rootX = &XE_KBPTR.rootX; + rootY = &XE_KBPTR.rootY; + break; + default: + if (xE->u.u.type == DeviceButtonPress || + xE->u.u.type == DeviceButtonRelease || + xE->u.u.type == DeviceMotionNotify) + { + rootX = &((deviceKeyButtonPointer*)xE)->root_x; + rootY = &((deviceKeyButtonPointer*)xE)->root_y; + break; + } + /* all other events return FALSE */ + return FALSE; + } + /* Motion events entering DIX get translated to Screen 0 coordinates. Replayed events have already been translated since they've entered DIX before */ - XE_KBPTR.rootX += panoramiXdataPtr[pSprite->screen->myNum].x - - panoramiXdataPtr[0].x; - XE_KBPTR.rootY += panoramiXdataPtr[pSprite->screen->myNum].y - - panoramiXdataPtr[0].y; - pSprite->hot.x = XE_KBPTR.rootX; - pSprite->hot.y = XE_KBPTR.rootY; + *rootX += panoramiXdataPtr[pSprite->screen->myNum].x - + panoramiXdataPtr[0].x; + *rootY += panoramiXdataPtr[pSprite->screen->myNum].y - + panoramiXdataPtr[0].y; + pSprite->hot.x = *rootX; + pSprite->hot.y = *rootY; if (pSprite->hot.x < pSprite->physLimits.x1) pSprite->hot.x = pSprite->physLimits.x1; else if (pSprite->hot.x >= pSprite->physLimits.x2) @@ -676,14 +700,14 @@ XineramaCheckMotion(xEvent *xE, DeviceIntPtr pDev) ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); pSprite->hotPhys = pSprite->hot; - if ((pSprite->hotPhys.x != XE_KBPTR.rootX) || - (pSprite->hotPhys.y != XE_KBPTR.rootY)) + if ((pSprite->hotPhys.x != *rootX) || + (pSprite->hotPhys.y != *rootY)) { XineramaSetCursorPosition( pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); } - XE_KBPTR.rootX = pSprite->hot.x; - XE_KBPTR.rootY = pSprite->hot.y; + *rootX = pSprite->hot.x; + *rootY = pSprite->hot.y; } #ifdef XEVIE diff --git a/dix/window.c b/dix/window.c index 14fccab..2487e27 100644 --- a/dix/window.c +++ b/dix/window.c @@ -2719,7 +2719,7 @@ EnableMapUnmapEvents(WindowPtr pWin) windowDisableMapUnmapEvents = NULL; } -static Bool +Bool MapUnmapEventsEnabled(WindowPtr pWin) { return pWin != windowDisableMapUnmapEvents; diff --git a/hw/dmx/Makefile.am b/hw/dmx/Makefile.am index 8457aea..53c1027 100644 --- a/hw/dmx/Makefile.am +++ b/hw/dmx/Makefile.am @@ -1,6 +1,6 @@ -DIST_SUBDIRS = input config glxProxy examples doc +DIST_SUBDIRS = glxProxy examples doc -SUBDIRS = input config examples +SUBDIRS = examples bin_PROGRAMS = Xdmx if XINERAMA @@ -20,11 +20,25 @@ if BUILDDOCS SUBDIRS += doc endif +if CONFIG_DBUS_API +DBUS_SRCS = dmxdbus.c dmxdbus.h +DBUS_INCS = -I$(top_srcdir)/config +DBUS_DEFS = @DBUS_CFLAGS@ +endif + +if HAVE_AVAHI +AVAHI_SRCS = dmxavahi.c dmxavahi.h +AVAHI_DEFS = @AVAHI_CFLAGS@ +endif + AM_CFLAGS = \ -DHAVE_DMX_CONFIG_H \ $(DIX_CFLAGS) \ $(GLX_INCS) \ $(GLX_DEFS) \ + $(DBUS_INCS) \ + $(DBUS_DEFS) \ + $(AVAHI_DEFS) \ $(DMX_CFLAGS) \ @DMXMODULES_CFLAGS@ @@ -62,8 +76,6 @@ Xdmx_SOURCES = dmx.c \ dmxprop.h \ dmxscrinit.c \ dmxscrinit.h \ - dmxshadow.c \ - dmxshadow.h \ dmxstat.c \ dmxstat.h \ dmxsync.c \ @@ -72,9 +84,29 @@ Xdmx_SOURCES = dmx.c \ dmxvisual.h \ dmxwindow.c \ dmxwindow.h \ + dmxatom.c \ + dmxatom.h \ + dmxlaunch.c \ + dmxlaunch.h \ + dmxshm.c \ + dmxshm.h \ + dmxcomp.c \ + dmxcomp.h \ + dmxrandr.c \ + dmxrandr.h \ + dmxxv.c \ + dmxxv.h \ + dmxgrab.c \ + dmxgrab.h \ + dmxselection.c \ + dmxselection.h \ + dmxdnd.c \ + dmxdnd.h \ $(top_srcdir)/mi/miinitext.c \ $(top_srcdir)/fb/fbcmap_mi.c \ - $(GLX_SRCS) + $(GLX_SRCS) \ + $(DBUS_SRCS) \ + $(AVAHI_SRCS) #if COMPOSITE @@ -84,9 +116,7 @@ Xdmx_SOURCES = dmx.c \ XDMX_LIBS = \ @XDMX_LIBS@ \ $(GLX_LIBS) \ - input/libdmxinput.a \ - config/libdmxconfig.a \ - $(XSERVER_LIBS) + $(AVAHI_LIBS) Xdmx_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) Xdmx_DEPENDENCIES= $(XDMX_LIBS) diff --git a/hw/dmx/dmx-config.h b/hw/dmx/dmx-config.h index 5b7b605..2cfcd6f 100644 --- a/hw/dmx/dmx-config.h +++ b/hw/dmx/dmx-config.h @@ -74,15 +74,10 @@ /* Disable the extensions that are not currently supported */ #undef MULTIBUFFER -#undef XV #undef DBE #undef XF86VIDMODE #undef XFreeXDGA #undef XF86DRI #undef SCREENSAVER -#undef RANDR -#undef XFIXES -#undef DAMAGE -#undef COMPOSITE #endif /* DMX_CONFIG_H */ diff --git a/hw/dmx/dmx.c b/hw/dmx/dmx.c index 10d9e22..ae4be98 100644 --- a/hw/dmx/dmx.c +++ b/hw/dmx/dmx.c @@ -63,10 +63,21 @@ #ifdef PANORAMIX #include "panoramiX.h" +extern unsigned long XRC_DRAWABLE; extern unsigned long XRT_WINDOW; extern int PanoramiXNumScreens; #endif +#ifdef RANDR +#include "randrstr.h" +#endif + +#include "dmxdbus.h" + +#ifdef HAVE_AVAHI +#include "dmxavahi.h" +#endif + extern void DMXExtensionInit(void); static unsigned char DMXCode; @@ -113,19 +124,41 @@ static int _DMXXineramaActive(void) return 0; } +static void DMXResetProc(ExtensionEntry *extEntry) +{ + +#ifdef HAVE_AVAHI + dmx_avahi_fini (); +#endif + +#ifdef CONFIG_DBUS_API + dmx_dbus_fini (); +#endif + +} + /** Initialize the extension. */ void DMXExtensionInit(void) { ExtensionEntry *extEntry; - + if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0, ProcDMXDispatch, SProcDMXDispatch, - NULL, StandardMinorOpcode))) + DMXResetProc, StandardMinorOpcode))) DMXCode = extEntry->base; + +#ifdef CONFIG_DBUS_API + dmx_dbus_init (); +#endif + +#ifdef HAVE_AVAHI + dmx_avahi_init (); +#endif + } static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, - CARD32 value) + CARD32 value) { switch (1 << bit) { case DMXScreenWindowWidth: attr->screenWindowWidth = value; break; @@ -142,25 +175,25 @@ static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, } static int dmxFetchScreenAttributes(unsigned int mask, - DMXScreenAttributesPtr attr, - CARD32 *value_list) + DMXScreenAttributesPtr attr, + CARD32 *value_list) { int i; CARD32 *value = value_list; int count = 0; - + for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetScreenAttribute(i, attr, *value); - ++value; - ++count; - } + if (mask & (1 << i)) { + dmxSetScreenAttribute(i, attr, *value); + ++value; + ++count; + } } return count; } static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, - CARD32 value) + CARD32 value) { switch (1 << bit) { case DMXDesktopWidth: attr->width = value; break; @@ -171,25 +204,25 @@ static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, } static int dmxFetchDesktopAttributes(unsigned int mask, - DMXDesktopAttributesPtr attr, - CARD32 *value_list) + DMXDesktopAttributesPtr attr, + CARD32 *value_list) { int i; CARD32 *value = value_list; int count = 0; - + for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetDesktopAttribute(i, attr, *value); + if (mask & (1 << i)) { + dmxSetDesktopAttribute(i, attr, *value); ++value; - ++count; - } + ++count; + } } return count; } static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, - CARD32 value) + CARD32 value) { switch (1 << bit) { case DMXInputType: attr->inputType = value; break; @@ -199,19 +232,19 @@ static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, } static int dmxFetchInputAttributes(unsigned int mask, - DMXInputAttributesPtr attr, - CARD32 *value_list) + DMXInputAttributesPtr attr, + CARD32 *value_list) { int i; CARD32 *value = value_list; int count = 0; for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetInputAttribute(i, attr, *value); - ++value; - ++count; - } + if (mask & (1 << i)) { + dmxSetInputAttribute(i, attr, *value); + ++value; + ++count; + } } return count; } @@ -231,7 +264,7 @@ static int ProcDMXQueryVersion(ClientPtr client) rep.patchVersion = DMX_EXTENSION_PATCH; if (client->swapped) { swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); + swapl(&rep.length, n); swapl(&rep.majorVersion, n); swapl(&rep.minorVersion, n); swapl(&rep.patchVersion, n); @@ -254,9 +287,9 @@ static int ProcDMXSync(ClientPtr client) rep.length = 0; rep.status = 0; if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); } WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep); return client->noClientException; @@ -273,27 +306,27 @@ static int ProcDMXForceWindowCreation(ClientPtr client) #ifdef PANORAMIX if (!noPanoramiXExtension) { - PanoramiXRes *win; - int i; + PanoramiXRes *win; + int i; - if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ + if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, + DixReadAccess))) + return -1; /* BadWindow */ - FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, + FOR_NSCREENS(i) { + if (Success != dixLookupWindow(&pWin, win->info[i].id, client, DixReadAccess)) - return -1; /* BadWindow */ + return -1; /* BadWindow */ - dmxForceWindowCreation(pWin); - } - goto doreply; + dmxForceWindowCreation(pWin); + } + goto doreply; } #endif if (Success != dixLookupWindow(&pWin, stuff->window, client, DixReadAccess)) - return -1; /* BadWindow */ + return -1; /* BadWindow */ dmxForceWindowCreation(pWin); doreply: @@ -303,9 +336,9 @@ static int ProcDMXForceWindowCreation(ClientPtr client) rep.length = 0; rep.status = 0; if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); } WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep); return Success; @@ -324,8 +357,8 @@ static int ProcDMXGetScreenCount(ClientPtr client) rep.screenCount = dmxGetNumScreens(); if (client->swapped) { swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.screenCount, n); + swapl(&rep.length, n); + swapl(&rep.screenCount, n); } WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep); return client->noClientException; @@ -343,10 +376,10 @@ static int ProcDMXGetScreenAttributes(ClientPtr client) REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); if (stuff->physicalScreen < 0 - || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; + || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr)) - return BadValue; + return BadValue; rep.logicalScreen = attr.logicalScreen; rep.screenWindowWidth = attr.screenWindowWidth; @@ -359,7 +392,7 @@ static int ProcDMXGetScreenAttributes(ClientPtr client) rep.rootWindowYoffset = attr.rootWindowYoffset; rep.rootWindowXorigin = attr.rootWindowXorigin; rep.rootWindowYorigin = attr.rootWindowYorigin; - + length = attr.displayName ? strlen(attr.displayName) : 0; paddedLength = (length + 3) & ~3; rep.type = X_Reply; @@ -369,19 +402,19 @@ static int ProcDMXGetScreenAttributes(ClientPtr client) if (client->swapped) { swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.displayNameLength, n); - swapl(&rep.logicalScreen, n); - swaps(&rep.screenWindowWidth, n); - swaps(&rep.screenWindowHeight, n); - swaps(&rep.screenWindowXoffset, n); - swaps(&rep.screenWindowYoffset, n); - swaps(&rep.rootWindowWidth, n); - swaps(&rep.rootWindowHeight, n); - swaps(&rep.rootWindowXoffset, n); - swaps(&rep.rootWindowYoffset, n); - swaps(&rep.rootWindowXorigin, n); - swaps(&rep.rootWindowYorigin, n); + swapl(&rep.length, n); + swapl(&rep.displayNameLength, n); + swapl(&rep.logicalScreen, n); + swaps(&rep.screenWindowWidth, n); + swaps(&rep.screenWindowHeight, n); + swaps(&rep.screenWindowXoffset, n); + swaps(&rep.screenWindowYoffset, n); + swaps(&rep.rootWindowWidth, n); + swaps(&rep.rootWindowHeight, n); + swaps(&rep.rootWindowXoffset, n); + swaps(&rep.rootWindowYoffset, n); + swaps(&rep.rootWindowXorigin, n); + swaps(&rep.rootWindowYorigin, n); } WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep); if (length) WriteToClient(client, length, (char *)attr.displayName); @@ -403,12 +436,12 @@ static int ProcDMXChangeScreensAttributes(ClientPtr client) int errorScreen = 0; unsigned int len; int ones = 0; - + REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq); len = client->req_len - (sizeof(xDMXChangeScreensAttributesReq) >> 2); if (len < stuff->screenCount + stuff->maskCount) - return BadLength; + return BadLength; screen_list = (CARD32 *)(stuff + 1); mask_list = &screen_list[stuff->screenCount]; @@ -416,28 +449,21 @@ static int ProcDMXChangeScreensAttributes(ClientPtr client) for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]); if (len != stuff->screenCount + stuff->maskCount + ones) - return BadLength; - + return BadLength; + if (!_DMXXineramaActive()) goto noxinerama; if (!(attribs = xalloc(stuff->screenCount * sizeof(*attribs)))) - return BadAlloc; + return BadAlloc; for (i = 0; i < stuff->screenCount; i++) { - int count; - - if (i < stuff->maskCount) mask = mask_list[i]; - dmxGetScreenAttributes(screen_list[i], &attribs[i]); - count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); - value_list += count; - } + int count; -#if PANORAMIX - status = dmxConfigureScreenWindows(stuff->screenCount, - screen_list, - attribs, - &errorScreen); -#endif + if (i < stuff->maskCount) mask = mask_list[i]; + dmxGetScreenAttributes(screen_list[i], &attribs[i]); + count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); + value_list += count; + } xfree(attribs); @@ -450,14 +476,14 @@ static int ProcDMXChangeScreensAttributes(ClientPtr client) rep.status = status; rep.errorScreen = errorScreen; if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.errorScreen, n); + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.errorScreen, n); } WriteToClient(client, - sizeof(xDMXChangeScreensAttributesReply), - (char *)&rep); + sizeof(xDMXChangeScreensAttributesReply), + (char *)&rep); return client->noClientException; } @@ -478,20 +504,25 @@ static int ProcDMXAddScreen(ClientPtr client) paddedLength = (stuff->displayNameLength + 3) & ~3; len = client->req_len - (sizeof(xDMXAddScreenReq) >> 2); if (len != Ones(stuff->valueMask) + paddedLength/4) - return BadLength; + return BadLength; memset(&attr, 0, sizeof(attr)); - dmxGetScreenAttributes(stuff->physicalScreen, &attr); + /*dmxGetScreenAttributes(stuff->physicalScreen, &attr); */ value_list = (CARD32 *)(stuff + 1); count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list); - + if (!(name = xalloc(stuff->displayNameLength + 1 + 4))) - return BadAlloc; + return BadAlloc; memcpy(name, &value_list[count], stuff->displayNameLength); name[stuff->displayNameLength] = '\0'; attr.displayName = name; + + status = dmxAttachScreen(stuff->physicalScreen, + &attr, 0, NULL, 0, NULL, 0, NULL, + 0, 0); - status = dmxAttachScreen(stuff->physicalScreen, &attr); + if (status == Success) + dmxEnableScreen(stuff->physicalScreen); xfree(name); @@ -544,28 +575,32 @@ static int dmxPopulatePanoramiX(ClientPtr client, Window window, CARD32 *screens, CARD32 *windows, xRectangle *pos, xRectangle *vis) { - WindowPtr pWin; - PanoramiXRes *win; + DrawablePtr pDraw; + PanoramiXRes *res; int i; int count = 0; DMXWindowAttributesRec attr; - if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ + + if(!(res = (PanoramiXRes *) SecurityLookupIDByClass( + client, window, XRC_DRAWABLE, DixReadAccess))) + return -1; /* BadDrawable */ FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, - DixReadAccess)) - return -1; /* BadWindow */ - if (dmxGetWindowAttributes(pWin, &attr)) { - screens[count] = attr.screen; - windows[count] = attr.window; - pos[count] = attr.pos; - vis[count] = attr.vis; - ++count; /* Only count existing windows */ - } + if (Success == dixLookupDrawable (&pDraw, res->info[i].id, client, + M_ANY, DixUnknownAccess)) + { + if (dmxGetDrawableAttributes (pDraw, &attr)) + { + screens[count] = attr.screen; + windows[count] = attr.window; + pos[count] = attr.pos; + vis[count] = attr.vis; + ++count; /* Only count existing windows */ + } + } } + return count; } #endif @@ -573,7 +608,7 @@ static int dmxPopulatePanoramiX(ClientPtr client, Window window, static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, CARD32 *windows, xRectangle *pos, xRectangle *vis) { - WindowPtr pWin; + DrawablePtr pDraw; DMXWindowAttributesRec attr; #ifdef PANORAMIX @@ -582,14 +617,21 @@ static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, pos, vis); #endif - if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess)) - return -1; /* BadWindow */ + if (Success != dixLookupDrawable (&pDraw, window, client, 0, + DixReadAccess)) + return -1; + + if (!dmxGetDrawableAttributes (pDraw, &attr)) + return -1; - dmxGetWindowAttributes(pWin, &attr); *screens = attr.screen; *windows = attr.window; *pos = attr.pos; *vis = attr.vis; + + if (!attr.window) + abort (); + return 1; } @@ -735,9 +777,6 @@ static int ProcDMXChangeDesktopAttributes(ClientPtr client) dmxGetDesktopAttributes(&attr); dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list); -#if PANORAMIX - status = dmxConfigureDesktop(&attr); -#endif if (status == BadValue) return status; noxinerama: diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h index 00200a8..1cdfce4 100644 --- a/hw/dmx/dmx.h +++ b/hw/dmx/dmx.h @@ -71,6 +71,13 @@ #include <GL/glxint.h> #endif +#include <xcb/xcb.h> +#include <xcb/xcbext.h> + +#include <X11/Xlib-xcb.h> + +#include "dmxxlibio.h" + typedef enum { PosNone = -1, PosAbsolute = 0, @@ -81,21 +88,81 @@ typedef enum { PosRelative } PositionType; -/** Provide the typedef globally, but keep the contents opaque outside - * of the input routines. \see dmxinput.h */ -typedef struct _DMXInputInfo DMXInputInfo; +typedef struct _DMXAtom { + Atom atom; + xcb_intern_atom_cookie_t cookie; +} DMXAtom; + +typedef struct _DMXSequence { + struct _DMXSequence *next; + unsigned long sequence; +} DMXSequence; + +typedef struct _DMXQueue { + DMXSequence *head; + DMXSequence **tail; +} DMXQueue; + +typedef void (*ReplyProcPtr) (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data); + +typedef struct _DMXRequest { + DMXSequence base; + ReplyProcPtr reply; + void *data; +} DMXRequest; + +typedef struct _DMXPropTrans { + const char *name; + const char *format; + Atom type; +} DMXPropTrans; + +typedef struct _DMXSelectionMap { + const char *name; + Atom atom; + Atom beAtom; +} DMXSelectionMap; + +#define DMX_DETACHED 0xff /** Provide the typedef globally, but keep the contents opaque outside * of the XSync statistic routines. \see dmxstat.c */ typedef struct _DMXStatInfo DMXStatInfo; +typedef struct _DMXInputInfo { + DeviceIntPtr *devs; + int numDevs; + int eventBase; +} DMXInputInfo; + +typedef struct _DMXDnDChild DMXDnDChild; + /** Global structure containing information about each backend screen. */ typedef struct _DMXScreenInfo { - const char *name; /**< Name from command line or config file */ + DMXInputInfo input; + + char *name; /**< Name that uniquely identifies screen */ + char *display; /**< Name from command line or config file */ int index; /**< Index into dmxScreens global */ /*---------- Back-end X server information ----------*/ + int fd; + int inDispatch; + + xcb_connection_t *connection; + xcb_get_input_focus_cookie_t sync; + + Atom *atomTable; + int atomTableSize; + + DMXAtom *beAtomTable; + int beAtomTableSize; + Display *beDisplay; /**< Back-end X server's display */ int beWidth; /**< Width of BE display */ int beHeight; /**< Height of BE display */ @@ -106,6 +173,8 @@ typedef struct _DMXScreenInfo { int beNumDepths; /**< Number of depths on BE server */ int *beDepths; /**< Depths from BE server */ + int alive; + int broken; int beNumPixmapFormats; /**< Number of pixmap formats on BE */ XPixmapFormatValues *bePixmapFormats; /**< Pixmap formats on BE */ @@ -120,15 +189,34 @@ typedef struct _DMXScreenInfo { Pixel beBlackPixel; /**< Default black pixel for BE */ Pixel beWhitePixel; /**< Default white pixel for BE */ + int beShapeEventBase; + +#ifdef RANDR + Bool beRandr; /**< Use RANDR support on BE server */ + Bool beRandrPending; + int beRandrEventBase; +#endif + +#ifdef MITSHM + Bool beShm; /**< Use MIT-SHM support on BE server */ + int beShmEventBase; +#endif + + Display *beAttachedDisplay; /**< Disabled X server's display */ + + char *authType; + int authTypeLen; + char *authData; + int authDataLen; + + int virtualFb; + /*---------- Screen window information ----------*/ Window scrnWin; /**< "Screen" window on backend display */ - int scrnX; /**< X offset of "screen" WRT BE display */ - int scrnY; /**< Y offset of "screen" WRT BE display */ int scrnWidth; /**< Width of "screen" */ int scrnHeight; /**< Height of "screen" */ - int scrnXSign; /**< X offset sign of "screen" */ - int scrnYSign; /**< Y offset sign of "screen" */ + int scrnEventMask; /** Default drawables for "screen" */ Drawable scrnDefDrawables[MAXFORMATS]; @@ -141,38 +229,61 @@ typedef struct _DMXScreenInfo { Window rootWin; /**< "Root" window on backend display */ int rootX; /**< X offset of "root" window WRT "screen"*/ int rootY; /**< Y offset of "root" window WRT "screen"*/ - int rootWidth; /**< Width of "root" window */ - int rootHeight; /**< Height of "root" window */ - - int rootXOrigin; /**< Global X origin of "root" window */ - int rootYOrigin; /**< Global Y origin of "root" window */ - - /*---------- Shadow framebuffer information ----------*/ - - void *shadow; /**< Shadow framebuffer data (if enabled) */ - XlibGC shadowGC; /**< Default GC used by shadow FB code */ - XImage *shadowFBImage; /**< Screen image used by shadow FB code */ + int rootEventMask; + + /*---------- Input overlay ----------*/ + XID inputOverlayWid; + WindowPtr pInputOverlayWin; + + /*---------- Selection information ----------*/ + Atom beSelectionAtom; + Window selectionOwner; + xcb_get_selection_owner_cookie_t getSelectionOwner; + Window getSelectionOwnerResult; + Atom multipleAtom; + Atom atomPairAtom; + Atom incrAtom; + + /*---------- DnD information ----------*/ + Atom wmStateAtom; + Atom xdndProxyAtom; + Atom xdndAwareAtom; + Atom xdndSelectionAtom; + Atom xdndEnterAtom; + Atom xdndPositionAtom; + Atom xdndStatusAtom; + Atom xdndLeaveAtom; + Atom xdndDropAtom; + Atom xdndFinishedAtom; + Atom xdndTypeListAtom; + Atom xdndActionAskAtom; + Atom xdndActionListAtom; + Atom xdndActionDescriptionAtom; + Bool dndHasTypeProp; + XID dndWid; + XID dndSource; + XID dndTarget; + int dndStatus; + XID dndWindow; + Atom dndAction; + Atom dndAcceptedAction; + int dndVersion; + Atom dndType[3]; + RegionRec dndBox; + int dndX; + int dndY; + int dndXPos; + int dndYPos; + xcb_translate_coordinates_cookie_t translateCoordinates; + xcb_get_property_cookie_t getTypeProp; + xcb_get_property_cookie_t getActionListProp; + xcb_get_property_cookie_t getActionDescriptionProp; + DMXDnDChild *dndChildren; + int dndNChildren; + xcb_query_tree_cookie_t queryTree; /*---------- Other related information ----------*/ - int shared; /**< Non-zero if another Xdmx is running */ - - Bool WMRunningOnBE; - - Cursor noCursor; - Cursor curCursor; - /* Support for cursors on overlapped - * backend displays. */ - CursorPtr cursor; - int cursorVisible; - int cursorNotShared; /* for overlapping screens on a backend */ - - PositionType where; /**< Relative layout information */ - int whereX; /**< Relative layout information */ - int whereY; /**< Relative layout information */ - int whereRefScreen; /**< Relative layout information */ - - int savedTimeout; /**< Original screen saver timeout */ int dpmsCapable; /**< Non-zero if backend is DPMS capable */ int dpmsEnabled; /**< Non-zero if DPMS enabled */ int dpmsStandby; /**< Original DPMS standby value */ @@ -182,6 +293,9 @@ typedef struct _DMXScreenInfo { DMXStatInfo *stat; /**< Statistics about XSync */ Bool needsSync; /**< True if an XSync is pending */ + DMXQueue ignore; + DMXQueue request; + #ifdef GLXEXT /** Visual information for glxProxy */ int numGlxVisuals; @@ -212,10 +326,15 @@ typedef struct _DMXScreenInfo { CopyWindowProcPtr CopyWindow; ResizeWindowProcPtr ResizeWindow; + HandleExposuresProcPtr HandleExposures; ReparentWindowProcPtr ReparentWindow; ChangeBorderWidthProcPtr ChangeBorderWidth; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; + + SetWindowPixmapProcPtr SetWindowPixmap; + GetImageProcPtr GetImage; GetSpansProcPtr GetSpans; @@ -254,15 +373,16 @@ typedef struct _DMXScreenInfo { TrianglesProcPtr Triangles; TriStripProcPtr TriStrip; TriFanProcPtr TriFan; + + RealizeGlyphProcPtr RealizeGlyph; + UnrealizeGlyphProcPtr UnrealizeGlyph; #endif } DMXScreenInfo; /* Global variables available to all Xserver/hw/dmx routines. */ extern int dmxNumScreens; /**< Number of dmxScreens */ extern DMXScreenInfo *dmxScreens; /**< List of outputs */ -extern int dmxShadowFB; /**< Non-zero if using - * shadow frame-buffer - * (deprecated) */ + extern XErrorEvent dmxLastErrorEvent; /**< Last error that * occurred */ extern Bool dmxErrorOccurred; /**< True if an error @@ -315,6 +435,23 @@ extern Bool dmxIgnoreBadFontPaths; /**< True if bad font extern Bool dmxAddRemoveScreens; /**< True if add and * remove screens support * is enabled */ +#ifdef RANDR +extern int xRROutputsPerScreen; +extern int xRRCrtcsPerScreen; +#endif + +extern DMXPropTrans *dmxPropTrans; +extern int dmxPropTransNum; + +extern DMXSelectionMap *dmxSelectionMap; +extern int dmxSelectionMapNum; + +#ifdef XV +extern char **dmxXvImageFormats; +extern int dmxXvImageFormatsNum; +#endif + +extern char dmxDigest[64]; /** Wrap screen or GC function pointer */ #define DMX_WRAP(_entry, _newfunc, _saved, _actual) \ @@ -370,4 +507,6 @@ do { \ #define MAXSCREENSCALLOC_FATAL(o,m) _MAXSCREENSALLOCF(o,MAXSCREENS*(m),1) #endif +char *dmxMemDup (const char *data, int Len); + #endif /* DMX_H */ diff --git a/hw/dmx/dmxatom.c b/hw/dmx/dmxatom.c new file mode 100644 index 0000000..bfbc30d --- /dev/null +++ b/hw/dmx/dmxatom.c @@ -0,0 +1,236 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmxatom.h" +#include "dmxsync.h" +#include "dmxscrinit.h" + +static void +dmxAddAtom (DMXScreenInfo *dmxScreen, + Atom atom, + Atom beAtom) +{ + int i; + + if (atom >= dmxScreen->beAtomTableSize) + { + DMXAtom *table; + + table = xrealloc (dmxScreen->beAtomTable, + sizeof (DMXAtom) * (atom + 1)); + if (table) + { + for (i = dmxScreen->beAtomTableSize; i < atom; i++) + { + table[i].atom = None; + table[i].cookie.sequence = 0; + } + + table[atom].atom = beAtom; + table[atom].cookie.sequence = 0; + + dmxScreen->beAtomTable = table; + dmxScreen->beAtomTableSize = atom + 1; + } + } + else + { + dmxScreen->beAtomTable[atom].atom = beAtom; + } + + if (beAtom) + { + if (beAtom >= dmxScreen->atomTableSize) + { + Atom *table; + + table = xrealloc (dmxScreen->atomTable, + sizeof (Atom) * (beAtom + 1)); + if (table) + { + for (i = dmxScreen->atomTableSize; i < beAtom; i++) + table[i] = None; + + table[beAtom] = atom; + + dmxScreen->atomTable = table; + dmxScreen->atomTableSize = beAtom + 1; + } + } + else + { + dmxScreen->atomTable[beAtom] = atom; + } + } +} + +static void +dmxInternAtomReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom atom = (Atom) data; + + dmxScreen->beAtomTable[atom].cookie.sequence = 0; + + if (reply) + { + xcb_intern_atom_reply_t *xatom = (xcb_intern_atom_reply_t *) reply; + + dmxAddAtom (dmxScreen, atom, xatom->atom); + } +} + +static unsigned int +dmxBERequestAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + if (atom < dmxScreen->beAtomTableSize) + if (dmxScreen->beAtomTable[atom].atom) + return 0; + + if (atom <= XA_LAST_PREDEFINED) + { + dmxAddAtom (dmxScreen, atom, atom); + } + else + { + char *name; + + dmxAddAtom (dmxScreen, atom, None); + + name = NameForAtom (atom); + if (name && atom < dmxScreen->beAtomTableSize) + { + dmxScreen->beAtomTable[atom].cookie = + xcb_intern_atom (dmxScreen->connection, + FALSE, + strlen (name), + name); + + return dmxScreen->beAtomTable[atom].cookie.sequence; + } + } + + return 0; +} + +Atom +dmxAtom (DMXScreenInfo *dmxScreen, + Atom beAtom) +{ + if (beAtom < dmxScreen->atomTableSize) + if (dmxScreen->atomTable[beAtom]) + return dmxScreen->atomTable[beAtom]; + + if (beAtom <= XA_LAST_PREDEFINED) + { + dmxAddAtom (dmxScreen, beAtom, beAtom); + } + else + { + xcb_get_atom_name_reply_t *reply; + Atom atom; + + reply = xcb_get_atom_name_reply + (dmxScreen->connection, + xcb_get_atom_name (dmxScreen->connection, + beAtom), + NULL); + if (!reply) + return None; + + atom = MakeAtom ((char *) (reply + 1), reply->name_len, TRUE); + + free (reply); + + if (!atom) + return None; + + dmxAddAtom (dmxScreen, atom, beAtom); + } + + if (beAtom < dmxScreen->atomTableSize) + return dmxScreen->atomTable[beAtom]; + + return None; +} + +Atom +dmxBEAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + xcb_intern_atom_cookie_t cookie = { 0 }; + + if (atom < dmxScreen->beAtomTableSize) + { + if (dmxScreen->beAtomTable[atom].atom) + return dmxScreen->beAtomTable[atom].atom; + + cookie = dmxScreen->beAtomTable[atom].cookie; + } + + if (!cookie.sequence) + cookie.sequence = dmxBERequestAtom (dmxScreen, atom); + + if (cookie.sequence) + { + xcb_intern_atom_reply_t *reply; + + reply = xcb_intern_atom_reply (dmxScreen->connection, cookie, NULL); + + dmxInternAtomReply (screenInfo.screens[dmxScreen->index], + cookie.sequence, + (xcb_generic_reply_t *) reply, + NULL, + (void *) atom); + } + + if (atom < dmxScreen->beAtomTableSize) + return dmxScreen->beAtomTable[atom].atom; + + return None; +} + +void +dmxBEPrefetchAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + unsigned int sequence; + + sequence = dmxBERequestAtom (dmxScreen, atom); + if (sequence) + dmxAddRequest (&dmxScreen->request, + dmxInternAtomReply, + sequence, + (void *) atom); +} diff --git a/hw/dmx/dmxatom.h b/hw/dmx/dmxatom.h new file mode 100644 index 0000000..88416b3 --- /dev/null +++ b/hw/dmx/dmxatom.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXATOM_H +#define DMXATOM_H + +#include "dmx.h" + +extern Atom dmxAtom (DMXScreenInfo *dmxScreen, Atom beAtom); +extern Atom dmxBEAtom (DMXScreenInfo *dmxScreen, Atom atom); +extern void dmxBEPrefetchAtom (DMXScreenInfo *dmxScreen, Atom atom); + +#endif /* DMXATOM_H */ diff --git a/hw/dmx/dmxavahi.c b/hw/dmx/dmxavahi.c new file mode 100644 index 0000000..9dfb85e --- /dev/null +++ b/hw/dmx/dmxavahi.c @@ -0,0 +1,358 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Hubert Figuiere <hfiguiere@novell.com> + * David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <avahi-client/client.h> +#include <avahi-client/publish.h> +#include <avahi-common/watch.h> + +#include "dix.h" +#include "os.h" +#include "opaque.h" +#include "dmxavahi.h" + +typedef struct _DMXAvahiPoll DMXAvahiPoll; + +struct AvahiWatch { + struct AvahiWatch *next; + + int fd; + AvahiWatchEvent event; + AvahiWatchCallback callback; + void *userdata; + + DMXAvahiPoll *p; +}; + +struct AvahiTimeout { + struct AvahiTimeout *next; + + AvahiTimeoutCallback callback; + void *userdata; + + DMXAvahiPoll *p; + OsTimerPtr timer; +}; + +struct _DMXAvahiPoll { + AvahiPoll base; + + AvahiWatch *watches; + AvahiTimeout *timeouts; +}; + +static DMXAvahiPoll avahi_poll; +static AvahiClient *avahi_client; +static AvahiEntryGroup *avahi_group; + +static const char * _service_name = "DMX service on %s"; + +static AvahiWatch * +dmx_avahi_watch_new (const AvahiPoll *api, + int fd, + AvahiWatchEvent event, + AvahiWatchCallback callback, + void *userdata) +{ + DMXAvahiPoll *p = (DMXAvahiPoll *) api; + AvahiWatch *w; + + w = xalloc (sizeof (AvahiWatch)); + if (!w) + return NULL; + + w->fd = fd; + w->event = event; + w->callback = callback; + w->userdata = userdata; + w->p = p; + + w->next = p->watches; + p->watches = w; + + if (w->event & AVAHI_WATCH_IN) + AddEnabledDevice (fd); + + return w; +} + +static void +dmx_avahi_watch_update (AvahiWatch *w, + AvahiWatchEvent event) +{ + if (event & AVAHI_WATCH_IN) + { + if (!(w->event & AVAHI_WATCH_IN)) + AddEnabledDevice (w->fd); + } + else + { + if (w->event & AVAHI_WATCH_IN) + RemoveEnabledDevice (w->fd); + } + + w->event = event; +} + +static AvahiWatchEvent +dmx_avahi_watch_get_events (AvahiWatch *w) +{ + return AVAHI_WATCH_IN; +} + +static void +dmx_avahi_watch_free (AvahiWatch *w) +{ + DMXAvahiPoll *p = w->p; + AvahiWatch *prev; + + for (prev = p->watches; prev; prev = prev->next) + if (prev->next == w) + break; + + if (prev) + prev->next = w->next; + else + p->watches = w->next; + + if (w->event & AVAHI_WATCH_IN) + RemoveEnabledDevice (w->fd); + + free (w); +} + +static CARD32 +avahi_poll_timeout (OsTimerPtr timer, + CARD32 time, + pointer arg) +{ + AvahiTimeout *t = (AvahiTimeout *) arg; + + (*t->callback) (t, t->userdata); + + return 0; +} + +static AvahiTimeout * +dmx_avahi_timeout_new (const AvahiPoll *api, + const struct timeval *tv, + AvahiTimeoutCallback callback, + void *userdata) +{ + DMXAvahiPoll *p = (DMXAvahiPoll *) api; + AvahiTimeout *t; + + t = xalloc (sizeof (AvahiTimeout)); + if (!t) + return NULL; + + t->callback = callback; + t->userdata = userdata; + t->timer = NULL; + t->p = p; + + t->next = p->timeouts; + p->timeouts = t; + + if (tv) + t->timer = TimerSet (NULL, + 0, + ((CARD16) tv->tv_sec) * 1000 + tv->tv_usec / 1000, + avahi_poll_timeout, + t); + + return t; +} + +static void +dmx_avahi_timeout_update (AvahiTimeout *t, + const struct timeval *tv) +{ + if (tv) + t->timer = TimerSet (t->timer, + 0, + ((CARD16) tv->tv_sec) * 1000 + tv->tv_usec / 1000, + avahi_poll_timeout, + t); + else + TimerCancel (t->timer); +} + +static void +dmx_avahi_timeout_free (AvahiTimeout *t) +{ + DMXAvahiPoll *p = t->p; + AvahiTimeout *prev; + + for (prev = p->timeouts; prev; prev = prev->next) + if (prev->next == t) + break; + + if (prev) + prev->next = t->next; + else + p->timeouts = t->next; + + TimerFree (t->timer); + + free (t); +} + +static void +avahi_poll_block_handler (pointer blockData, + OSTimePtr pTimeout, + pointer pReadMask) +{ +} + +static void +avahi_poll_wakeup_handler (pointer blockData, + int result, + pointer pReadMask) +{ + DMXAvahiPoll *p = (DMXAvahiPoll *) blockData; + AvahiWatch *w = p->watches; + fd_set *fds = (fd_set *) pReadMask; + + while (w) + { + AvahiWatch *next = w->next; + + if (FD_ISSET (w->fd, fds)) + (*w->callback) (w, w->fd, AVAHI_WATCH_IN, w->userdata); + + w = next; + } +} + +static void +dmx_avahi_poll_init (DMXAvahiPoll *p) +{ + p->base.watch_new = dmx_avahi_watch_new; + p->base.watch_update = dmx_avahi_watch_update; + p->base.watch_get_events = dmx_avahi_watch_get_events; + p->base.watch_free = dmx_avahi_watch_free; + p->base.timeout_new = dmx_avahi_timeout_new; + p->base.timeout_update = dmx_avahi_timeout_update; + p->base.timeout_free = dmx_avahi_timeout_free; + + RegisterBlockAndWakeupHandlers (avahi_poll_block_handler, + avahi_poll_wakeup_handler, + p); +} + +static void +dmx_avahi_poll_fini (DMXAvahiPoll *p) +{ + while (p->timeouts) + dmx_avahi_timeout_free (p->timeouts); + + while (p->watches) + dmx_avahi_watch_free (p->watches); + + RemoveBlockAndWakeupHandlers (avahi_poll_block_handler, + avahi_poll_wakeup_handler, + p); +} + +static void +avahi_client_callback (AvahiClient *c, + AvahiClientState state, + void *userdata) +{ + switch (state) { + case AVAHI_CLIENT_S_RUNNING: { + char hname[512], name[576]; + + if (gethostname (hname, sizeof (hname))) + break; + + sprintf (name, _service_name, hname); + + avahi_group = avahi_entry_group_new (c, 0, 0); + if (avahi_group) + { + avahi_entry_group_add_service (avahi_group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + name, + "_dmx._tcp", + 0, + 0, + 6000 + atoi (display), + NULL); + + avahi_entry_group_commit (avahi_group); + } + } break; + case AVAHI_CLIENT_FAILURE: + case AVAHI_CLIENT_S_COLLISION: + case AVAHI_CLIENT_CONNECTING: + break; + case AVAHI_CLIENT_S_REGISTERING: + if (avahi_group) + avahi_entry_group_reset (avahi_group); + default: + break; + } +} + +void +dmx_avahi_init (void) +{ + dmx_avahi_poll_init (&avahi_poll); + + avahi_group = NULL; + avahi_client = avahi_client_new (&avahi_poll.base, + 0, + avahi_client_callback, + NULL, + NULL); +} + +void +dmx_avahi_fini (void) +{ + if (avahi_group) + { + avahi_entry_group_free (avahi_group); + avahi_group = NULL; + } + + if (avahi_client) + { + avahi_client_free (avahi_client); + avahi_client = NULL; + } + + dmx_avahi_poll_fini (&avahi_poll); +} diff --git a/hw/dmx/dmxavahi.h b/hw/dmx/dmxavahi.h new file mode 100644 index 0000000..881a37c --- /dev/null +++ b/hw/dmx/dmxavahi.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Hubert Figuiere <hfiguiere@novell.com> + * David Reveman <davidr@novell.com> + */ + + +#ifndef DMX_AVAHI_H +#define DMX_AVAHI_H + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#ifdef HAVE_AVAHI +extern void dmx_avahi_init (void); +extern void dmx_avahi_fini (void); +#endif + +#endif diff --git a/hw/dmx/dmxcb.c b/hw/dmx/dmxcb.c index 2ecfe22..47139f3 100644 --- a/hw/dmx/dmxcb.c +++ b/hw/dmx/dmxcb.c @@ -42,6 +42,7 @@ #include "dmxcb.h" #include "dmxinput.h" #include "dmxlog.h" +#include "dmxwindow.h" extern char *ConnectionInfo; extern int connBlockScreenStart; @@ -50,6 +51,8 @@ extern int connBlockScreenStart; extern int PanoramiXPixWidth; extern int PanoramiXPixHeight; extern int PanoramiXNumScreens; +#include "panoramiX.h" +#include "panoramiXsrv.h" #endif int dmxGlobalWidth, dmxGlobalHeight; @@ -64,46 +67,100 @@ void dmxSetWidthHeight(int width, int height) dmxGlobalHeight = height; } -/** Computes the global bounding box for DMX. This may be larger than - * the one computed by Xinerama because of the DMX configuration - * file. */ -void dmxComputeWidthHeight(DMXRecomputeFlag flag) +void dmxComputeWidthHeight(void) { - int i; - DMXScreenInfo *dmxScreen; - int w = 0; - int h = 0; + int i; + ScreenPtr pScreen; + int w = 0; + int h = 0; for (i = 0; i < dmxNumScreens; i++) { - /* Don't use root* here because this is - * the global bounding box. */ - dmxScreen = &dmxScreens[i]; - if (w < dmxScreen->scrnWidth + dmxScreen->rootXOrigin) - w = dmxScreen->scrnWidth + dmxScreen->rootXOrigin; - if (h < dmxScreen->scrnHeight + dmxScreen->rootYOrigin) - h = dmxScreen->scrnHeight + dmxScreen->rootYOrigin; + pScreen = screenInfo.screens[i]; + if (w < pScreen->width) + w = pScreen->width; + if (h < pScreen->height) + h = pScreen->height; } - if (!dmxGlobalWidth && !dmxGlobalHeight) { - dmxLog(dmxInfo, "Using %dx%d as global bounding box\n", w, h); - } else { - switch (flag) { - case DMX_NO_RECOMPUTE_BOUNDING_BOX: - dmxLog(dmxInfo, - "Using old bounding box (%dx%d) instead of new (%dx%d)\n", - dmxGlobalWidth, dmxGlobalHeight, w, h); - w = dmxGlobalWidth; - h = dmxGlobalHeight; - break; - case DMX_RECOMPUTE_BOUNDING_BOX: - dmxLog(dmxInfo, - "Using %dx%d as global bounding box, instead of %dx%d\n", - w, h, dmxGlobalWidth, dmxGlobalHeight); - break; - } + + dmxSetWidthHeight (w, h); +} + +static Bool +dmxCreateInputOverlayWindow (void) +{ + WindowPtr pWin; + XID inputOverlayWid; + XID overrideRedirect = TRUE; + int result; + Atom xdndVersion = 5; + + if (dmxScreens[0].inputOverlayWid) + return TRUE; + + inputOverlayWid = FakeClientID (0); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *newWin; + int j; + + if (!(newWin = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newWin->type = XRT_WINDOW; + newWin->u.win.visibility = VisibilityNotViewable; + newWin->u.win.class = InputOnly; + newWin->u.win.root = FALSE; + newWin->info[0].id = inputOverlayWid; + for(j = 1; j < PanoramiXNumScreens; j++) + newWin->info[j].id = FakeClientID (0); + + FOR_NSCREENS_BACKWARD(j) { + pWin = CreateWindow (newWin->info[j].id, WindowTable[j], + -1, -1, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pWin->drawable.id, RT_WINDOW, pWin)) + return FALSE; + + dmxScreens[j].inputOverlayWid = inputOverlayWid; + dmxScreens[j].pInputOverlayWin = pWin; + } + + AddResource (newWin->info[0].id, XRT_WINDOW, newWin); } - - dmxGlobalWidth = w; - dmxGlobalHeight = h; + else +#endif + + { + pWin = CreateWindow (inputOverlayWid, WindowTable[0], + -1, -1, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pWin->drawable.id, RT_WINDOW, pWin)) + return FALSE; + + dmxScreens[0].inputOverlayWid = inputOverlayWid; + dmxScreens[0].pInputOverlayWin = pWin; + } + + ChangeWindowProperty (dmxScreens[0].pInputOverlayWin, + dmxScreens[0].xdndAwareAtom, + XA_ATOM, + 32, + PropModeReplace, + 1, + &xdndVersion, + TRUE); + + return TRUE; } /** A callback routine that hooks into Xinerama and provides a @@ -198,7 +255,6 @@ void dmxConnectionBlockCallback(void) offset = voffset + depth->nVisuals * sizeof(xVisualType); } - dmxInputLogDevices(); dmxLog(dmxInfo, "===== End of Summary =====\n"); #ifdef PANORAMIX @@ -220,4 +276,7 @@ void dmxConnectionBlockCallback(void) } #endif MAXSCREENSFREE(found); + + if (!dmxCreateInputOverlayWindow ()) + dmxLog (dmxFatal, "dmxCreateInputOverlayWindow: failed"); } diff --git a/hw/dmx/dmxcb.h b/hw/dmx/dmxcb.h index fa334db..6f90830 100644 --- a/hw/dmx/dmxcb.h +++ b/hw/dmx/dmxcb.h @@ -40,14 +40,7 @@ /** The cursor position, in global coordinates. */ extern int dmxGlobalWidth, dmxGlobalHeight; -/** #dmxComputeWidthHeight can either recompute the global bounding box - * or not. */ -typedef enum { - DMX_RECOMPUTE_BOUNDING_BOX, - DMX_NO_RECOMPUTE_BOUNDING_BOX -} DMXRecomputeFlag; - extern void dmxSetWidthHeight(int width, int height); -extern void dmxComputeWidthHeight(DMXRecomputeFlag flag); +extern void dmxComputeWidthHeight(void); extern void dmxConnectionBlockCallback(void); #endif diff --git a/hw/dmx/dmxclient.h b/hw/dmx/dmxclient.h index f0c3608..4673409 100644 --- a/hw/dmx/dmxclient.h +++ b/hw/dmx/dmxclient.h @@ -72,6 +72,11 @@ typedef XID KeySym64; #define Colormap Colormap64 #define GContext GContext64 #define KeySym KeySym64 +#ifdef RANDR +#define RRMode RRMode64 +#define RROutput RROutput64 +#define RRCrtc RRCrtc64 +#endif #endif #include <X11/Xlib.h> @@ -91,16 +96,25 @@ typedef XID KeySym64; #undef PictFormatType #endif +#ifdef RANDR +#include <X11/extensions/Xrandr.h> +#endif + #ifdef XKB #include <X11/extensions/XKB.h> #include <X11/extensions/XKBstr.h> #endif +#ifdef XV +#include <X11/extensions/Xvlib.h> +#endif + #include <X11/extensions/XI.h> /* Always include these, since we query them even if we don't export XINPUT. */ #include <X11/extensions/XInput.h> /* For XDevice */ #include <X11/extensions/Xext.h> +#include <X11/extensions/Xcomposite.h> #undef GC @@ -119,6 +133,11 @@ typedef XID KeySym64; #undef Colormap #undef GContext #undef KeySym +#ifdef RANDR +#undef RRMode +#undef RROutput +#undef RRCrtc +#endif #endif /* These are in exglobals.h, but that conflicts with xkbsrv.h */ diff --git a/hw/dmx/dmxcmap.c b/hw/dmx/dmxcmap.c index 4aa586a..eed5e33 100644 --- a/hw/dmx/dmxcmap.c +++ b/hw/dmx/dmxcmap.c @@ -70,12 +70,15 @@ Bool dmxBECreateColormap(ColormapPtr pColormap) Visual *visual = dmxLookupVisual(pScreen, pVisual); if (visual) { - pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, - dmxScreen->scrnWin, - visual, - (pVisual->class & DynamicClass ? - AllocAll : AllocNone)); - return (pCmapPriv->cmap != 0); + pCmapPriv->cmap = 0; + XLIB_PROLOGUE (dmxScreen); + pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, + dmxScreen->scrnWin, + visual, + (pVisual->class & DynamicClass ? + AllocAll : AllocNone)); + XLIB_EPILOGUE (dmxScreen); + return (pCmapPriv->cmap != 0); } else { dmxLog(dmxWarning, "dmxBECreateColormap: No visual found\n"); @@ -115,7 +118,9 @@ Bool dmxBEFreeColormap(ColormapPtr pColormap) dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); if (pCmapPriv->cmap) { + XLIB_PROLOGUE (dmxScreen); XFreeColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + XLIB_EPILOGUE (dmxScreen); pCmapPriv->cmap = (Colormap)0; return TRUE; } @@ -156,7 +161,9 @@ void dmxInstallColormap(ColormapPtr pColormap) DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); if (dmxScreen->beDisplay) { + XLIB_PROLOGUE (dmxScreen); XInstallColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } } @@ -182,7 +189,9 @@ void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) color[i].flags = pdef[i].flags; color[i].pad = pdef[i].pad; } + XLIB_PROLOGUE (dmxScreen); XStoreColors(dmxScreen->beDisplay, pCmapPriv->cmap, color, ndef); + XLIB_EPILOGUE (dmxScreen); xfree(color); } else { /* xalloc failed, so fallback */ XColor c; @@ -193,7 +202,9 @@ void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) c.green = pdef[i].green; c.flags = pdef[i].flags; c.pad = pdef[i].pad; + XLIB_PROLOGUE (dmxScreen); XStoreColor(dmxScreen->beDisplay, pCmapPriv->cmap, &c); + XLIB_EPILOGUE (dmxScreen); } } dmxSync(dmxScreen, FALSE); diff --git a/hw/dmx/dmxcomp.c b/hw/dmx/dmxcomp.c new file mode 100644 index 0000000..debd97d --- /dev/null +++ b/hw/dmx/dmxcomp.c @@ -0,0 +1,199 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxcomp.h" +#include "compint.h" + +extern int (*ProcCompositeVector[CompositeNumberRequests]) (ClientPtr); +static int (*dmxSaveCompositeVector[CompositeNumberRequests]) (ClientPtr); + +unsigned long DMX_CLIENTWINDOW; +unsigned long DMX_CLIENTSUBWINDOWS; + +static int +dmxProcCompositeRedirectWindow (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; + } + + /* Add implicit CompositeRedirectManual. This prevents clients + from using CompositeRedirectManual and composite extension from + handling window updates. Window updates are handled by + back-end servers. */ + if (!GetCompWindow (pWin)) + { + rc = compRedirectWindow (serverClient, pWin, CompositeRedirectManual); + if (rc != Success) + return rc; + } + + rc = compRedirectWindow (client, pWin, stuff->update); + if (rc == Success) + { + AddResource (GetCompWindow (pWin)->clients->id, + DMX_CLIENTWINDOW, + pWin); + } + else + { + if (!GetCompWindow (pWin)->clients->next) + compUnredirectWindow (serverClient, pWin, CompositeRedirectManual); + } + + return rc; +} + +static int +dmxProcCompositeRedirectSubwindows (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; + } + + if (!GetCompSubwindows (pWin)) + { + rc = compRedirectSubwindows (serverClient, pWin, + CompositeRedirectManual); + if (rc != Success) + return rc; + } + + rc = compRedirectSubwindows (client, pWin, stuff->update); + if (rc == Success) + { + AddResource (GetCompSubwindows (pWin)->clients->id, + DMX_CLIENTSUBWINDOWS, + pWin); + } + else + { + if (!GetCompSubwindows (pWin)->clients->next) + compUnredirectSubwindows (serverClient, pWin, + CompositeRedirectManual); + } + + return rc; +} + +static int +dmxFreeCompositeClientWindow (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw; + int count = 0; + + for (ccw = cw->clients; ccw; ccw = ccw->next) + if (ccw->update != CompositeRedirectManual) + count++; + + /* free our implicit manual redirect if that's the only one left */ + if (count <= 1) + compUnredirectWindow (serverClient, pWin, CompositeRedirectManual); + + return Success; +} + +static int +dmxFreeCompositeClientSubwindows (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw; + int count = 0; + + for (ccw = csw->clients; ccw; ccw = ccw->next) + if (ccw->update != CompositeRedirectManual) + count++; + + /* free our implicit manual redirect if that's the only one left */ + if (count <= 1) + compUnredirectSubwindows (serverClient, pWin, + CompositeRedirectManual); + + return Success; +} + +/** Initialize the Proc Vector for the Composite extension. The functions + * here cannot be handled by the mi layer Composite hooks either because + * the required information is no longer available when it reaches the + * mi layer or no mi layer hooks exist. This function is called from + * InitOutput() since it should be initialized only once per server + * generation. */ +void +dmxInitComposite (void) +{ + int i; + + DMX_CLIENTWINDOW = CreateNewResourceType (dmxFreeCompositeClientWindow); + DMX_CLIENTSUBWINDOWS = + CreateNewResourceType (dmxFreeCompositeClientSubwindows); + + for (i = 0; i < CompositeNumberRequests; i++) + dmxSaveCompositeVector[i] = ProcCompositeVector[i]; + + ProcCompositeVector[X_CompositeRedirectWindow] + = dmxProcCompositeRedirectWindow; + ProcCompositeVector[X_CompositeRedirectSubwindows] + = dmxProcCompositeRedirectSubwindows; +} + +/** Reset the Proc Vector for the Composite extension back to the original + * functions. This function is called from dmxCloseScreen() during the + * server reset (only for screen #0). */ +void +dmxResetComposite (void) +{ + int i; + + for (i = 0; i < CompositeNumberRequests; i++) + ProcCompositeVector[i] = dmxSaveCompositeVector[i]; +} diff --git a/hw/dmx/dmxcomp.h b/hw/dmx/dmxcomp.h new file mode 100644 index 0000000..f9bffbf --- /dev/null +++ b/hw/dmx/dmxcomp.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXCOMP_H +#define DMXCOMP_H + +void +dmxInitComposite (void); + +void +dmxResetComposite (void); + +#endif /* DMXCOMP_H */ diff --git a/hw/dmx/dmxcursor.c b/hw/dmx/dmxcursor.c index 6218dc3..24cc7ee 100644 --- a/hw/dmx/dmxcursor.c +++ b/hw/dmx/dmxcursor.c @@ -33,548 +33,86 @@ * */ -/** \file - * This file contains code than supports cursor movement, including the - * code that initializes and reinitializes the screen positions and - * computes screen overlap. - * - * "This code is based very closely on the XFree86 equivalent - * (xfree86/common/xf86Cursor.c)." --David Dawes. - * - * "This code was then extensively re-written, as explained here." - * --Rik Faith - * - * The code in xf86Cursor.c used edge lists to implement the - * CursorOffScreen function. The edge list computation was complex - * (especially in the face of arbitrarily overlapping screens) compared - * with the speed savings in the CursorOffScreen function. The new - * implementation has erred on the side of correctness, readability, and - * maintainability over efficiency. For the common (non-edge) case, the - * dmxCursorOffScreen function does avoid a loop over all the screens. - * When the cursor has left the screen, all the screens are searched, - * and the first screen (in dmxScreens order) containing the cursor will - * be returned. If run-time profiling shows that this routing is a - * performance bottle-neck, then an edge list may have to be - * reimplemented. An edge list algorithm is O(edges) whereas the new - * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and - * dmxNumScreens may be 30-60 for large backend walls, this trade off - * may be compelling. - * - * The xf86InitOrigins routine uses bit masks during the computation and - * is therefore limited to the length of a word (e.g., 32 or 64 bits) - * screens. Because Xdmx is expected to be used with a large number of - * backend displays, this limitation was removed. The new - * implementation has erred on the side of readability over efficiency, - * using the dmxSL* routines to manage a screen list instead of a - * bitmap, and a function call to decrease the length of the main - * routine. Both algorithms are of the same order, and both are called - * only at server generation time, so trading clarity and long-term - * maintainability for efficiency does not seem justified in this case. - */ - #ifdef HAVE_DMX_CONFIG_H #include <dmx-config.h> #endif -#define DMX_CURSOR_DEBUG 0 - #include "dmx.h" #include "dmxsync.h" #include "dmxcursor.h" #include "dmxlog.h" #include "dmxprop.h" #include "dmxinput.h" +#include "dmxgrab.h" #include "mipointer.h" #include "windowstr.h" #include "globals.h" #include "cursorstr.h" -#include "dixevents.h" /* For GetSpriteCursor() */ - -#if DMX_CURSOR_DEBUG -#define DMXDBG0(f) dmxLog(dmxDebug,f) -#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) -#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) -#else -#define DMXDBG0(f) -#define DMXDBG1(f,a) -#define DMXDBG2(f,a,b) -#define DMXDBG3(f,a,b,c) -#define DMXDBG4(f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) -#endif - -static int dmxCursorDoMultiCursors = 1; -/** Turn off support for displaying multiple cursors on overlapped - back-end displays. See #dmxCursorDoMultiCursors. */ -void dmxCursorNoMulti(void) +Bool +dmxInitCursor (ScreenPtr pScreen) { - dmxCursorDoMultiCursors = 0; -} + if (!dixRequestPrivate(pScreen, sizeof(dmxCursorPrivRec))) + return FALSE; -static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - DMXScreenInfo *dmxScreen; - int i; - int localX = *x; - int localY = *y; - int globalX; - int globalY; - - if (screenInfo.numScreens == 1) - return FALSE; - - /* On current screen? */ - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (localX >= 0 - && localX < dmxScreen->rootWidth - && localY >= 0 - && localY < dmxScreen->rootHeight) - return FALSE; - - /* Convert to global coordinate space */ - globalX = dmxScreen->rootXOrigin + localX; - globalY = dmxScreen->rootYOrigin + localY; - - /* Is cursor on the current screen? - * This efficiently exits this routine - * for the most common case. */ - if (ppScreen && *ppScreen) { - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) - return FALSE; - } + if (!dixRequestPrivate (dmxDevicePrivateKey, sizeof (dmxDevicePrivRec))) + return FALSE; - /* Find first screen cursor is on */ - for (i = 0; i < dmxNumScreens; i++) { - dmxScreen = &dmxScreens[i]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { - if (dmxScreen->index == (*ppScreen)->myNum) - return FALSE; - *ppScreen = screenInfo.screens[dmxScreen->index]; - *x = globalX - dmxScreen->rootXOrigin; - *y = globalY - dmxScreen->rootYOrigin; - return TRUE; - } - } - return FALSE; + return TRUE; } -static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) +static Bool +dmxCursorOffScreen (ScreenPtr *ppScreen, + int *x, + int *y) { + return FALSE; } -static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +static void +dmxCrossScreen (ScreenPtr pScreen, + Bool entering) { - DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); -#if 11 /*BP*/ - /* This call is depracated. Replace with???? */ - miPointerWarpCursor(pDev, pScreen, x, y); -#else - pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); -#endif } -miPointerScreenFuncRec dmxPointerCursorFuncs = +static void +dmxWarpCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + int x, + int y) { - dmxCursorOffScreen, - dmxCrossScreen, - dmxWarpCursor, - dmxeqEnqueue, /*XXX incompatible type/function! */ - dmxeqSwitchScreen -}; - - -/** Create a list of screens that we'll manipulate. */ -static int *dmxSLCreate(void) -{ - int *list = malloc(dmxNumScreens * sizeof(*list)); int i; - - for (i = 0; i < dmxNumScreens; i++) - list[i] = 1; - return list; -} -/** Free list. */ -static void dmxSLFree(int *list) -{ - free(list); -} - -/** Find next uninitialized entry in list. */ -static int dmxSLFindNext(int *list) -{ - int i; for (i = 0; i < dmxNumScreens; i++) - if (list[i]) - return i; - return -1; -} - -/** Make one pass over all the screens and return the number updated. */ -static int dmxTryComputeScreenOrigins(int *screensLeft) -{ - ScreenPtr pScreen; - DMXScreenInfo *screen; - int i, ref; - int changed = 0; - - for (i = 0; i < dmxNumScreens; i++) { - if (!screensLeft[i]) - continue; - screen = &dmxScreens[i]; - switch (screen->where) { - case PosAbsolute: - dixScreenOrigins[i].x = screen->whereX; - dixScreenOrigins[i].y = screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRelative: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRightOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosLeftOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosBelow: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosAbove: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosNone: - dmxLog(dmxFatal, "No position information for screen %d\n", i); - } - } - return changed; -} + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; -static void dmxComputeScreenOrigins(void) -{ - int *screensLeft; - int i, ref; - int minX, minY; - - /* Compute origins based on - * configuration information. */ - screensLeft = dmxSLCreate(); - while ((i = dmxSLFindNext(screensLeft)) >= 0) { - while (dmxTryComputeScreenOrigins(screensLeft)); - if ((i = dmxSLFindNext(screensLeft)) >= 0) { - /* All of the remaining screens are referencing each other. - * Assign a value to one of them and go through again. This - * guarantees that we will eventually terminate. - */ - ref = dmxScreens[i].whereRefScreen; - dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; - screensLeft[ref] = 0; - } - } - dmxSLFree(screensLeft); - - - /* Justify the topmost and leftmost to - * (0,0). */ - minX = dixScreenOrigins[0].x; - minY = dixScreenOrigins[0].y; - for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ - if (dixScreenOrigins[i].x < minX) - minX = dixScreenOrigins[i].x; - if (dixScreenOrigins[i].y < minY) - minY = dixScreenOrigins[i].y; - } - if (minX || minY) { - for (i = 0; i < dmxNumScreens; i++) { - dixScreenOrigins[i].x -= minX; - dixScreenOrigins[i].y -= minY; - } - } -} + if (!dmxScreen->beDisplay) + continue; -/** Recompute origin information in the #dmxScreens list. This is - * either called from #dmxInitOrigins() or from #dmxReconfig(). */ -void dmxReInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); + dmxInputWarpPointer (&dmxScreen->input, pDev, x, y); } } -/** Initialize screen origins (and relative position). This is called - * for each server generation. For dynamic reconfiguration, use - * #dmxReInitOrigins() instead. */ -void dmxInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->whereX, dmxScreen->whereY, - dmxScreen->where, - - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - } - - dmxComputeScreenOrigins(); +miPointerScreenFuncRec dmxPointerCursorFuncs = { + dmxCursorOffScreen, + dmxCrossScreen, + dmxWarpCursor +}; - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxScreen->rootXOrigin = dixScreenOrigins[i].x; - dmxScreen->rootYOrigin = dixScreenOrigins[i].y; - } +#ifdef ARGB_CURSOR - dmxReInitOrigins(); -} +static Cursor +dmxCreateARGBCursor (ScreenPtr pScreen, + CursorPtr pCursor); -/** Returns non-zero if the global \a x, \a y coordinate is on the - * screen window of the \a dmxScreen. */ -int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) -{ -#if DMX_CURSOR_DEBUG > 1 - dmxLog(dmxDebug, - "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", - dmxScreen->index, x, y, - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY); #endif - if (x >= dmxScreen->rootXOrigin - && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && y >= dmxScreen->rootYOrigin - && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; - return 0; -} - -/** Returns non-zero if \a a overlaps \a b. */ -static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) -{ - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - return 0; -} - -/** Used with #dmxInterateOverlap to print out a list of screens which - * overlap each other. */ -static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) -{ - DMXScreenInfo *a = closure; - if (dmxScreen != a) { - if (dmxScreen->cursorNotShared) - dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); - else - dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); - } - return NULL; -} - -/** Iterate over the screens which overlap with the \a start screen, - * calling \a f with the \a closure for each argument. Often used with - * #dmxPrintOverlap. */ -static void *dmxIterateOverlap(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) -{ - DMXScreenInfo *pt; - - if (!start->over) return f(start, closure); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - void *retval; - if ((retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; -} - -/** Used with #dmxPropertyIterate to determine if screen \a a is the - * same as the screen \a closure. */ -static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) -{ - DMXScreenInfo *b = closure; - - if (a == b) - return a; - return NULL; -} - -/** Detects overlapping dmxScreens and creates circular lists. This - * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and - * the computation only needs to be performed for every server - * generation or dynamic reconfiguration . */ -void dmxInitOverlap(void) -{ - int i, j; - DMXScreenInfo *a, *b, *pt; - - for (i = 0; i < dmxNumScreens; i++) - dmxScreens[i].over = NULL; - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - for (j = i+1; j < dmxNumScreens; j++) { - b = &dmxScreens[j]; - if (b->over) - continue; - - if (dmxDoesOverlap(a, b)) { - DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", - a->index, b->index, a, a->over, b, b->over); - b->over = (a->over ? a->over : a); - a->over = b; - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (!a->over) - continue; - - /* Flag all pairs that are on same display */ - for (pt = a->over; pt != a; pt = pt->over) { - if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { - /* The ->over sets contain the transitive set of screens - * that overlap. For screens that are on the same - * backend display, we only want to exclude pairs of - * screens that mutually overlap on the backend display, - * so we call dmxDoesOverlap, which is stricter than the - * ->over set. */ - if (!dmxDoesOverlap(a, pt)) - continue; - a->cursorNotShared = 1; - pt->cursorNotShared = 1; - dmxLog(dmxInfo, - "Screen %d and %d overlap on %s\n", - a->index, pt->index, a->name); - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (a->over) { - dmxLogOutput(a, "Overlaps"); - dmxIterateOverlap(a, dmxPrintOverlap, a); - dmxLogOutputCont(a, "\n"); - } - } -} /** Create \a pCursor on the back-end associated with \a pScreen. */ -void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) +void +dmxBECreateCursor (ScreenPtr pScreen, + CursorPtr pCursor) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); @@ -587,9 +125,49 @@ void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) unsigned long m; int i; - if (!pCursorPriv) + if (pCursorPriv->cursor) return; + if (IsAnimCur (pCursor)) + { + AnimCurPtr ac = GetAnimCur (pCursor); + XAnimCursor *cursors; + int i; + + cursors = xalloc (sizeof (*cursors) * ac->nelt); + if (!cursors) + return; + + for (i = 0; i < ac->nelt; i++) + { + dmxCursorPrivPtr pEltPriv = DMX_GET_CURSOR_PRIV (ac->elts[i].pCursor, + pScreen); + + dmxBECreateCursor (pScreen, ac->elts[i].pCursor); + + cursors[i].cursor = pEltPriv->cursor; + cursors[i].delay = ac->elts[i].delay; + } + + pCursorPriv->cursor = XRenderCreateAnimCursor (dmxScreen->beDisplay, + ac->nelt, + cursors); + + xfree (cursors); + + if (pCursorPriv->cursor) + return; + } + +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + { + pCursorPriv->cursor = dmxCreateARGBCursor (pScreen, pCursor); + if (pCursorPriv->cursor) + return; + } +#endif + m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; v.function = GXcopy; v.plane_mask = AllPlanes; @@ -600,14 +178,18 @@ void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { if (dmxScreen->bePixmapFormats[i].depth == 1) { /* Create GC in the back-end servers */ + XLIB_PROLOGUE (dmxScreen); gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], m, &v); + XLIB_EPILOGUE (dmxScreen); break; } } if (!gc) dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); + XLIB_PROLOGUE (dmxScreen); + src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, pBits->width, pBits->height, 1); msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, @@ -652,329 +234,113 @@ void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) XFreePixmap(dmxScreen->beDisplay, msk); XFreeGC(dmxScreen->beDisplay, gc); - dmxSync(dmxScreen, FALSE); + XLIB_EPILOGUE (dmxScreen); } -static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +static Bool +_dmxRealizeCursor (ScreenPtr pScreen, + CursorPtr pCursor) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv; - - DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); - - DMX_SET_CURSOR_PRIV(pCursor, pScreen, xalloc(sizeof(*pCursorPriv))); - if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) - return FALSE; + dmxCursorPrivPtr pCursorPriv; - pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - pCursorPriv->cursor = (Cursor)0; + pCursorPriv = DMX_GET_CURSOR_PRIV (pCursor, pScreen); + pCursorPriv->cursor = (Cursor) 0; - if (!dmxScreen->beDisplay) - return TRUE; + if (dmxScreen->beDisplay) + dmxBECreateCursor (pScreen, pCursor); - dmxBECreateCursor(pScreen, pCursor); return TRUE; } /** Free \a pCursor on the back-end associated with \a pScreen. */ -Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - - if (pCursorPriv) { - XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); - pCursorPriv->cursor = (Cursor)0; - return TRUE; - } - - return FALSE; -} - -static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +Bool +dmxBEFreeCursor (ScreenPtr pScreen, + CursorPtr pCursor) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV (pCursor, pScreen); - DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", - pScreen->myNum, pCursor); - - if (dmxScreen->beDisplay) { - if (dmxBEFreeCursor(pScreen, pCursor)) - xfree(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); - } - DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); + if (pCursorPriv->cursor) + { + XLIB_PROLOGUE (dmxScreen); + XFreeCursor (dmxScreen->beDisplay, pCursorPriv->cursor); + XLIB_EPILOGUE (dmxScreen); - return TRUE; -} + pCursorPriv->cursor = (Cursor) 0; -static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - int newX = x + dmxScreen->rootX; - int newY = y + dmxScreen->rootY; - - if (newX < 0) newX = 0; - if (newY < 0) newY = 0; - - DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", - pScreen->myNum, x, y, newX, newY); - if (dmxScreen->beDisplay) { - XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, - 0, 0, 0, 0, newX, newY); - dmxSync(dmxScreen, TRUE); - } -} - -static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + if (IsAnimCur (pCursor)) + { + AnimCurPtr ac = GetAnimCur (pCursor); + int i; - DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); - - if (pCursor) { - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - pCursorPriv->cursor); - dmxScreen->cursor = pCursor; - dmxScreen->curCursor = pCursorPriv->cursor; - dmxScreen->cursorVisible = 1; + for (i = 0; i < ac->nelt; i++) + dmxBEFreeCursor (pScreen, ac->elts[i].pCursor); } - _dmxMoveCursor(pScreen, x, y); - } else { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - dmxScreen->cursor = NULL; - dmxScreen->curCursor = (Cursor)0; - dmxScreen->cursorVisible = 0; - } - if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); -} -static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxRealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; + return TRUE; } - return TRUE; -} -static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxUnrealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; - } - return TRUE; + return FALSE; } -static CursorPtr dmxFindCursor(DMXScreenInfo *start) +static Bool +_dmxUnrealizeCursor (ScreenPtr pScreen, + CursorPtr pCursor) { - DMXScreenInfo *pt; - - if (!start || !start->over) - return GetSpriteCursor(inputInfo.pointer); - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursor) - return pt->cursor; - if (pt == start) - break; - } - return GetSpriteCursor(inputInfo.pointer); + dmxBEFreeCursor (pScreen, pCursor); + return TRUE; } -/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This - * function is usually called via #dmxPointerSpriteFuncs, except during - * reconfiguration when the cursor is repositioned to force an update on - * newley overlapping screens and on screens that no longer overlap. - * - * The coords (x,y) are in global coord space. We'll loop over the - * back-end screens and see if they contain the global coord. If so, call - * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. - */ -void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +static Bool +dmxRealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) { - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxMoveCursor(pScreen, x, y); - return; - } + if (pDev == inputInfo.pointer) + return _dmxRealizeCursor (pScreen, pCursor); - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - if (/* pt != start && */ !pt->cursorVisible) { - if (!pt->cursor) { - /* This only happens during - * reconfiguration when a new overlap - * occurs. */ - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(start))) - _dmxRealizeCursor(screenInfo.screens[pt->index], - pt->cursor = pCursor); - - } - _dmxSetCursor(screenInfo.screens[pt->index], - pt->cursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - _dmxMoveCursor(screenInfo.screens[pt->index], - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else if (/* pt != start && */ pt->cursorVisible) { - _dmxSetCursor(screenInfo.screens[pt->index], - NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } + return TRUE; } -static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +static Bool +dmxUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) { - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - int GX, GY, gx, gy; - - DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", - pScreen->myNum, start, pCursor, x, y); - - /* We do this check here because of two cases: - * - * 1) if a client calls XWarpPointer() - * and Xinerama is not running, we can - * have mi's notion of the pointer - * position out of phase with DMX's - * notion. - * - * 2) if a down button is held while the - * cursor moves outside the root window, - * mi's notion of the pointer position - * is out of phase with DMX's notion and - * the cursor can remain visible when it - * shouldn't be. */ - - dmxGetGlobalPosition(&GX, &GY); - gx = start->rootXOrigin + x; - gy = start->rootYOrigin + y; - if (x && y && (GX != gx || GY != gy)) - dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxSetCursor(pScreen, pCursor, x, y); - return; - } + if (pDev == inputInfo.pointer) + return _dmxUnrealizeCursor (pScreen, pCursor); - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - _dmxSetCursor(screenInfo.screens[pt->index], pCursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else { - _dmxSetCursor(screenInfo.screens[pt->index], NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } + return TRUE; } - -/** This routine is used by the backend input routines to hide the - * cursor on a screen that is being used for relative input. \see - * dmxbackend.c */ -void dmxHideCursor(DMXScreenInfo *dmxScreen) +static void +dmxMoveCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + int x, + int y) { - int x, y; - ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; - - dmxGetGlobalPosition(&x, &y); - _dmxSetCursor(pScreen, NULL, x, y); } -/** This routine is called during reconfiguration to make sure the - * cursor is visible. */ -void dmxCheckCursor(void) +static void +dmxSetCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor, + int x, + int y) { - int i; - int x, y; - ScreenPtr pScreen; - DMXScreenInfo *firstScreen; - - dmxGetGlobalPosition(&x, &y); - firstScreen = dmxFindFirstScreen(x, y); - - DMXDBG2("dmxCheckCursor %d %d\n", x, y); - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - pScreen = screenInfo.screens[dmxScreen->index]; - - if (!dmxOnScreen(x, y, dmxScreen)) { -#if 00 - if (firstScreen && i == miPointerCurrentScreen()->myNum) - miPointerSetNewScreen(firstScreen->index, x, y); -#else - if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) - miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); -#endif - _dmxSetCursor(pScreen, NULL, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } else { - if (!dmxScreen->cursor) { - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(dmxScreen))) { - _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); - } - } - _dmxSetCursor(pScreen, dmxScreen->cursor, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } - } - DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); } -static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) +static Bool +dmxDeviceCursorInitialize (DeviceIntPtr pDev, + ScreenPtr pScr) { return TRUE; } -static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) +static void +dmxDeviceCursorCleanup (DeviceIntPtr pDev, + ScreenPtr pScr) { } @@ -987,3 +353,62 @@ miPointerSpriteFuncRec dmxPointerSpriteFuncs = dmxDeviceCursorInitialize, dmxDeviceCursorCleanup }; + +#ifdef ARGB_CURSOR + +#include <X11/extensions/Xrender.h> + +static Cursor +dmxCreateARGBCursor (ScreenPtr pScreen, + CursorPtr pCursor) +{ + Pixmap xpixmap; + XlibGC xgc; + XImage *ximage; + XRenderPictFormat *xformat; + Picture xpicture; + Cursor cursor = None; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + XLIB_PROLOGUE (dmxScreen); + + xpixmap = XCreatePixmap (dmxScreen->beDisplay, + dmxScreen->scrnWin, + pCursor->bits->width, + pCursor->bits->height, + 32); + + xgc = XCreateGC (dmxScreen->beDisplay, xpixmap, 0, NULL); + + ximage = XCreateImage (dmxScreen->beDisplay, + DefaultVisual (dmxScreen->beDisplay, 0), + 32, ZPixmap, 0, + (char *) pCursor->bits->argb, + pCursor->bits->width, + pCursor->bits->height, + 32, pCursor->bits->width * 4); + + XPutImage (dmxScreen->beDisplay, xpixmap, xgc, ximage, + 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); + + XFree (ximage); + XFreeGC (dmxScreen->beDisplay, xgc); + + xformat = XRenderFindStandardFormat (dmxScreen->beDisplay, + PictStandardARGB32); + xpicture = XRenderCreatePicture (dmxScreen->beDisplay, xpixmap, + xformat, 0, 0); + + cursor = XRenderCreateCursor (dmxScreen->beDisplay, xpicture, + pCursor->bits->xhot, + pCursor->bits->yhot); + + XRenderFreePicture (dmxScreen->beDisplay, xpicture); + XFreePixmap (dmxScreen->beDisplay, xpixmap); + + XLIB_EPILOGUE (dmxScreen); + + return cursor; +} + +#endif diff --git a/hw/dmx/dmxcursor.h b/hw/dmx/dmxcursor.h index da8ea5e..19c596b 100644 --- a/hw/dmx/dmxcursor.h +++ b/hw/dmx/dmxcursor.h @@ -1,3 +1,4 @@ +/* $XFree86$ */ /* * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. * @@ -51,22 +52,11 @@ extern miPointerScreenFuncRec dmxPointerCursorFuncs; /** Sprite functions for mi layer. \see dmxcursor.c \see dmxscrinit.c */ extern miPointerSpriteFuncRec dmxPointerSpriteFuncs; -extern void dmxReInitOrigins(void); -extern void dmxInitOrigins(void); -extern void dmxInitOverlap(void); -extern void dmxCursorNoMulti(void); -extern void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); -extern void dmxCheckCursor(void); -extern int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen); -extern void dmxHideCursor(DMXScreenInfo *dmxScreen); +extern Bool dmxInitCursor(ScreenPtr pScreen); extern void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor); extern Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor); #define DMX_GET_CURSOR_PRIV(_pCursor, _pScreen) \ ((dmxCursorPrivPtr)dixLookupPrivate(&(_pCursor)->devPrivates, _pScreen)) - -#define DMX_SET_CURSOR_PRIV(_pCursor, _pScreen, v) \ - dixSetPrivate(&(_pCursor)->devPrivates, _pScreen, v) - #endif /* DMXCURSOR_H */ diff --git a/hw/dmx/dmxdbus.c b/hw/dmx/dmxdbus.c new file mode 100644 index 0000000..0ea4628 --- /dev/null +++ b/hw/dmx/dmxdbus.c @@ -0,0 +1,549 @@ +/* + * Copyright © 2006-2007 Daniel Stone + * Copyright © 2008 Novell, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Daniel Stone <daniel@fooishbar.org> + * David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "config-backends.h" +#include "dixstruct.h" +#include "opaque.h" /* for 'display': there should be a better way. */ +#include "dmxdbus.h" +#include "dmxextension.h" + +#define API_VERSION 3 + +#define MATCH_RULE "type='method_call',interface='org.x.config.dmx'" +#define MALFORMED_MSG "[dmx/dbus] malformed message, dropping" + +struct connection_info { + char busobject[32]; + char busname[64]; + DBusConnection *connection; +}; + +static void +reset_info (struct connection_info *info) +{ + info->connection = NULL; + info->busname[0] = '\0'; + info->busobject[0] = '\0'; +} + +static int +enable_screen (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DMXScreenAttributesRec attr; + uint32_t screen; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &screen, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + if (screen >= dmxGetNumScreens ()) + { + dbus_set_error (error, + DMX_ERROR_INVALID_SCREEN, + "Screen %d does not exist", screen); + return BadValue; + } + + dmxGetScreenAttributes (screen, &attr); + + if (!attr.name || !*attr.name) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "No back-end server attached to screen %d", + screen); + return BadValue; + } + + dmxEnableScreen(screen); + + return Success; +} + +static int +disable_screen (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DMXScreenAttributesRec attr; + uint32_t screen; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &screen, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + if (screen >= dmxGetNumScreens ()) + { + dbus_set_error (error, + DMX_ERROR_INVALID_SCREEN, + "Screen %d does not exist", screen); + return BadValue; + } + + dmxGetScreenAttributes (screen, &attr); + + if (!attr.name || !*attr.name) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "No back-end server attached to screen %d", + screen); + return BadValue; + } + + dmxDisableScreen(screen); + + return Success; +} + +static int +attach_screen (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DMXScreenAttributesRec attr; + uint32_t window, screen, auth_type_len, auth_data_len; + char *display, *auth_type, *auth_data, *name; + int ret; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &screen, + DBUS_TYPE_STRING, + &display, + DBUS_TYPE_STRING, + &name, + DBUS_TYPE_UINT32, + &window, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &auth_type, &auth_type_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &auth_data, &auth_data_len, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + if (!*name) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Cannot use empty string for screen name"); + return BadValue; + } + + if (screen >= dmxGetNumScreens ()) + { + dbus_set_error (error, + DMX_ERROR_INVALID_SCREEN, + "Screen %d does not exist", screen); + return BadValue; + } + + dmxGetScreenAttributes (screen, &attr); + + if (attr.name && *attr.name) + { + dbus_set_error (error, + DMX_ERROR_SCREEN_IN_USE, + "Back-end server already attached to screen %d", + screen); + return BadValue; + } + + memset (&attr, 0, sizeof (attr)); + + attr.name = name; + attr.displayName = display; + + ret = dmxAttachScreen (screen, + &attr, + window, + auth_type, + auth_type_len, + auth_data, + auth_data_len, + (dmxErrorSetProcPtr) dbus_set_error, + error, + DBUS_ERROR_FAILED); + + if (ret != Success) + { + DebugF ("[dmx/dbus] dmxAttachScreen failed\n"); + return ret; + } + + return Success; +} + +static int +detach_screen (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + uint32_t screen; + int ret; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &screen, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + ret = dmxDetachScreen (screen); + if (ret != Success) + { + DebugF ("[dmx/dbus] dmxDetachScreen failed\n"); + return ret; + } + + return Success; +} + +static int +add_input (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DMXInputAttributesRec attr; + DBusMessageIter iter; + uint32_t screen, id; + dbus_bool_t core; + int input_id, ret; + + dbus_message_iter_init_append (reply, &iter); + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &screen, + DBUS_TYPE_BOOLEAN, + &core, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + memset (&attr, 0, sizeof (attr)); + + attr.physicalScreen = screen; + attr.inputType = 2; + + ret = dmxAddInput (&attr, &input_id); + if (ret != Success) + { + DebugF ("[dmx/dbus] dmxAddInput failed\n"); + return ret; + } + + id = input_id; + + if (!dbus_message_iter_append_basic (&iter, + DBUS_TYPE_UINT32, + &id)) + { + ErrorF ("[dmx/dbus] couldn't append to iterator\n"); + dmxRemoveInput (id); + return BadAlloc; + } + + return Success; +} + +static int +remove_input (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + uint32_t id; + int ret; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_UINT32, + &id, + DBUS_TYPE_INVALID)) + { + DebugF (MALFORMED_MSG ": %s, %s", error->name, error->message); + return BadValue; + } + + ret = dmxRemoveInput (id); + if (ret != Success) + { + DebugF ("[dmx/dbus] dmxRemoveInput failed\n"); + return ret; + } + + return Success; +} + +static int +list_screens (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DBusMessageIter iter, subiter; + int screen; + + dbus_message_iter_init_append (reply, &iter); + + for (screen = 0; screen < dmxGetNumScreens (); screen++) + { + DMXScreenAttributesRec attribs; + + dmxGetScreenAttributes (screen, &attribs); + + if (!attribs.name || !*attribs.name) + continue; + + if (!dbus_message_iter_open_container (&iter, + DBUS_TYPE_STRUCT, + NULL, + &subiter)) + { + ErrorF ("[dmx/dbus] couldn't init container\n"); + return BadAlloc; + } + + if (!dbus_message_iter_append_basic (&subiter, + DBUS_TYPE_UINT32, + &screen)) + { + ErrorF ("[dmx/dbus] couldn't append to iterator\n"); + return BadAlloc; + } + + if (!dbus_message_iter_append_basic (&subiter, + DBUS_TYPE_STRING, + &attribs.name)) + { + ErrorF("[dmx/dbus] couldn't append to iterator\n"); + return BadAlloc; + } + + if (!dbus_message_iter_close_container (&iter, &subiter)) + { + ErrorF ("[dmx/dbus] couldn't close container\n"); + return BadAlloc; + } + } + + return Success; +} + +static int +get_version (DBusMessage *message, + DBusMessage *reply, + DBusError *error) +{ + DBusMessageIter iter; + unsigned int version = API_VERSION; + + dbus_message_iter_init_append (reply, &iter); + + if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &version)) + { + ErrorF ("[dmx/dbus] couldn't append version\n"); + return BadAlloc; + } + + return Success; +} + +static DBusHandlerResult +message_handler (DBusConnection *connection, + DBusMessage *message, + void *data) +{ + struct connection_info *info = data; + DBusMessage *reply; + DBusError error; + + /* ret is the overall D-Bus handler result, whereas err is the internal + * X error from our individual functions. */ + int err, ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + DebugF ("[dmx/dbus] received a message for %s\n", + dbus_message_get_interface (message)); + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + if (!reply) + { + ErrorF ("[dmx/dbus] failed to create reply\n"); + ret = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto err_start; + } + + if (strcmp (dbus_message_get_member (message), "enableScreen") == 0) + err = enable_screen (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "disableScreen") == 0) + err = disable_screen (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "attachScreen") == 0) + err = attach_screen (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "detachScreen") == 0) + err = detach_screen (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "addInput") == 0) + err = add_input (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "removeInput") == 0) + err = remove_input (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "listScreens") == 0) + err = list_screens (message, reply, &error); + else if (strcmp (dbus_message_get_member (message), "version") == 0) + err = get_version (message, reply, &error); + else + goto err_reply; + + /* Failure to allocate is a special case. */ + if (err == BadAlloc) + { + ret = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto err_reply; + } + + if (err != Success) + { + dbus_message_unref (reply); + + reply = dbus_message_new_error_printf (message, + error.name, + error.message); + + if (!reply) + { + ErrorF ("[dmx/dbus] failed to create reply\n"); + ret = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto err_start; + } + } + + /* While failure here is always an OOM, we don't return that, + * since that would result in devices being double-added/removed. */ + if (dbus_connection_send (info->connection, reply, NULL)) + dbus_connection_flush (info->connection); + else + ErrorF ("[dmx/dbus] failed to send reply\n"); + + ret = DBUS_HANDLER_RESULT_HANDLED; + +err_reply: + dbus_message_unref (reply); +err_start: + dbus_error_free (&error); + + return ret; +} + +static void +connect_hook (DBusConnection *connection, + void *data) +{ + DBusObjectPathVTable vtable = { .message_function = message_handler }; + DBusError error; + struct connection_info *info = data; + + info->connection = connection; + + dbus_error_init (&error); + + /* blocks until we get a reply. */ + dbus_bus_add_match (info->connection, MATCH_RULE, &error); + if (!dbus_error_is_set (&error)) + { + if (dbus_connection_register_object_path (info->connection, + info->busobject, + &vtable, + info)) + { + DebugF ("[dbus] registered %s, %s\n", info->busname, + info->busobject); + } + else + { + ErrorF ("[dmx/dbus] couldn't register object path\n"); + dbus_bus_remove_match (info->connection, MATCH_RULE, &error); + reset_info (info); + } + } + else + { + ErrorF ("[dmx/dbus] couldn't add match: %s (%s)\n", error.name, + error.message); + reset_info (info); + } + + dbus_error_free (&error); +} + +static void +disconnect_hook (void *data) +{ +} + +static struct connection_info connection_data; +static struct config_dbus_core_hook core_hook = { + .connect = connect_hook, + .disconnect = disconnect_hook, + .data = &connection_data +}; + +int +dmx_dbus_init (void) +{ + snprintf (connection_data.busobject, sizeof (connection_data.busobject), + "/org/x/config/dmx/%d", atoi (display)); + + return config_dbus_core_add_hook (&core_hook); +} + +void +dmx_dbus_fini (void) +{ + config_dbus_core_remove_hook (&core_hook); + reset_info (&connection_data); +} diff --git a/hw/dmx/dmxdbus.h b/hw/dmx/dmxdbus.h new file mode 100644 index 0000000..1905685 --- /dev/null +++ b/hw/dmx/dmxdbus.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2008 David Reveman + * + * 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 + * David Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * David Reveman makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DAVID REVEMAN 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMX_DBUS_H +#define DMX_DBUS_H + +#define DMX_ERROR_INVALID_SCREEN "org.x.config.dmx.InvalidScreen" +#define DMX_ERROR_SCREEN_IN_USE "org.x.config.dmx.ScreenInUse" + +#ifdef CONFIG_DBUS_API +int dmx_dbus_init (void); +void dmx_dbus_fini (void); +#endif + +#endif diff --git a/hw/dmx/dmxdnd.c b/hw/dmx/dmxdnd.c new file mode 100644 index 0000000..0841db6 --- /dev/null +++ b/hw/dmx/dmxdnd.c @@ -0,0 +1,1870 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxlog.h" +#include "dmxatom.h" +#include "dmxwindow.h" +#include "dmxscrinit.h" +#include "dmxsync.h" +#include "dmxinput.h" +#include "dmxselection.h" +#include "dmxdnd.h" + +#include "selection.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include <xcb/xinput.h> +#include <xcb/shape.h> + +struct _DMXDnDChild { + Window target; + Window wid; + BoxRec box; + RegionPtr boundingShape; + RegionPtr inputShape; + int map_state; + int version; +}; + +void +dmxBEDnDRootWindowUpdate (ScreenPtr pScreen, + Window window) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_atom_t version = 5; + + xcb_change_property (dmxScreen->connection, + XCB_PROP_MODE_REPLACE, + window, + dmxBEAtom (dmxScreen, dmxScreen->xdndAwareAtom), + XA_ATOM, + 32, + 1, + &version); + xcb_change_property (dmxScreen->connection, + XCB_PROP_MODE_REPLACE, + window, + dmxBEAtom (dmxScreen, dmxScreen->xdndProxyAtom), + XA_WINDOW, + 32, + 1, + &window); +} + +static void +dmxDnDSendDeclineStatus (void) +{ + WindowPtr pWin; + + if (!dmxScreens[0].dndWindow) + return; + + if (dixLookupWindow (&pWin, + dmxScreens[0].dndWindow, + serverClient, + DixReadAccess) == Success) + { + xEvent x; + + x.u.u.type = ClientMessage | 0x80; + x.u.u.detail = 32; + x.u.clientMessage.window = dmxScreens[0].dndWindow; + x.u.clientMessage.u.l.type = dmxScreens[0].xdndStatusAtom; + x.u.clientMessage.u.l.longs0 = dmxScreens[0].inputOverlayWid; + x.u.clientMessage.u.l.longs1 = 0; + x.u.clientMessage.u.l.longs2 = 0; + x.u.clientMessage.u.l.longs3 = 0; + x.u.clientMessage.u.l.longs4 = 0; + + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &x, + 1, + NoEventMask, + NullGrab, 0); + } +} + +static void +dmxBEDnDUpdateTarget (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window target = None; + Window wid = None; + int version = 0; + + if (!dmxScreens[0].dndWindow || !dmxScreen->dndSource) + return; + + if (dmxScreen->dndStatus) + { + int n; + + n = dmxScreen->dndNChildren; + while (n--) + { + if (dmxScreen->dndChildren[n].map_state != XCB_MAP_STATE_VIEWABLE) + continue; + + if (dmxScreen->dndChildren[n].box.x1 <= dmxScreen->dndX && + dmxScreen->dndChildren[n].box.y1 <= dmxScreen->dndY && + dmxScreen->dndChildren[n].box.x2 > dmxScreen->dndX && + dmxScreen->dndChildren[n].box.y2 > dmxScreen->dndY) + { + BoxRec box; + + if ((!dmxScreen->dndChildren[n].boundingShape || + POINT_IN_REGION (pScreen, + dmxScreen->dndChildren[n].boundingShape, + dmxScreen->dndX - + dmxScreen->dndChildren[n].box.x1, + dmxScreen->dndY - + dmxScreen->dndChildren[n].box.y1, + &box)) && + (!dmxScreen->dndChildren[n].inputShape || + POINT_IN_REGION (pScreen, + dmxScreen->dndChildren[n].inputShape, + dmxScreen->dndX - + dmxScreen->dndChildren[n].box.x1, + dmxScreen->dndY - + dmxScreen->dndChildren[n].box.y1, + &box))) + break; + } + } + + if (n >= 0 && dmxScreen->dndChildren[n].version >= 3) + { + target = dmxScreen->dndChildren[n].target; + wid = dmxScreen->dndChildren[n].wid; + version = dmxScreen->dndChildren[n].version < 5 ? + dmxScreen->dndChildren[n].version : 5; + } + } + + if (target != dmxScreen->dndTarget) + { + if (dmxScreen->dndTarget) + { + xcb_client_message_event_t xevent; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndLeaveAtom); + xevent.window = dmxScreen->dndTarget; + + xevent.data.data32[0] = dmxScreen->dndSource; + xevent.data.data32[1] = 0; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndWid, + 0, + (const char *) &xevent); + } + + if (target) + { + xcb_client_message_event_t xevent; + int i; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndEnterAtom); + xevent.window = target; + + xevent.data.data32[0] = dmxScreen->dndSource; + xevent.data.data32[1] = version << 24; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + if (dmxScreen->dndHasTypeProp) + xevent.data.data32[1] |= 1; + + for (i = 0; i < 3; i++) + if (ValidAtom (dmxScreen->dndType[i])) + xevent.data.data32[i + 2] = + dmxBEAtom (dmxScreen, dmxScreen->dndType[i]); + + xcb_send_event (dmxScreen->connection, + FALSE, + wid, + 0, + (const char *) &xevent); + + dmxScreen->dndXPos = -1; + dmxScreen->dndYPos = -1; + } + else if (dmxScreen->dndStatus) + { + dmxDnDSendDeclineStatus (); + } + + dmxScreen->dndTarget = target; + dmxScreen->dndWid = wid; + } + + if (dmxScreen->dndTarget) + { + if (dmxScreen->dndX != dmxScreen->dndXPos || + dmxScreen->dndY != dmxScreen->dndYPos) + { + xcb_client_message_event_t xevent; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndPositionAtom); + xevent.window = dmxScreen->dndTarget; + + xevent.data.data32[0] = dmxScreen->dndSource; + xevent.data.data32[1] = 0; + xevent.data.data32[2] = (dmxScreen->dndX << 16) | dmxScreen->dndY; + xevent.data.data32[3] = 0; /* XXX: need time stamp */ + xevent.data.data32[4] = dmxBEAtom (dmxScreen, + dmxScreen->dndAction); + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndWid, + 0, + (const char *) &xevent); + + dmxScreen->dndXPos = dmxScreen->dndX; + dmxScreen->dndYPos = dmxScreen->dndY; + } + } +} + +static void +dmxDnDAwarePropertyReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 32) + { + uint32_t *data = xcb_get_property_value (xproperty); + int length = xcb_get_property_value_length (xproperty); + + if (length) + dmxScreen->dndChildren[n].version = *data; + } + } +} + +static void +dmxDnDProxyPropertyReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 32) + { + uint32_t *data = xcb_get_property_value (xproperty); + int length = xcb_get_property_value_length (xproperty); + + if (length) + { + xcb_get_property_cookie_t prop; + + dmxScreen->dndChildren[n].wid = *data; + + /* ignore previous xdndAware property reply */ + dmxScreen->dndChildren[n].version = 0; + + prop = xcb_get_property (dmxScreen->connection, + xFalse, + dmxScreen->dndChildren[n].wid, + dmxBEAtom (dmxScreen, + dmxScreen->xdndAwareAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 1); + dmxAddRequest (&dmxScreen->request, + dmxDnDAwarePropertyReply, + prop.sequence, + (void *) n); + } + } + } +} + +static void +dmxDnDGeometryReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + xcb_get_geometry_reply_t *xgeometry = + (xcb_get_geometry_reply_t *) reply; + + dmxScreen->dndChildren[n].box.x1 = xgeometry->x; + dmxScreen->dndChildren[n].box.y1 = xgeometry->y; + dmxScreen->dndChildren[n].box.x2 = xgeometry->x + xgeometry->width; + dmxScreen->dndChildren[n].box.y2 = xgeometry->y + xgeometry->height; + } +} + +typedef struct dmx_xcb_shape_get_rectangles_reply_t { + uint8_t response_type; + uint8_t ordering; + uint16_t sequence; + uint32_t length; + uint32_t rectangles_len; + uint32_t pad1; + uint32_t pad2; + uint32_t pad3; + uint32_t pad4; + uint32_t pad5; +} dmx_xcb_shape_get_rectangles_reply_t; + +static void +dmxDnDBoundingShapeReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + RegionPtr pRegion; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + dmx_xcb_shape_get_rectangles_reply_t *xshape = + (dmx_xcb_shape_get_rectangles_reply_t *) reply; + + pRegion = RECTS_TO_REGION (pScreen, + xshape->rectangles_len, + (xRectangle *) (xshape + 1), + xshape->ordering); + + if (dmxScreen->dndChildren[n].boundingShape) + REGION_DESTROY (pScreen, dmxScreen->dndChildren[n].boundingShape); + + dmxScreen->dndChildren[n].boundingShape = pRegion; + } +} + +static void +dmxDnDInputShapeReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + RegionPtr pRegion; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + dmx_xcb_shape_get_rectangles_reply_t *xshape = + (dmx_xcb_shape_get_rectangles_reply_t *) reply; + + pRegion = RECTS_TO_REGION (pScreen, + xshape->rectangles_len, + (xRectangle *) (xshape + 1), + xshape->ordering); + + if (dmxScreen->dndChildren[n].inputShape) + REGION_DESTROY (pScreen, dmxScreen->dndChildren[n].inputShape); + + dmxScreen->dndChildren[n].inputShape = pRegion; + } +} + +static void +dmxDnDBoundingShapeUpdateReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + dmxDnDBoundingShapeReply (pScreen, sequence, reply, error, data); + dmxBEDnDUpdateTarget (pScreen); +} + +static void +dmxDnDInputShapeUpdateReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + dmxDnDInputShapeReply (pScreen, sequence, reply, error, data); + dmxBEDnDUpdateTarget (pScreen); +} + +static void +dmxDnDWindowAttributesReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + xcb_get_window_attributes_reply_t *xattrib = + (xcb_get_window_attributes_reply_t *) reply; + + dmxScreen->dndChildren[n].map_state = xattrib->map_state; + + if (xattrib->map_state == XCB_MAP_STATE_VIEWABLE) + dmxBEDnDUpdateTarget (pScreen); + } +} + +/* XXX: back-end server DND target lookup method is efficient but + doesn't support reparenting window managers */ +static void +dmxDnDQueryTreeReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (sequence != dmxScreen->queryTree.sequence) + return; + + assert (!dmxScreen->dndChildren); + + if (reply) + { + xcb_query_tree_reply_t *xquery = (xcb_query_tree_reply_t *) reply; + DMXDnDChild *children; + xcb_window_t *c; + int n; + + c = xcb_query_tree_children (xquery); + n = xcb_query_tree_children_length (xquery); + + children = xalloc (n * sizeof (DMXDnDChild)); + if (!children) + return; + + dmxScreen->dndChildren = children; + dmxScreen->dndNChildren = n; + + while (n--) + { + xcb_get_property_cookie_t prop; + xcb_get_geometry_cookie_t geometry; + xcb_shape_get_rectangles_cookie_t shape; + xcb_get_window_attributes_cookie_t attr; + + children[n].box.x1 = 0; + children[n].box.y1 = 0; + children[n].box.x2 = 0; + children[n].box.y2 = 0; + children[n].boundingShape = NULL; + children[n].inputShape = NULL; + children[n].version = 0; + children[n].target = c[n]; + children[n].wid = c[n]; + + prop = xcb_get_property (dmxScreen->connection, + xFalse, + c[n], + dmxBEAtom (dmxScreen, + dmxScreen->xdndAwareAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 1); + dmxAddRequest (&dmxScreen->request, + dmxDnDAwarePropertyReply, + prop.sequence, + (void *) n); + + prop = xcb_get_property (dmxScreen->connection, + xFalse, + c[n], + dmxBEAtom (dmxScreen, + dmxScreen->xdndProxyAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 1); + dmxAddRequest (&dmxScreen->request, + dmxDnDProxyPropertyReply, + prop.sequence, + (void *) n); + + geometry = xcb_get_geometry (dmxScreen->connection, c[n]); + dmxAddRequest (&dmxScreen->request, + dmxDnDGeometryReply, + geometry.sequence, + (void *) n); + + xcb_shape_select_input (dmxScreen->connection, c[n], 1); + + shape = xcb_shape_get_rectangles (dmxScreen->connection, c[n], + ShapeBounding); + dmxAddRequest (&dmxScreen->request, + dmxDnDBoundingShapeReply, + shape.sequence, + (void *) n); + + shape = xcb_shape_get_rectangles (dmxScreen->connection, c[n], + ShapeInput); + dmxAddRequest (&dmxScreen->request, + dmxDnDInputShapeReply, + shape.sequence, + (void *) n); + + attr = xcb_get_window_attributes (dmxScreen->connection, c[n]); + dmxAddRequest (&dmxScreen->request, + dmxDnDWindowAttributesReply, + attr.sequence, + (void *) n); + } + } +} + +static void +dmxBEDnDUpdatePosition (ScreenPtr pScreen, + int x, + int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int i; + + for (i = 0; i < dmxNumScreens; i++) + dmxScreens[i].dndStatus = 0; + + dmxScreen->dndX = x; + dmxScreen->dndY = y; + dmxScreen->dndStatus = 1; + + if (!dmxScreen->dndChildren) + { + if (!dmxScreen->queryTree.sequence) + { + Window root = DefaultRootWindow (dmxScreen->beDisplay); + + XSelectInput (dmxScreen->beDisplay, root, + dmxScreen->scrnEventMask | + StructureNotifyMask | SubstructureNotifyMask); + + dmxScreen->queryTree = xcb_query_tree (dmxScreen->connection, + root); + dmxAddRequest (&dmxScreen->request, + dmxDnDQueryTreeReply, + dmxScreen->queryTree.sequence, + 0); + } + } + + for (i = 0; i < dmxNumScreens; i++) + dmxBEDnDUpdateTarget (screenInfo.screens[i]); +} + +static void +dmxDnDFreeChildren (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->dndChildren) + { + int i; + + for (i = 0; i < dmxScreen->dndNChildren; i++) + { + if (dmxScreen->dndChildren[i].boundingShape) + REGION_DESTROY (pScreen, + dmxScreen->dndChildren[i].boundingShape); + + if (dmxScreen->dndChildren[i].inputShape) + REGION_DESTROY (pScreen, + dmxScreen->dndChildren[i].inputShape); + + xcb_shape_select_input (dmxScreen->connection, + dmxScreen->dndChildren[i].target, + 0); + } + + xfree (dmxScreen->dndChildren); + + dmxScreen->dndChildren = NULL; + dmxScreen->dndNChildren = 0; + } +} + +static void +dmxBEDnDHideProxyWindow (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pProxyWin = dmxScreen->pInputOverlayWin; + + if (!pProxyWin->mapped) + return; + + dmxScreen->dndStatus = 0; + dmxBEDnDUpdateTarget (pScreen); + + UnmapWindow (pProxyWin, FALSE); + + if (dmxScreen->dndChildren || dmxScreen->queryTree.sequence) + XSelectInput (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay), + dmxScreen->scrnEventMask); + + dmxDnDFreeChildren (pScreen); + + dmxScreen->dndSource = None; + dmxScreen->queryTree.sequence = 0; +} + +void +dmxBEDnDSpriteUpdate (ScreenPtr pScreen, + Window event, + int rootX, + int rootY) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pProxyWin = dmxScreen->pInputOverlayWin; + + if (event != dmxScreen->rootWin) + { + if (!pProxyWin->mapped) + { + Selection *pSel; + XID vlist[5]; + + if (dixLookupSelection (&pSel, + dmxScreen->xdndSelectionAtom, + serverClient, + DixReadAccess) != Success) + return; + + if (!pSel->window) + return; + + vlist[0] = 0; + vlist[1] = 0; + vlist[2] = WindowTable[pScreen->myNum]->drawable.width; + vlist[3] = WindowTable[pScreen->myNum]->drawable.height; + vlist[4] = Above; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int j; + + FOR_NSCREENS_BACKWARD(j) { + ConfigureWindow (dmxScreens[j].pInputOverlayWin, + CWX | CWY | CWWidth | CWHeight | + CWStackMode, + vlist, + serverClient); + MapWindow (dmxScreens[j].pInputOverlayWin, serverClient); + + dmxScreens[j].dndSource = None; + dmxScreens[j].dndTarget = None; + } + } + else +#endif + + { + ConfigureWindow (pProxyWin, + CWX | CWY | CWWidth | CWHeight | CWStackMode, + vlist, + serverClient); + MapWindow (pProxyWin, serverClient); + + dmxScreen->dndSource = None; + dmxScreen->dndTarget = None; + } + } + + dmxBEDnDUpdatePosition (pScreen, rootX, rootY); + } + else + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int j; + + FOR_NSCREENS_BACKWARD(j) { + dmxBEDnDHideProxyWindow (screenInfo.screens[j]); + } + } + else +#endif + + dmxBEDnDHideProxyWindow (pScreen); + } +} + +static void +dmxDnDUpdatePosition (DMXScreenInfo *dmxScreen, + WindowPtr pWin, + int x, + int y) +{ + WindowPtr pDst = NullWindow; + BoxRec box; + XID targetId = None; + xEvent event; + int version = 0; + + event.u.u.type = ClientMessage | 0x80; + event.u.u.detail = 32; + + event.u.clientMessage.u.l.longs0 = dmxScreens[0].inputOverlayWid; + + if (pWin) + { + if (!dmxFakeMotion (&dmxScreen->input, x, y)) + pWin = NullWindow; + } + else + { + dmxEndFakeMotion (&dmxScreen->input); + } + + while (pWin) + { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int) pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int) pWin->drawable.height + + wBorderWidth (pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape (pWin) || + POINT_IN_REGION (pWin->drawable.pScreen, + &pWin->borderSize, x, y, &box)) + + && (!wInputShape (pWin) || + POINT_IN_REGION (pWin->drawable.pScreen, + wInputShape (pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + { + WindowPtr pProxy = NullWindow; + PropertyPtr pProp; + + if (dixLookupProperty (&pProp, + pWin, + dmxScreen->xdndProxyAtom, + serverClient, + DixReadAccess) == Success) + { + if (pProp->format == 32 && pProp->size == 1) + dixLookupWindow (&pProxy, + *((XID *) pProp->data), + serverClient, + DixReadAccess); + } + + if (dixLookupProperty (&pProp, + pProxy ? pProxy : pWin, + dmxScreen->xdndAwareAtom, + serverClient, + DixReadAccess) == Success) + { + if (pProp->format == 32 && pProp->size == 1) + { + Atom v; + + v = *((Atom *) pProp->data); + if (v >= 3) + { + pDst = pProxy ? pProxy : pWin; + targetId = pWin->drawable.id; + version = v; + if (version > 5) + version = 5; + } + } + } + + if (dixLookupProperty (&pProp, + pWin, + dmxScreen->wmStateAtom, + serverClient, + DixReadAccess) == Success) + break; + + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + + if (dmxScreen->dndTarget != targetId) + { + if (dmxScreen->dndWindow) + { + event.u.clientMessage.window = dmxScreen->dndTarget; + event.u.clientMessage.u.l.type = dmxScreen->xdndLeaveAtom; + + event.u.clientMessage.u.l.longs1 = 0; + event.u.clientMessage.u.l.longs2 = 0; + event.u.clientMessage.u.l.longs3 = 0; + event.u.clientMessage.u.l.longs4 = 0; + + if (dixLookupWindow (&pWin, + dmxScreen->dndWindow, + serverClient, + DixReadAccess) == Success) + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &event, + 1, + NoEventMask, + NullGrab, 0); + + dmxScreen->dndStatus = 0; + dmxScreen->dndTarget = None; + dmxScreen->dndWindow = None; + } + + if (pDst) + { + event.u.clientMessage.window = targetId; + event.u.clientMessage.u.l.type = dmxScreen->xdndEnterAtom; + + event.u.clientMessage.u.l.longs1 = version << 24; + event.u.clientMessage.u.l.longs2 = dmxScreen->dndType[0]; + event.u.clientMessage.u.l.longs3 = dmxScreen->dndType[1]; + event.u.clientMessage.u.l.longs4 = dmxScreen->dndType[2]; + + if (dmxScreen->dndHasTypeProp) + event.u.clientMessage.u.l.longs1 |= 1; + + DeliverEventsToWindow (PickPointer (serverClient), + pDst, + &event, + 1, + NoEventMask, + NullGrab, 0); + + dmxScreen->dndStatus = 0; + dmxScreen->dndWindow = pDst->drawable.id; + dmxScreen->dndTarget = targetId; + dmxScreen->dndXPos = -1; + dmxScreen->dndYPos = -1; + dmxScreen->dndAcceptedAction = None; + dmxScreen->dndVersion = version; + + REGION_EMPTY (pScreen, &dmxScreen->dndBox); + } + } + + if (pDst && !POINT_IN_REGION (pScreen, + &dmxScreen->dndBox, + x, y, &box)) + { + event.u.clientMessage.window = dmxScreen->dndTarget; + event.u.clientMessage.u.l.type = dmxScreen->xdndPositionAtom; + + event.u.clientMessage.u.l.longs1 = 0; + event.u.clientMessage.u.l.longs2 = (x << 16) | y; + event.u.clientMessage.u.l.longs3 = currentTime.milliseconds; + event.u.clientMessage.u.l.longs4 = dmxScreen->dndAction; + + DeliverEventsToWindow (PickPointer (serverClient), + pDst, + &event, + 1, + NoEventMask, + NullGrab, 0); + + dmxScreen->dndXPos = x; + dmxScreen->dndYPos = y; + + box.x1 = SHRT_MIN; + box.y1 = SHRT_MIN; + box.x2 = SHRT_MAX; + box.y2 = SHRT_MAX; + + REGION_RESET (pScreen, &dmxScreen->dndBox, &box); + } +} + +static void +dmxDnDTranslateCoordinatesReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply) + { + xcb_translate_coordinates_reply_t *xcoord = + (xcb_translate_coordinates_reply_t *) reply; + + dmxScreen->dndX = xcoord->dst_x; + dmxScreen->dndY = xcoord->dst_y; + + if (dmxScreen->dndSource) + { + WindowPtr pWin = WindowTable[pScreen->myNum]; + xcb_client_message_event_t xevent; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pWin = WindowTable[0]; +#endif + + if (!dmxScreen->getTypeProp.sequence) + dmxDnDUpdatePosition (dmxScreen, + pWin, + dmxScreen->dndX, + dmxScreen->dndY); + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndStatusAtom); + xevent.window = dmxScreen->dndSource; + + xevent.data.data32[0] = dmxScreen->dndWid; + xevent.data.data32[1] = dmxScreen->dndStatus; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + if (ValidAtom (dmxScreen->dndAcceptedAction)) + xevent.data.data32[4] = + dmxBEAtom (dmxScreen, dmxScreen->dndAcceptedAction); + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndSource, + 0, + (const char *) &xevent); + } + } +} + +static void +dmxDnDGetTypePropReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 32 && + dmxAtom (dmxScreen, xproperty->type) == XA_ATOM) + { + uint32_t *data = xcb_get_property_value (xproperty); + int i; + + for (i = 0; i < xcb_get_property_value_length (xproperty); i++) + data[i] = dmxAtom (dmxScreen, data[i]); + + ChangeWindowProperty (dmxScreens[0].pInputOverlayWin, + dmxScreen->xdndTypeListAtom, + XA_ATOM, + 32, + PropModeReplace, + xcb_get_property_value_length (xproperty), + data, + TRUE); + + dmxScreen->dndHasTypeProp = TRUE; + } + + if (dmxScreen->dndX != -1 && dmxScreen->dndY != -1) + { + WindowPtr pWin = WindowTable[pScreen->myNum]; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pWin = WindowTable[0]; +#endif + + dmxDnDUpdatePosition (dmxScreen, + pWin, + dmxScreen->dndX, + dmxScreen->dndY); + } + } + + dmxScreen->getTypeProp.sequence = 0; +} + +static void +dmxDnDGetActionListPropReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 32 && + dmxAtom (dmxScreen, xproperty->type) == XA_ATOM) + { + uint32_t *data = xcb_get_property_value (xproperty); + int i; + + for (i = 0; i < xcb_get_property_value_length (xproperty); i++) + data[i] = dmxAtom (dmxScreen, data[i]); + + ChangeWindowProperty (dmxScreens[0].pInputOverlayWin, + dmxScreen->xdndActionListAtom, + XA_ATOM, + 32, + PropModeReplace, + xcb_get_property_value_length (xproperty), + data, + TRUE); + } + } + + dmxScreen->getActionListProp.sequence = 0; +} + +static void +dmxDnDGetActionDescriptionPropReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 8 && + dmxAtom (dmxScreen, xproperty->type) == XA_STRING) + { + ChangeWindowProperty (dmxScreens[0].pInputOverlayWin, + dmxScreen->xdndActionDescriptionAtom, + XA_STRING, + 8, + PropModeReplace, + xcb_get_property_value_length (xproperty), + xcb_get_property_value (xproperty), + TRUE); + } + } + + dmxScreen->getActionDescriptionProp.sequence = 0; +} + +static void +dmxDnDPositionMessage (ScreenPtr pScreen, + Window source, + int xRoot, + int yRoot, + Time time, + Atom action) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (action) + dmxScreen->dndAction = dmxAtom (dmxScreen, action); + + if (dmxScreen->dndAction == dmxScreen->xdndActionAskAtom) + { + dmxScreen->getActionListProp = + xcb_get_property (dmxScreen->connection, + xFalse, + source, + dmxBEAtom (dmxScreen, + dmxScreen->xdndActionListAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + dmxAddRequest (&dmxScreen->request, + dmxDnDGetActionListPropReply, + dmxScreen->getActionListProp.sequence, + 0); + + dmxScreen->getActionDescriptionProp = + xcb_get_property (dmxScreen->connection, + xFalse, + source, + dmxBEAtom (dmxScreen, + dmxScreen->xdndActionDescriptionAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + dmxAddRequest (&dmxScreen->request, + dmxDnDGetActionDescriptionPropReply, + dmxScreen->getActionDescriptionProp.sequence, + 0); + } + + dmxScreen->translateCoordinates = + xcb_translate_coordinates (dmxScreen->connection, + DefaultRootWindow (dmxScreen->beDisplay), + dmxScreen->rootWin, + xRoot, + yRoot); + dmxAddRequest (&dmxScreen->request, + dmxDnDTranslateCoordinatesReply, + dmxScreen->translateCoordinates.sequence, + 0); +} + +static void +dmxDnDEnterMessage (ScreenPtr pScreen, + Window target, + Window source, + Atom type0, + Atom type1, + Atom type2, + Bool hasTypeProp, + int version) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxScreen->dndWid = target; + dmxScreen->dndSource = source; + dmxScreen->dndAction = None; + dmxScreen->dndAcceptedAction = None; + dmxScreen->dndType[0] = type0; + dmxScreen->dndType[1] = type1; + dmxScreen->dndType[2] = type2; + dmxScreen->dndHasTypeProp = FALSE; + + if (hasTypeProp) + { + dmxScreen->getTypeProp = + xcb_get_property (dmxScreen->connection, + xFalse, + source, + dmxBEAtom (dmxScreen, + dmxScreen->xdndTypeListAtom), + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + if (dmxScreen->getTypeProp.sequence) + dmxAddRequest (&dmxScreen->request, + dmxDnDGetTypePropReply, + dmxScreen->getTypeProp.sequence, + 0); + } +} + +static void +dmxDnDLeaveMessage (ScreenPtr pScreen, + Window source) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxDnDUpdatePosition (dmxScreen, NullWindow, 0, 0); + + dmxScreen->dndWid = None; + dmxScreen->dndSource = None; + dmxScreen->dndStatus = 0; + dmxScreen->dndXPos = -1; + dmxScreen->dndYPos = -1; + dmxScreen->dndX = -1; + dmxScreen->dndY = -1; +} + +static void +dmxDnDDropMessage (ScreenPtr pScreen, + Window source, + Time time) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxEndFakeMotion (&dmxScreen->input); + + if (dmxScreen->dndWindow) + { + WindowPtr pWin; + xEvent event; + BoxRec box; + + event.u.u.type = ClientMessage | 0x80; + event.u.u.detail = 32; + + event.u.clientMessage.window = dmxScreen->dndTarget; + event.u.clientMessage.u.l.type = dmxScreen->xdndDropAtom; + + event.u.clientMessage.u.l.longs0 = dmxScreens[0].inputOverlayWid; + event.u.clientMessage.u.l.longs1 = 0; + event.u.clientMessage.u.l.longs2 = currentTime.milliseconds; + event.u.clientMessage.u.l.longs3 = 0; + event.u.clientMessage.u.l.longs4 = 0; + + if (dixLookupWindow (&pWin, + dmxScreen->dndWindow, + serverClient, + DixReadAccess) == Success) + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &event, + 1, + NoEventMask, + NullGrab, 0); + + box.x1 = SHRT_MIN; + box.y1 = SHRT_MIN; + box.x2 = SHRT_MAX; + box.y2 = SHRT_MAX; + + REGION_RESET (pScreen, &dmxScreen->dndBox, &box); + } + else + { + xcb_client_message_event_t xevent; + + dmxDnDLeaveMessage (pScreen, source); + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndFinishedAtom); + xevent.window = dmxScreen->dndSource; + + xevent.data.data32[0] = dmxScreen->dndWid; + xevent.data.data32[1] = 0; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndSource, + 0, + (const char *) &xevent); + + dmxScreen->dndWid = None; + dmxScreen->dndSource = None; + } +} + +static void +dmxDnDStatusMessage (ScreenPtr pScreen, + Window target, + int status, + Atom action) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pWin; + + if (!dmxScreens[0].dndWindow) + return; + + if (!dmxScreen->dndStatus) + return; + + if (target != dmxScreen->dndTarget) + return; + + if (dixLookupWindow (&pWin, + dmxScreens[0].dndWindow, + serverClient, + DixReadAccess) == Success) + { + xEvent x; + + x.u.u.type = ClientMessage | 0x80; + x.u.u.detail = 32; + x.u.clientMessage.window = dmxScreens[0].dndWindow; + x.u.clientMessage.u.l.type = dmxScreens[0].xdndStatusAtom; + x.u.clientMessage.u.l.longs0 = dmxScreens[0].inputOverlayWid; + x.u.clientMessage.u.l.longs1 = 0; + x.u.clientMessage.u.l.longs2 = 0; + x.u.clientMessage.u.l.longs3 = 0; + x.u.clientMessage.u.l.longs4 = 0; + + if (status) + { + x.u.clientMessage.u.l.longs1 = 1; + x.u.clientMessage.u.l.longs4 = dmxAtom (dmxScreen, action); + } + + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &x, + 1, + NoEventMask, + NullGrab, 0); + } +} + +static void +dmxDnDFinishedMessage (ScreenPtr pScreen, + Window target, + int status, + Atom action) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pWin; + + if (!dmxScreens[0].dndWindow) + return; + + if (target != dmxScreen->dndTarget) + return; + + if (dixLookupWindow (&pWin, + dmxScreens[0].dndWindow, + serverClient, + DixReadAccess) == Success) + { + xEvent x; + + x.u.u.type = ClientMessage | 0x80; + x.u.u.detail = 32; + x.u.clientMessage.window = dmxScreens[0].dndWindow; + x.u.clientMessage.u.l.type = dmxScreens[0].xdndFinishedAtom; + x.u.clientMessage.u.l.longs0 = dmxScreens[0].inputOverlayWid; + x.u.clientMessage.u.l.longs1 = 0; + x.u.clientMessage.u.l.longs2 = 0; + x.u.clientMessage.u.l.longs3 = 0; + x.u.clientMessage.u.l.longs4 = 0; + + if (status) + { + x.u.clientMessage.u.l.longs1 = 1; + x.u.clientMessage.u.l.longs2 = dmxAtom (dmxScreen, action); + } + + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &x, + 1, + NoEventMask, + NullGrab, 0); + } +} + +Bool +dmxScreenEventCheckDnD (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_map_notify_event_t *xmap = (xcb_map_notify_event_t *) event; + int reltype, type = event->response_type & 0x7f; + + switch (type) { + case XCB_MAP_NOTIFY: + if (xmap->window == dmxScreen->rootWin) + return FALSE; + + /* fall-through */ + case XCB_UNMAP_NOTIFY: + case XCB_CONFIGURE_NOTIFY: + if (xmap->event != DefaultRootWindow (dmxScreen->beDisplay)) + return FALSE; + + dmxDnDFreeChildren (pScreen); + + dmxScreen->queryTree.sequence = 0; + + if (dmxScreen->dndStatus) + dmxBEDnDUpdatePosition (pScreen, dmxScreen->dndX, dmxScreen->dndY); + break; + case XCB_CLIENT_MESSAGE: { + xcb_client_message_event_t *xclient = + (xcb_client_message_event_t *) event; + xcb_atom_t type = xclient->type; + + if (dmxAtom (dmxScreen, type) == dmxScreen->xdndPositionAtom) + { + dmxDnDPositionMessage (pScreen, + xclient->data.data32[0], + xclient->data.data32[2] >> 16, + xclient->data.data32[2] & 0xffff, + xclient->data.data32[3], + xclient->data.data32[4]); + } + else if (dmxAtom (dmxScreen, type) == dmxScreen->xdndEnterAtom) + { + dmxDnDEnterMessage (pScreen, + xclient->window, + xclient->data.data32[0], + xclient->data.data32[2], + xclient->data.data32[3], + xclient->data.data32[4], + ((xclient->data.data32[1] & 1) != 0), + (xclient->data.data32[1] & 0xff000000) >> 24); + } + else if (dmxAtom (dmxScreen, type) == dmxScreen->xdndLeaveAtom) + { + dmxDnDLeaveMessage (pScreen, xclient->data.data32[0]); + } + else if (dmxAtom (dmxScreen, type) == dmxScreen->xdndDropAtom) + { + dmxDnDDropMessage (pScreen, + xclient->data.data32[0], + xclient->data.data32[2]); + } + else if (dmxAtom (dmxScreen, type) == dmxScreen->xdndStatusAtom) + { + dmxDnDStatusMessage (pScreen, + xclient->data.data32[0], + ((xclient->data.data32[1] & 1) != 0), + xclient->data.data32[4]); + } + else if (dmxAtom (dmxScreen, type) == dmxScreen->xdndFinishedAtom) + { + dmxDnDFinishedMessage (pScreen, + xclient->data.data32[0], + ((xclient->data.data32[1] & 1) != 0), + xclient->data.data32[2]); + } + else + { + return FALSE; + } + } break; + default: + reltype = type - dmxScreen->beShapeEventBase; + + switch (reltype) { + case XCB_SHAPE_NOTIFY: { + xcb_shape_notify_event_t *xshape = + (xcb_shape_notify_event_t *) event; + int i; + + for (i = 0; i < dmxScreen->dndNChildren; i++) + if (dmxScreen->dndChildren[i].target == xshape->affected_window) + break; + + if (i < dmxScreen->dndNChildren) + { + xcb_shape_get_rectangles_cookie_t shape; + + switch (xshape->shape_kind) { + case ShapeBounding: + shape = xcb_shape_get_rectangles (dmxScreen->connection, + xshape->affected_window, + ShapeBounding); + dmxAddRequest (&dmxScreen->request, + dmxDnDBoundingShapeUpdateReply, + shape.sequence, + (void *) i); + + case ShapeInput: + shape = xcb_shape_get_rectangles (dmxScreen->connection, + xshape->affected_window, + ShapeInput); + dmxAddRequest (&dmxScreen->request, + dmxDnDInputShapeUpdateReply, + shape.sequence, + (void *) i); + default: + break; + } + } + else + { + return FALSE; + } + } break; + default: + return FALSE; + } + } + + return TRUE; +} + +void +dmxDnDClientMessageEvent (xEvent *event) +{ + Atom type = event->u.clientMessage.u.l.type; + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (type == dmxScreens[0].xdndStatusAtom) + { + int dndStatus = event->u.clientMessage.u.l.longs1 & 1; + Atom dndAcceptedAction = event->u.clientMessage.u.l.longs4; + + if (!dmxScreen->dndSource) + continue; + + if (event->u.clientMessage.u.l.longs0 != dmxScreen->dndTarget) + continue; + + if (dmxScreen->dndStatus != dndStatus || + dmxScreen->dndAcceptedAction != dndAcceptedAction) + { + xcb_client_message_event_t xevent; + + dmxScreen->dndStatus = dndStatus; + dmxScreen->dndAcceptedAction = dndAcceptedAction; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, + dmxScreen->xdndStatusAtom); + xevent.window = dmxScreen->dndSource; + + xevent.data.data32[0] = dmxScreen->dndWid; + xevent.data.data32[1] = dmxScreen->dndStatus; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + if (ValidAtom (dmxScreen->dndAcceptedAction)) + xevent.data.data32[4] = + dmxBEAtom (dmxScreen, + dmxScreen->dndAcceptedAction); + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndSource, + 0, + (const char *) &xevent); + } + + REGION_EMPTY (pScreen, &dmxScreen->dndBox); + + if (dmxScreen->dndStatus & 2) + { + BoxRec box; + + box.x1 = event->u.clientMessage.u.l.longs2 >> 16; + box.y1 = event->u.clientMessage.u.l.longs2 & 0xffff; + box.x2 = box.x1 + + (event->u.clientMessage.u.l.longs3 >> 16); + box.y2 = box.y1 + + (event->u.clientMessage.u.l.longs3 & 0xffff); + + REGION_RESET (pScreen, &dmxScreen->dndBox, &box); + } + + if (dmxScreen->dndX != dmxScreen->dndXPos || + dmxScreen->dndY != dmxScreen->dndYPos) + { + WindowPtr pWin = WindowTable[i]; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pWin = WindowTable[0]; +#endif + + dmxDnDUpdatePosition (dmxScreen, + pWin, + dmxScreen->dndX, + dmxScreen->dndY); + } + } + else if (type == dmxScreen->xdndFinishedAtom) + { + xcb_client_message_event_t xevent; + + if (!dmxScreen->dndSource) + continue; + + if (event->u.clientMessage.u.l.longs0 != dmxScreen->dndTarget) + continue; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, dmxScreen->xdndFinishedAtom); + xevent.window = dmxScreen->dndSource; + + xevent.data.data32[0] = dmxScreen->dndWid; + xevent.data.data32[1] = 0; + xevent.data.data32[2] = 0; + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + if (dmxScreen->dndVersion >= 5) + { + xevent.data.data32[1] = event->u.clientMessage.u.l.longs1 & 1; + xevent.data.data32[2] = event->u.clientMessage.u.l.longs2; + } + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndSource, + 0, + (const char *) &xevent); + + dmxScreen->dndTarget = None; + dmxScreen->dndWindow = None; + + dmxDnDLeaveMessage (screenInfo.screens[i], dmxScreen->dndSource); + + dmxScreen->dndWid = None; + dmxScreen->dndSource = None; + } + else if (type == dmxScreen->xdndEnterAtom) + { + dmxScreen->dndAction = None; + dmxScreen->dndType[0] = event->u.clientMessage.u.l.longs2; + dmxScreen->dndType[1] = event->u.clientMessage.u.l.longs3; + dmxScreen->dndType[2] = event->u.clientMessage.u.l.longs4; + dmxScreen->dndHasTypeProp = + ((event->u.clientMessage.u.l.longs1 & 1) != 0); + } + else if (type == dmxScreen->xdndLeaveAtom) + { + dmxBEDnDHideProxyWindow (screenInfo.screens[i]); + } + else if (type == dmxScreen->xdndPositionAtom) + { + WindowPtr pWin = NullWindow; + Window dndSource = dmxScreen->dndSource; + +#ifdef PANORAMIX + PanoramiXRes *win = NULL; + + if (!noPanoramiXExtension) + { + win = (PanoramiXRes *) + SecurityLookupIDByType (serverClient, + event->u.clientMessage.u.l.longs0, + XRT_WINDOW, + DixReadAccess); + if (win) + dixLookupWindow (&pWin, win->info[i].id, + serverClient, DixReadAccess); + } + else +#endif + dixLookupWindow (&pWin, event->u.clientMessage.u.l.longs0, + serverClient, DixReadAccess); + + if (pWin) + dmxScreen->dndSource = DMX_GET_WINDOW_PRIV (pWin)->window; + + dmxScreen->dndWindow = event->u.clientMessage.u.l.longs0; + dmxScreen->dndAction = event->u.clientMessage.u.l.longs4; + dmxScreen->dndXPos = -1; + dmxScreen->dndXPos = -1; + + if (dmxScreen->dndStatus) + { + if (dmxScreen->dndSource != dndSource) + dmxDnDSendDeclineStatus (); + + dmxBEDnDUpdatePosition (screenInfo.screens[i], + dmxScreen->dndX, + dmxScreen->dndY); + } + } + else if (type == dmxScreen->xdndDropAtom) + { + Window target = None; + int status = 0; + + if (dmxScreen->dndStatus) + { + if (dmxScreen->dndTarget) + { + xcb_client_message_event_t xevent; + + xevent.response_type = XCB_CLIENT_MESSAGE; + xevent.format = 32; + + xevent.type = dmxBEAtom (dmxScreen, + dmxScreen->xdndDropAtom); + xevent.window = dmxScreen->dndTarget; + + xevent.data.data32[0] = dmxScreen->dndSource; + xevent.data.data32[1] = 0; + xevent.data.data32[2] = 0; /* XXX: need time stamp */ + xevent.data.data32[3] = 0; + xevent.data.data32[4] = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + dmxScreen->dndWid, + 0, + (const char *) &xevent); + + status = 1; + target = dmxScreen->dndTarget; + + dmxScreen->dndTarget = None; + } + else + { + WindowPtr pWin; + xEvent x; + + x.u.u.type = ClientMessage | 0x80; + x.u.u.detail = 32; + x.u.clientMessage.window = dmxScreens[0].dndWindow; + x.u.clientMessage.u.l.type = + dmxScreens[0].xdndFinishedAtom; + x.u.clientMessage.u.l.longs0 = + dmxScreens[0].inputOverlayWid; + x.u.clientMessage.u.l.longs1 = 0; + x.u.clientMessage.u.l.longs2 = 0; + x.u.clientMessage.u.l.longs3 = 0; + x.u.clientMessage.u.l.longs4 = 0; + + if (dixLookupWindow (&pWin, + dmxScreens[0].dndWindow, + serverClient, + DixReadAccess) == Success) + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &x, + 1, + NoEventMask, + NullGrab, 0); + } + } + + dmxBEDnDHideProxyWindow (screenInfo.screens[i]); + + dmxScreen->dndTarget = target; + dmxScreen->dndStatus = status; + } + } +} + +#define MAKE_DND_ATOM(name) \ + MakeAtom ("Xdnd" name, strlen ("Xdnd" name), TRUE) + +Bool +dmxDnDScreenInit (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxScreen->wmStateAtom = MakeAtom ("WM_STATE", strlen ("WM_STATE"), TRUE); + + dmxScreen->xdndProxyAtom = MAKE_DND_ATOM ("Proxy"); + dmxScreen->xdndAwareAtom = MAKE_DND_ATOM ("Aware"); + dmxScreen->xdndSelectionAtom = MAKE_DND_ATOM ("Selection"); + dmxScreen->xdndEnterAtom = MAKE_DND_ATOM ("Enter"); + dmxScreen->xdndPositionAtom = MAKE_DND_ATOM ("Position"); + dmxScreen->xdndStatusAtom = MAKE_DND_ATOM ("Status"); + dmxScreen->xdndLeaveAtom = MAKE_DND_ATOM ("Leave"); + dmxScreen->xdndDropAtom = MAKE_DND_ATOM ("Drop"); + dmxScreen->xdndFinishedAtom = MAKE_DND_ATOM ("Finished"); + dmxScreen->xdndTypeListAtom = MAKE_DND_ATOM ("TypeList"); + dmxScreen->xdndActionAskAtom = MAKE_DND_ATOM ("ActionAsk"); + dmxScreen->xdndActionListAtom = MAKE_DND_ATOM ("ActionList"); + dmxScreen->xdndActionDescriptionAtom = MAKE_DND_ATOM ("ActionDescription"); + + dmxScreen->dndXPos = -1; + dmxScreen->dndYPos = -1; + + REGION_INIT (pScreen, &dmxScreen->dndBox, NullBox, 0); + + return TRUE; +} + +void +dmxDnDScreenFini (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + REGION_UNINIT (pScreen, &dmxScreen->dndBox); +} diff --git a/hw/dmx/dmxdnd.h b/hw/dmx/dmxdnd.h new file mode 100644 index 0000000..6c6d975 --- /dev/null +++ b/hw/dmx/dmxdnd.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXDND_H +#define DMXDND_H + +#include "dmx.h" + +void +dmxBEDnDRootWindowUpdate (ScreenPtr pScreen, + Window window); + +void +dmxBEDnDSpriteUpdate (ScreenPtr pScreen, + Window window, + int rootX, + int rootY); + +Bool +dmxScreenEventCheckDnD (ScreenPtr pScreen, + xcb_generic_event_t *event); + +void +dmxDnDClientMessageEvent (xEvent *event); + +Bool +dmxDnDScreenInit (ScreenPtr pScreen); + +void +dmxDnDScreenFini (ScreenPtr pScreen); + +#endif /* DMXDND_H */ diff --git a/hw/dmx/dmxdpms.c b/hw/dmx/dmxdpms.c index 2af1605..0498cf4 100644 --- a/hw/dmx/dmxdpms.c +++ b/hw/dmx/dmxdpms.c @@ -56,13 +56,17 @@ static unsigned long dpmsGeneration = 0; static Bool dpmsSupported = TRUE; -static void _dmxDPMSInit(DMXScreenInfo *dmxScreen) +/** Initialize DPMS support. We save the current settings and turn off + * DPMS. The settings are restored in #dmxDPMSTerm. */ +void dmxBEDPMSScreenInit(ScreenPtr pScreen) { - int event_base, error_base; - int major, minor; - CARD16 level, standby, suspend, off; - BOOL state; - const char *monitor; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int event_base, error_base; + int major, minor; + CARD16 level, standby, suspend, off; + BOOL state; + const char *monitor; + int status = 1; if (dpmsGeneration != serverGeneration) { dpmsSupported = TRUE; /* On unless a backend doesn't support it */ @@ -74,37 +78,52 @@ static void _dmxDPMSInit(DMXScreenInfo *dmxScreen) #endif dmxScreen->dpmsCapable = 0; - + if (!dmxScreen->beDisplay) { dmxLogOutput(dmxScreen, "Cannot determine if DPMS supported (detached screen)\n"); - dpmsSupported = FALSE; return; } - if (!DPMSQueryExtension(dmxScreen->beDisplay, - &event_base, &error_base)) { - dmxLogOutput(dmxScreen, "DPMS not supported\n"); - dpmsSupported = FALSE; - return; - } - if (!DPMSGetVersion(dmxScreen->beDisplay, &major, &minor)) { - dmxLogOutput(dmxScreen, "DPMS not supported\n"); - dpmsSupported = FALSE; + if (dmxScreen->scrnWin != DefaultRootWindow (dmxScreen->beDisplay)) { + dmxLogOutput(dmxScreen, + "Cannot use DPMS in window mode\n"); return; } - if (!DPMSCapable(dmxScreen->beDisplay)) { - dmxLogOutput(dmxScreen, "DPMS %d.%d (not DPMS capable)\n", - major, minor); - dpmsSupported = FALSE; - return; + + dpmsSupported = FALSE; + + XLIB_PROLOGUE (dmxScreen); + + if (!(status = DPMSQueryExtension(dmxScreen->beDisplay, + &event_base, &error_base))) + dmxLogOutput(dmxScreen, "DPMS not supported\n"); + + if (status) + if (!(status = DPMSGetVersion(dmxScreen->beDisplay, &major, &minor))) + dmxLogOutput(dmxScreen, "DPMS not supported\n"); + + if (status) + if (!(status = DPMSCapable(dmxScreen->beDisplay))) + dmxLogOutput(dmxScreen, "DPMS %d.%d (not DPMS capable)\n", + major, minor); + + if (status) + { + DPMSInfo(dmxScreen->beDisplay, &level, &state); + DPMSGetTimeouts(dmxScreen->beDisplay, &standby, &suspend, &off); + DPMSSetTimeouts(dmxScreen->beDisplay, 0, 0, 0); + DPMSEnable(dmxScreen->beDisplay); + DPMSForceLevel(dmxScreen->beDisplay, DPMSModeOn); + + dpmsSupported = TRUE; } - DPMSInfo(dmxScreen->beDisplay, &level, &state); - DPMSGetTimeouts(dmxScreen->beDisplay, &standby, &suspend, &off); - DPMSSetTimeouts(dmxScreen->beDisplay, 0, 0, 0); - DPMSEnable(dmxScreen->beDisplay); - DPMSForceLevel(dmxScreen->beDisplay, DPMSModeOn); + XLIB_EPILOGUE (dmxScreen); + + if (!dpmsSupported) + return; + dmxScreen->dpmsCapable = 1; dmxScreen->dpmsEnabled = !!state; dmxScreen->dpmsStandby = standby; @@ -125,49 +144,26 @@ static void _dmxDPMSInit(DMXScreenInfo *dmxScreen) standby, suspend, off); } -/** Initialize DPMS support. We save the current settings and turn off - * DPMS. The settings are restored in #dmxDPMSTerm. */ -void dmxDPMSInit(DMXScreenInfo *dmxScreen) -{ - int interval, preferBlanking, allowExposures; - - /* Turn off DPMS */ - _dmxDPMSInit(dmxScreen); - - if (!dmxScreen->beDisplay) - return; - - /* Turn off screen saver */ - XGetScreenSaver(dmxScreen->beDisplay, &dmxScreen->savedTimeout, &interval, - &preferBlanking, &allowExposures); - XSetScreenSaver(dmxScreen->beDisplay, 0, interval, - preferBlanking, allowExposures); - XResetScreenSaver(dmxScreen->beDisplay); - dmxSync(dmxScreen, FALSE); -} - /** Terminate DPMS support on \a dmxScreen. We restore the settings * saved in #dmxDPMSInit. */ -void dmxDPMSTerm(DMXScreenInfo *dmxScreen) +void dmxBEDPMSScreenFini(ScreenPtr pScreen) { - int timeout, interval, preferBlanking, allowExposures; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; if (!dmxScreen->beDisplay) return; - XGetScreenSaver(dmxScreen->beDisplay, &timeout, &interval, - &preferBlanking, &allowExposures); - XSetScreenSaver(dmxScreen->beDisplay, dmxScreen->savedTimeout, interval, - preferBlanking, allowExposures); if (dmxScreen->dpmsCapable) { /* Restore saved state */ + XLIB_PROLOGUE (dmxScreen); DPMSForceLevel(dmxScreen->beDisplay, DPMSModeOn); DPMSSetTimeouts(dmxScreen->beDisplay, dmxScreen->dpmsStandby, dmxScreen->dpmsSuspend, dmxScreen->dpmsOff); if (dmxScreen->dpmsEnabled) DPMSEnable(dmxScreen->beDisplay); else DPMSDisable(dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); + dmxSync(dmxScreen, FALSE); } - dmxSync(dmxScreen, FALSE); } /** Called when activity is detected so that DPMS power-saving mode can @@ -203,8 +199,10 @@ int DPMSSet(ClientPtr client, int level) for (i = 0; i < dmxNumScreens; i++) { DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->beDisplay) { + if (dmxScreen->beDisplay && dmxScreen->dpmsCapable) { + XLIB_PROLOGUE (dmxScreen); DPMSForceLevel(dmxScreen->beDisplay, level); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } } diff --git a/hw/dmx/dmxdpms.h b/hw/dmx/dmxdpms.h index e3eee98..5be9a39 100644 --- a/hw/dmx/dmxdpms.h +++ b/hw/dmx/dmxdpms.h @@ -36,7 +36,7 @@ #ifndef _DMXDPMS_H_ #define _DMXDPMS_H_ -extern void dmxDPMSInit(DMXScreenInfo *dmxScreen); -extern void dmxDPMSTerm(DMXScreenInfo *dmxScreen); +extern void dmxBEDPMSScreenInit(ScreenPtr pScreen); +extern void dmxBEDPMSScreenFini(ScreenPtr pScreen); extern void dmxDPMSWakeup(void); /* Call when input is processed */ #endif diff --git a/hw/dmx/dmxextension.c b/hw/dmx/dmxextension.c index aaa50d5..a3eef48 100644 --- a/hw/dmx/dmxextension.c +++ b/hw/dmx/dmxextension.c @@ -51,18 +51,38 @@ #include "dmxgc.h" #include "dmxfont.h" #include "dmxcmap.h" +#include "dmxshm.h" #ifdef RENDER #include "dmxpict.h" #endif +#ifdef RANDR +#include "dmxrandr.h" +#endif #include "dmxinput.h" +#include "dmxlog.h" +#include "dmxgrab.h" #include "dmxsync.h" #include "dmxscrinit.h" -#include "input/dmxinputinit.h" +#ifdef XV +#include "dmxxv.h" +#endif #include "windowstr.h" #include "inputstr.h" /* For DeviceIntRec */ #include <X11/extensions/dmxproto.h> /* For DMX_BAD_* */ #include "cursorstr.h" +#include "propertyst.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +#define dmxErrorSet(set, error, name, fmt, ...) \ + if (set) (*set) (error, name, fmt, ##__VA_ARGS__) + +#define dmxLogErrorSet(type, set, error, name, fmt, ...) \ + dmxLog (type, fmt "\n", ##__VA_ARGS__); \ + dmxErrorSet (set, error, name, fmt, ##__VA_ARGS__) /* The default font is declared in dix/globals.c, but is not included in * _any_ header files. */ @@ -77,7 +97,8 @@ Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) if (physical < 0 || physical >= dmxNumScreens) return FALSE; dmxScreen = &dmxScreens[physical]; - attr->displayName = dmxScreen->name; + attr->name = dmxScreen->name; + attr->displayName = dmxScreen->display; #ifdef PANORAMIX attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0; #else @@ -86,16 +107,25 @@ Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) attr->screenWindowWidth = dmxScreen->scrnWidth; attr->screenWindowHeight = dmxScreen->scrnHeight; - attr->screenWindowXoffset = dmxScreen->scrnX; - attr->screenWindowYoffset = dmxScreen->scrnY; + attr->screenWindowXoffset = 0; + attr->screenWindowYoffset = 0; + + attr->rootWindowWidth = WindowTable[physical]->drawable.width; + attr->rootWindowHeight = WindowTable[physical]->drawable.height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + attr->rootWindowWidth = PanoramiXPixWidth; + attr->rootWindowHeight = PanoramiXPixHeight; + } +#endif - attr->rootWindowWidth = dmxScreen->rootWidth; - attr->rootWindowHeight = dmxScreen->rootHeight; attr->rootWindowXoffset = dmxScreen->rootX; attr->rootWindowYoffset = dmxScreen->rootY; - attr->rootWindowXorigin = dmxScreen->rootXOrigin; - attr->rootWindowYorigin = dmxScreen->rootYOrigin; + attr->rootWindowXorigin = 0; + attr->rootWindowYorigin = 0; return TRUE; } @@ -156,6 +186,76 @@ Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr) return TRUE; } +/** This routine provides information to the DMX protocol extension + * about a particular window. */ +Bool dmxGetDrawableAttributes(DrawablePtr pDraw, DMXWindowAttributesPtr attr) +{ + if ((pDraw->type == UNDRAWABLE_WINDOW) || (pDraw->type == DRAWABLE_WINDOW)) + { + WindowPtr pWindow = (WindowPtr) pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWindow); + + attr->screen = pWindow->drawable.pScreen->myNum; + attr->window = pWinPriv->window; + + attr->pos.x = pWindow->drawable.x; + attr->pos.y = pWindow->drawable.y; + attr->pos.width = pWindow->drawable.width; + attr->pos.height = pWindow->drawable.height; + + if (!pWinPriv->window || pWinPriv->offscreen) { + attr->vis.x = 0; + attr->vis.y = 0; + attr->vis.height = 0; + attr->vis.width = 0; + return pWinPriv->window ? TRUE : FALSE; + } + + /* Compute display-relative coordinates */ + attr->vis.x = pWindow->drawable.x; + attr->vis.y = pWindow->drawable.y; + attr->vis.width = pWindow->drawable.width; + attr->vis.height = pWindow->drawable.height; + + if (attr->pos.x < 0) { + attr->vis.x -= attr->pos.x; + attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x; + } + if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) { + if (attr->pos.x < 0) + attr->vis.width = pWindow->drawable.pScreen->width; + else + attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x; + } + if (attr->pos.y < 0) { + attr->vis.y -= attr->pos.y; + attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y; + } + if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) { + if (attr->pos.y < 0) + attr->vis.height = pWindow->drawable.pScreen->height; + else + attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y; + } + + /* Convert to window-relative coordinates */ + attr->vis.x -= attr->pos.x; + attr->vis.y -= attr->pos.y; + } + else + { + PixmapPtr pPixmap = (PixmapPtr) pDraw; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV (pPixmap); + xRectangle empty = { 0, 0, 0, 0 }; + + attr->screen = pDraw->pScreen->myNum; + attr->window = pPixPriv->pixmap; + attr->pos = attr->vis = empty; + } + + return TRUE; +} + void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr) { attr->width = dmxGlobalWidth; @@ -171,7 +271,9 @@ int dmxGetInputCount(void) { int i, total; - for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs; + for (total = i = 0; i < dmxNumScreens; i++) + total += dmxScreens[i].input.numDevs; + return total; } @@ -185,89 +287,83 @@ int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr) DMXInputInfo *dmxInput; if (deviceId < 0) return -1; - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; + for (i = 0; i < dmxNumScreens; i++) { + dmxInput = &dmxScreens[i].input; for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - if (deviceId != dmxLocal->pDevice->id) continue; - attr->isCore = !!dmxLocal->isCore; - attr->sendsCore = !!dmxLocal->sendsCore; - attr->detached = !!dmxInput->detached; - attr->physicalScreen = -1; - attr->physicalId = -1; - attr->name = NULL; - switch (dmxLocal->extType) { - case DMX_LOCAL_TYPE_LOCAL: - attr->inputType = 0; - break; - case DMX_LOCAL_TYPE_CONSOLE: - attr->inputType = 1; - attr->name = dmxInput->name; - attr->physicalId = dmxLocal->deviceId; - break; - case DMX_LOCAL_TYPE_BACKEND: - case DMX_LOCAL_TYPE_COMMON: - attr->inputType = 2; - attr->physicalScreen = dmxInput->scrnIdx; - attr->name = dmxInput->name; - attr->physicalId = dmxLocal->deviceId; - break; - } - return 0; /* Success */ + if (deviceId != dmxInput->devs[i]->id) continue; + attr->isCore = FALSE; + attr->sendsCore = TRUE; + attr->detached = FALSE; + attr->inputType = 2; + attr->physicalScreen = i; + attr->name = dmxInput->devs[i]->name; + attr->physicalId = deviceId; + return 0; /* Success */ } } return -1; /* Failure */ } -/** Reinitialized the cursor boundaries. */ -static void dmxAdjustCursorBoundaries(void) -{ - int i; - - dmxReInitOrigins(); - dmxInitOverlap(); - dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); - dmxConnectionBlockCallback(); - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (!dmxInput->detached) dmxInputReInit(dmxInput); - } - - dmxCheckCursor(); - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (!dmxInput->detached) dmxInputLateReInit(dmxInput); - } -} - /** Add an input with the specified attributes. If the input is added, * the physical id is returned in \a deviceId. */ int dmxAddInput(DMXInputAttributesPtr attr, int *id) { - int retcode = BadValue; + if (attr->physicalScreen < 0 || attr->physicalScreen >= dmxNumScreens) + return BadValue; - if (attr->inputType == 1) /* console */ - retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id); - else if (attr->inputType == 2) /* backend */ - retcode = dmxInputAttachBackend(attr->physicalScreen, - attr->sendsCore,id); + if (attr->inputType == 2) + { + DMXScreenInfo *dmxScreen = &dmxScreens[attr->physicalScreen]; + int ret; - if (retcode == Success) { - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); + if (dmxScreen->beDisplay) + { + ret = dmxInputAttach (&dmxScreen->input); + if (ret != Success) + return ret; - /* Force completion of the changes */ - dmxSync(NULL, TRUE); + dmxInputEnable (&dmxScreen->input); + } + else + { + dmxScreen->beDisplay = dmxScreen->beAttachedDisplay; + ret = dmxInputAttach (&dmxScreen->input); + dmxScreen->beDisplay = NULL; + + if (ret != Success) + return ret; + } + + *id = attr->physicalScreen; + + return ret; } - return retcode; + return BadValue; } /** Remove the input with physical id \a id. */ int dmxRemoveInput(int id) { - return dmxInputDetachId(id); + int ret; + + if (id < 0 || id >= dmxNumScreens) + return BadValue; + + if (dmxScreens[id].beDisplay) + { + dmxInputDisable (&dmxScreens[id].input); + ret = dmxInputDetach (&dmxScreens[id].input); + } + else + { + dmxScreens[id].beDisplay = dmxScreens[id].beAttachedDisplay; + ret = dmxInputDetach (&dmxScreens[id].input); + dmxScreens[id].beDisplay = NULL; + + } + + return ret; } /** Return the value of #dmxNumScreens -- the total number of backend @@ -370,307 +466,6 @@ void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h) } } -#ifdef PANORAMIX -#include "panoramiXsrv.h" - -/** Change the "screen" window attributes by resizing the actual window - * on the back-end display (if necessary). */ -static void dmxConfigureScreenWindow(int idx, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - ScreenPtr pScreen = screenInfo.screens[idx]; - - /* Resize "screen" window */ - if (dmxScreen->scrnX != x || - dmxScreen->scrnY != y || - dmxScreen->scrnWidth != w || - dmxScreen->scrnHeight != h) { - dmxResizeScreenWindow(pScreen, x, y, w, h); - } - - /* Change "screen" window values */ - dmxScreen->scrnX = x; - dmxScreen->scrnY = y; - dmxScreen->scrnWidth = w; - dmxScreen->scrnHeight = h; -} - -/** Change the "root" window position and size by resizing the actual - * window on the back-end display (if necessary) and updating all of - * DMX's resources by calling #dmxUpdateScreenResources. */ -static void dmxConfigureRootWindow(int idx, int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - WindowPtr pRoot = WindowTable[idx]; - - /* NOTE: Either this function or the ones that it calls must handle - * the case where w == 0 || h == 0. Currently, the functions that - * this one calls handle that case. */ - - /* 1. Resize "root" window */ - if (dmxScreen->rootX != x || - dmxScreen->rootY != y || - dmxScreen->rootWidth != w || - dmxScreen->rootHeight != h) { - dmxResizeRootWindow(pRoot, x, y, w, h); - } - - /* 2. Update all of the screen's resources associated with this root - * window */ - if (dmxScreen->rootWidth != w || - dmxScreen->rootHeight != h) { - dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h); - } - - /* Change "root" window values */ - dmxScreen->rootX = x; - dmxScreen->rootY = y; - dmxScreen->rootWidth = w; - dmxScreen->rootHeight = h; -} - -/** Change the "root" window's origin by updating DMX's internal data - * structures (dix and Xinerama) to use the new origin and adjust the - * positions of windows that overlap this "root" window. */ -static void dmxSetRootWindowOrigin(int idx, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - ScreenPtr pScreen = screenInfo.screens[idx]; - WindowPtr pRoot = WindowTable[idx]; - WindowPtr pChild; - int xoff; - int yoff; - - /* Change "root" window's origin */ - dmxScreen->rootXOrigin = x; - dmxScreen->rootYOrigin = y; - - /* Compute offsets here in case <x,y> has been changed above */ - xoff = x - dixScreenOrigins[idx].x; - yoff = y - dixScreenOrigins[idx].y; - - /* Adjust the root window's position in dixScreenOrigins */ - dixScreenOrigins[idx].x = dmxScreen->rootXOrigin; - dixScreenOrigins[idx].y = dmxScreen->rootYOrigin; - - /* Recalculate the Xinerama regions and data structs */ - XineramaReinitData(pScreen); - - /* Adjust each of the root window's children */ - if (!idx) ReinitializeRootWindow(WindowTable[0], xoff, yoff); - pChild = pRoot->firstChild; - while (pChild) { - /* Adjust child window's position */ - pScreen->MoveWindow(pChild, - pChild->origin.x - wBorderWidth(pChild) - xoff, - pChild->origin.y - wBorderWidth(pChild) - yoff, - pChild->nextSib, - VTMove); - - /* Note that the call to MoveWindow will eventually call - * dmxPositionWindow which will automatically create a - * window if it is now exposed on screen (for lazy window - * creation optimization) and it will properly set the - * offscreen flag. - */ - - pChild = pChild->nextSib; - } -} - -/** Configure the attributes of each "screen" and "root" window. */ -int dmxConfigureScreenWindows(int nscreens, - CARD32 *screens, - DMXScreenAttributesPtr attribs, - int *errorScreen) -{ - int i; - - for (i = 0; i < nscreens; i++) { - DMXScreenAttributesPtr attr = &attribs[i]; - int idx = screens[i]; - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - if (errorScreen) *errorScreen = i; - - if (!dmxScreen->beDisplay) return DMX_BAD_VALUE; - - /* Check for illegal values */ - if (idx < 0 || idx >= dmxNumScreens) return BadValue; - - /* The "screen" and "root" windows must have valid sizes */ - if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 || - attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0) - return DMX_BAD_VALUE; - - /* The "screen" window must fit entirely within the BE display */ - if (attr->screenWindowXoffset < 0 || - attr->screenWindowYoffset < 0 || - attr->screenWindowXoffset - + attr->screenWindowWidth > (unsigned)dmxScreen->beWidth || - attr->screenWindowYoffset - + attr->screenWindowHeight > (unsigned)dmxScreen->beHeight) - return DMX_BAD_VALUE; - - /* The "root" window must fit entirely within the "screen" window */ - if (attr->rootWindowXoffset < 0 || - attr->rootWindowYoffset < 0 || - attr->rootWindowXoffset - + attr->rootWindowWidth > attr->screenWindowWidth || - attr->rootWindowYoffset - + attr->rootWindowHeight > attr->screenWindowHeight) - return DMX_BAD_VALUE; - - /* The "root" window must not expose unaddressable coordinates */ - if (attr->rootWindowXorigin < 0 || - attr->rootWindowYorigin < 0 || - attr->rootWindowXorigin + attr->rootWindowWidth > 32767 || - attr->rootWindowYorigin + attr->rootWindowHeight > 32767) - return DMX_BAD_VALUE; - - /* The "root" window must fit within the global bounding box */ - if (attr->rootWindowXorigin - + attr->rootWindowWidth > (unsigned)dmxGlobalWidth || - attr->rootWindowYorigin - + attr->rootWindowHeight > (unsigned)dmxGlobalHeight) - return DMX_BAD_VALUE; - - /* FIXME: Handle the rest of the illegal value checking */ - } - - /* No illegal values found */ - if (errorScreen) *errorScreen = 0; - - for (i = 0; i < nscreens; i++) { - DMXScreenAttributesPtr attr = &attribs[i]; - int idx = screens[i]; - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - dmxLog(dmxInfo, "Changing screen #%d attributes " - "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d " - "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n", - idx, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - attr->screenWindowWidth, attr->screenWindowHeight, - attr->screenWindowXoffset, attr->screenWindowYoffset, - attr->rootWindowWidth, attr->rootWindowHeight, - attr->rootWindowXoffset, attr->rootWindowYoffset, - attr->rootWindowXorigin, attr->rootWindowYorigin); - - /* Configure "screen" window */ - dmxConfigureScreenWindow(idx, - attr->screenWindowXoffset, - attr->screenWindowYoffset, - attr->screenWindowWidth, - attr->screenWindowHeight); - - /* Configure "root" window */ - dmxConfigureRootWindow(idx, - attr->rootWindowXoffset, - attr->rootWindowYoffset, - attr->rootWindowWidth, - attr->rootWindowHeight); - - - /* Set "root" window's origin */ - dmxSetRootWindowOrigin(idx, - attr->rootWindowXorigin, - attr->rootWindowYorigin); - } - - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); - - /* Force completion of the changes */ - dmxSync(NULL, TRUE); - - return Success; -} - -/** Configure the attributes of the global desktop. */ -int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs) -{ - if (attribs->width <= 0 || attribs->width >= 32767 || - attribs->height <= 0 || attribs->height >= 32767) - return DMX_BAD_VALUE; - - /* If the desktop is shrinking, adjust the "root" windows on each - * "screen" window to only show the visible desktop. Also, handle - * the special case where the desktop shrinks such that the it no - * longer overlaps an portion of a "screen" window. */ - if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) { - int i; - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->rootXOrigin - + dmxScreen->rootWidth > attribs->width || - dmxScreen->rootYOrigin - + dmxScreen->rootHeight > attribs->height) { - int w, h; - if ((w = attribs->width - dmxScreen->rootXOrigin) < 0) w = 0; - if ((h = attribs->height - dmxScreen->rootYOrigin) < 0) h = 0; - if (w > dmxScreen->scrnWidth) w = dmxScreen->scrnWidth; - if (h > dmxScreen->scrnHeight) h = dmxScreen->scrnHeight; - if (w > dmxScreen->rootWidth) w = dmxScreen->rootWidth; - if (h > dmxScreen->rootHeight) h = dmxScreen->rootHeight; - dmxConfigureRootWindow(i, - dmxScreen->rootX, - dmxScreen->rootY, - w, h); - } - } - } - - /* Set the global width/height */ - dmxSetWidthHeight(attribs->width, attribs->height); - - /* Handle shift[XY] changes */ - if (attribs->shiftX || attribs->shiftY) { - int i; - for (i = 0; i < dmxNumScreens; i++) { - ScreenPtr pScreen = screenInfo.screens[i]; - WindowPtr pChild = WindowTable[i]->firstChild; - while (pChild) { - /* Adjust child window's position */ - pScreen->MoveWindow(pChild, - pChild->origin.x - wBorderWidth(pChild) - - attribs->shiftX, - pChild->origin.y - wBorderWidth(pChild) - - attribs->shiftY, - pChild->nextSib, - VTMove); - - /* Note that the call to MoveWindow will eventually call - * dmxPositionWindow which will automatically create a - * window if it is now exposed on screen (for lazy - * window creation optimization) and it will properly - * set the offscreen flag. - */ - - pChild = pChild->nextSib; - } - } - } - - /* Update connection block, Xinerama, etc. -- these appears to - * already be handled in dmxConnectionBlockCallback(), which is - * called from dmxAdjustCursorBoundaries() [below]. */ - - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); - - /* Force completion of the changes */ - dmxSync(NULL, TRUE); - - return Success; -} -#endif - /** Create the scratch GCs per depth. */ static void dmxBECreateScratchGCs(int scrnNum) { @@ -685,6 +480,8 @@ static void dmxBECreateScratchGCs(int scrnNum) #ifdef PANORAMIX static Bool FoundPixImage; +extern unsigned long XRT_PICTURE; + /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs * to have its image restored. When it is found, see if there is * another screen with the same image. If so, copy the pixmap image @@ -692,46 +489,128 @@ static Bool FoundPixImage; static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, pointer p) { + PixmapPtr pSrc = NULL; + PixmapPtr pDst = (PixmapPtr) p; + int idx = pDst->drawable.pScreen->myNum; + int i; + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { - PixmapPtr pDst = (PixmapPtr)p; int idx = pDst->drawable.pScreen->myNum; PanoramiXRes *pXinPix = (PanoramiXRes *)value; PixmapPtr pPix; - int i; pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); if (pPix != pDst) return; /* Not a match.... Next! */ - for (i = 0; i < PanoramiXNumScreens; i++) { - PixmapPtr pSrc; - dmxPixPrivPtr pSrcPriv = NULL; - + for (i = 0; i < PanoramiXNumScreens; i++) + { if (i == idx) continue; /* Self replication is bad */ pSrc = (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); - pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); - if (pSrcPriv->pixmap) { - DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; - DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; - dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); - XImage *img; - int j; - XlibGC gc = NULL; - - /* This should never happen, but just in case.... */ - if (pSrc->drawable.width != pDst->drawable.width || - pSrc->drawable.height != pDst->drawable.height) - return; - - /* Copy from src pixmap to dst pixmap */ - img = XGetImage(dmxSrcScreen->beDisplay, - pSrcPriv->pixmap, - 0, 0, - pSrc->drawable.width, pSrc->drawable.height, - -1, - ZPixmap); + break; + } + } + +#ifdef RENDER + else if ((type & TypeMask) == (XRT_PICTURE & TypeMask)) + { + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPic = (PanoramiXRes *) value; + PicturePtr pPic; + + pPic = (PicturePtr) LookupIDByType (pXinPic->info[idx].id, + PictureType); + + /* Not a match.... Next! */ + if (!pPic || !pPic->pDrawable) return; + if (pPic->pDrawable->type != DRAWABLE_PIXMAP) return; + if (pPic->pDrawable != (DrawablePtr) pDst) return; + + for (i = 0; i < PanoramiXNumScreens; i++) + { + if (i == idx) continue; /* Self replication is bad */ + + pPic = (PicturePtr) LookupIDByType (pXinPic->info[i].id, + PictureType); + pSrc = (PixmapPtr) pPic->pDrawable; + break; + } + } +#endif + + else if ((type & TypeMask) == (XRT_WINDOW & TypeMask)) + { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinWin = (PanoramiXRes *) value; + Bool border; + WindowPtr pWin; + pWin = (WindowPtr) LookupIDByType (pXinWin->info[idx].id, RT_WINDOW); + + if (!pWin) return; + if (!pWin->borderIsPixel && pWin->border.pixmap == pDst) + { + border = TRUE; + } + else if (pWin->backgroundState == BackgroundPixmap && + pWin->background.pixmap == pDst) + { + border = FALSE; + } + else + { + return; + } + + for (i = 0; i < PanoramiXNumScreens; i++) + { + if (i == idx) continue; /* Self replication is bad */ + + pWin = (WindowPtr) LookupIDByType (pXinWin->info[i].id, RT_WINDOW); + + if (border) + pSrc = pWin->border.pixmap; + else + pSrc = pWin->background.pixmap; + + break; + } + } + + if (pSrc) + { + dmxPixPrivPtr pSrcPriv = DMX_GET_PIXMAP_PRIV (pSrc); + + if (pSrcPriv->pixmap) + { + DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; + DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; + dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); + XImage *img = NULL; + int j; + XlibGC gc = NULL; + + /* This should never happen, but just in case.... */ + if (pSrc->drawable.width != pDst->drawable.width || + pSrc->drawable.height != pDst->drawable.height) + return; + + XLIB_PROLOGUE (dmxSrcScreen); + + /* Copy from src pixmap to dst pixmap */ + img = XGetImage(dmxSrcScreen->beDisplay, + pSrcPriv->pixmap, + 0, 0, + pSrc->drawable.width, pSrc->drawable.height, + -1, + ZPixmap); + + XLIB_EPILOGUE (dmxSrcScreen); + + if (img) + { for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) { if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) { unsigned long m; @@ -742,26 +621,31 @@ static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, v.plane_mask = AllPlanes; v.clip_mask = None; + XLIB_PROLOGUE (dmxDstScreen); gc = XCreateGC(dmxDstScreen->beDisplay, dmxDstScreen->scrnDefDrawables[j], m, &v); + XLIB_EPILOGUE (dmxDstScreen); break; } } if (gc) { + XLIB_PROLOGUE (dmxDstScreen); XPutImage(dmxDstScreen->beDisplay, pDstPriv->pixmap, gc, img, 0, 0, 0, 0, pDst->drawable.width, pDst->drawable.height); XFreeGC(dmxDstScreen->beDisplay, gc); + XLIB_EPILOGUE (dmxDstScreen); FoundPixImage = True; } else { dmxLog(dmxWarning, "Could not create GC\n"); } XDestroyImage(img); - return; + } else { + dmxLog(dmxWarning, "Could not create image\n"); } } } @@ -810,14 +694,17 @@ static void dmxBERestorePixmap(PixmapPtr pPixmap) v.plane_mask = AllPlanes; v.clip_mask = None; + XLIB_PROLOGUE (dmxScreen); gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], m, &v); + XLIB_EPILOGUE (dmxScreen); break; } } if (gc) { + XLIB_PROLOGUE (dmxScreen); XPutImage(dmxScreen->beDisplay, pPixPriv->pixmap, gc, @@ -825,6 +712,7 @@ static void dmxBERestorePixmap(PixmapPtr pPixmap) 0, 0, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height); XFreeGC(dmxScreen->beDisplay, gc); + XLIB_EPILOGUE (dmxScreen); } else { dmxLog(dmxWarning, "Cannot restore pixmap image\n"); } @@ -832,7 +720,10 @@ static void dmxBERestorePixmap(PixmapPtr pPixmap) XDestroyImage(pPixPriv->detachedImage); pPixPriv->detachedImage = NULL; } else { - dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + dmxLog(dmxWarning, "Cannot restore pixmap image: %dx%d - %d\n", + pPixmap->drawable.width, + pPixmap->drawable.height, + pPixmap->drawable.depth); } } #else @@ -888,11 +779,17 @@ static void dmxBECreateResources(pointer value, XID id, RESTYPE type, } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { (void)dmxBELoadFont(pScreen, (FontPtr)value); } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { - dmxBECreateCursor(pScreen, (CursorPtr)value); + dmxBECreateCursor (pScreen, (CursorPtr) value); + } else if ((type & TypeMask) == (RT_PASSIVEGRAB & TypeMask)) { + GrabPtr grab = value; + if (grab->cursor) + dmxBECreateCursor (pScreen, grab->cursor); } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { ColormapPtr pCmap = value; if (pCmap->pScreen->myNum == scrnNum) (void)dmxBECreateColormap((ColormapPtr)value); + } else if ((type & TypeMask) == (DMX_SHMSEG & TypeMask)) { + dmxBEAttachShmSeg (&dmxScreens[scrnNum], (dmxShmSegInfoPtr) value); #if 0 #ifdef RENDER /* TODO: Recreate Picture and GlyphSet resources */ @@ -930,9 +827,14 @@ static void dmxBECreateWindowTree(int idx) dmxBERestorePixmap(pRoot->background.pixmap); } + dmxBECreateCursor (screenInfo.screens[idx], pRoot->optional->cursor); + /* Create root window first */ dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot); - XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); + +#ifdef RENDER + if (pWinPriv->hasPict) dmxCreatePictureList (pRoot); +#endif pWin = pRoot->lastChild; while (pWin) { @@ -950,14 +852,17 @@ static void dmxBECreateWindowTree(int idx) dmxBERestorePixmap(pWin->background.pixmap); } + if (wUseDefault(pWin, cursor, 0)) + dmxBECreateCursor (screenInfo.screens[idx], + pWin->optional->cursor); + /* Reset the window attributes */ dmxGetDefaultWindowAttributes(pWin, &pWinPriv->cmap, &pWinPriv->visual); /* Create the window */ - if (pWinPriv->mapped && !pWinPriv->offscreen) - dmxCreateAndRealizeWindow(pWin, TRUE); + dmxCreateAndRealizeWindow(pWin, TRUE); /* Next, create the bottom-most child */ if (pWin->lastChild) { @@ -980,77 +885,392 @@ static void dmxBECreateWindowTree(int idx) } } -/* Refresh screen by generating exposure events for all windows */ -static void dmxForceExposures(int idx) +static void dmxBEMapRootWindow(int idx) { - ScreenPtr pScreen = screenInfo.screens[idx]; - WindowPtr pRoot = WindowTable[idx]; - Bool anyMarked = FALSE; - WindowPtr pChild; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) - anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, - (WindowPtr *)NULL); - if (anyMarked) { - /* If any windows have been marked, set the root window's - * clipList to be broken since it will be recalculated in - * ValidateTree() - */ - REGION_BREAK(pScreen, &pRoot->clipList); - pScreen->ValidateTree(pRoot, NULL, VTBroken); - pScreen->HandleExposures(pRoot); - if (pScreen->PostValidateTree) - pScreen->PostValidateTree(pRoot, NULL, VTBroken); + XLIB_PROLOGUE (dmxScreen); + XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); + XLIB_EPILOGUE (dmxScreen); +} + +static void dmxBECreateWindowProperties (int idx) +{ + WindowPtr pRoot = WindowTable[idx]; + WindowPtr pRoot0 = pRoot; + WindowPtr pWin; + WindowPtr pWin0; + PropertyPtr pProp, pLast; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pRoot0 = WindowTable[0]; +#endif + + pWin = pRoot; + pWin0 = pRoot0; + while (pWin) + { + pLast = NULL; + do + { + for (pProp = wUserProps (pWin0); pProp; pProp = pProp->next) + if (pProp->next == pLast) + break; + + if (pProp) + dmxBESetWindowProperty (pWin, (pLast = pProp)); + } while (pLast != wUserProps (pWin0)); + + /* Next, create the bottom-most child */ + if (pWin->lastChild) { + pWin = pWin->lastChild; + pWin0 = pWin0->lastChild; + continue; + } + + /* If the window has no children, move on to the next higher window */ + while (!pWin->prevSib && (pWin != pRoot)) + { + pWin = pWin->parent; + pWin0 = pWin0->parent; + } + + if (pWin->prevSib) { + pWin = pWin->prevSib; + pWin0 = pWin0->prevSib; + continue; + } + + /* When we reach the root window, we are finished */ + if (pWin == pRoot) + break; } } /** Compare the new and old screens to see if they are compatible. */ -static Bool dmxCompareScreens(DMXScreenInfo *new, DMXScreenInfo *old) +static Bool dmxCompareScreens(DMXScreenInfo *new, + DMXScreenInfo *old, + dmxErrorSetProcPtr errorSet, + void *error, + const char *errorName) { int i; - if (new->beWidth != old->beWidth) return FALSE; - if (new->beHeight != old->beHeight) return FALSE; - if (new->beDepth != old->beDepth) return FALSE; - if (new->beBPP != old->beBPP) return FALSE; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + ScreenPtr pScreen = screenInfo.screens[0]; + int j; + + old = dmxScreens; /* each new screen must match the first screen */ + + if (new->beDepth != old->beDepth) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen depth is not %d", + old->beDepth); + return FALSE; + } + + if (new->beBPP != old->beBPP) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen BPP is not %d", + old->beBPP); + return FALSE; + } + + for (i = 0; i < old->beNumDepths; i++) + { + for (j = 0; j < new->beNumDepths; j++) + if (new->beDepths[j] == old->beDepths[i]) + break; + + if (j == new->beNumDepths) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen doesn't support depth %d", + old->beDepths[i]); + return FALSE; + } + } + + for (i = 0; i < old->beNumPixmapFormats; i++) + { + for (j = 0; j < new->beNumPixmapFormats; j++) + if (new->bePixmapFormats[j].depth == + old->bePixmapFormats[i].depth && + new->bePixmapFormats[j].bits_per_pixel == + old->bePixmapFormats[i].bits_per_pixel && + new->bePixmapFormats[j].scanline_pad == + old->bePixmapFormats[i].scanline_pad) + break; + + if (j == new->beNumPixmapFormats) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen doesn't support pixmap format " + "depth=%d,bits_per_pixel=%d,scanline_pad=%d\n", + old->bePixmapFormats[i].depth, + old->bePixmapFormats[i].bits_per_pixel, + old->bePixmapFormats[i].scanline_pad); + return FALSE; + } + } + + for (i = 0; i < pScreen->numVisuals; i++) + { + int k; + + for (k = 0; k < old->beNumVisuals; k++) + if (pScreen->visuals[i].class == + old->beVisuals[k].class && + pScreen->visuals[i].bitsPerRGBValue == + old->beVisuals[k].bits_per_rgb && + pScreen->visuals[i].ColormapEntries == + old->beVisuals[k].colormap_size && + pScreen->visuals[i].nplanes == + old->beVisuals[k].depth && + pScreen->visuals[i].redMask == + old->beVisuals[k].red_mask && + pScreen->visuals[i].greenMask == + old->beVisuals[k].green_mask && + pScreen->visuals[i].blueMask == + old->beVisuals[k].blue_mask) + break; + + assert (k < old->beNumVisuals); + + for (j = 0; j < new->beNumVisuals; j++) + if (new->beVisuals[j].depth == + old->beVisuals[k].depth && + new->beVisuals[j].class == + old->beVisuals[k].class && + new->beVisuals[j].red_mask == + old->beVisuals[k].red_mask && + new->beVisuals[j].green_mask == + old->beVisuals[k].green_mask && + new->beVisuals[j].blue_mask == + old->beVisuals[k].blue_mask && + new->beVisuals[j].bits_per_rgb >= + old->beVisuals[k].bits_per_rgb && + new->beVisuals[j].colormap_size >= + old->beVisuals[k].colormap_size) + break; + + if (j == new->beNumVisuals) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen doesn't support visual: " + "class: %s, " + "depth: %d planes, " + "available colormap entries: %d%s, " + "red/green/blue masks: 0x%lx/0x%lx/0x%lx, " + "significant bits in color specification: " + "%d bits", + old->beVisuals[k].class == StaticGray ? + "StaticGray" : + old->beVisuals[k].class == GrayScale ? + "GrayScale" : + old->beVisuals[k].class == StaticColor ? + "StaticColor" : + old->beVisuals[k].class == PseudoColor ? + "PseudoColor" : + old->beVisuals[k].class == TrueColor ? + "TrueColor" : + old->beVisuals[k].class == DirectColor ? + "DirectColor" : + "Unknown Class", + old->beVisuals[k].depth, + old->beVisuals[k].colormap_size, + (old->beVisuals[k].class == TrueColor || + old->beVisuals[k].class == DirectColor) ? + " per subfield" : "", + old->beVisuals[k].red_mask, + old->beVisuals[k].green_mask, + old->beVisuals[k].blue_mask, + old->beVisuals[k].bits_per_rgb); + return FALSE; + } + } + + return TRUE; + } +#endif + + if (new->beWidth != old->beWidth || new->beHeight != old->beHeight) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen dimensions are not %dx%d", + old->beWidth, old->beHeight); + return FALSE; + } + if (new->beDepth != old->beDepth) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen depth is not %d", + old->beDepth); + return FALSE; + } + if (new->beBPP != old->beBPP) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen BPP is not %dx%d", + old->beBPP); + return FALSE; + } + if (new->beNumDepths != old->beNumDepths) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen number of depths is not %d", + old->beNumDepths); + return FALSE; + } - if (new->beNumDepths != old->beNumDepths) return FALSE; for (i = 0; i < old->beNumDepths; i++) - if (new->beDepths[i] != old->beDepths[i]) return FALSE; + if (new->beDepths[i] != old->beDepths[i]) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen depth index %d is not %d", + i, old->beDepths[i]); + return FALSE; + } - if (new->beNumPixmapFormats != old->beNumPixmapFormats) return FALSE; + if (new->beNumPixmapFormats != old->beNumPixmapFormats) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen number of pixmap formats is not %d", + old->beNumPixmapFormats); + return FALSE; + } for (i = 0; i < old->beNumPixmapFormats; i++) { if (new->bePixmapFormats[i].depth != - old->bePixmapFormats[i].depth) return FALSE; + old->bePixmapFormats[i].depth) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "depth of screen pixmap format index %d is not %d", + i, old->bePixmapFormats[i].depth); + return FALSE; + } if (new->bePixmapFormats[i].bits_per_pixel != - old->bePixmapFormats[i].bits_per_pixel) return FALSE; + old->bePixmapFormats[i].bits_per_pixel) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "bits_per_pixel of screen pixmap format " + "index %d is not %d", + i, old->bePixmapFormats[i].bits_per_pixel); + return FALSE; + } if (new->bePixmapFormats[i].scanline_pad != - old->bePixmapFormats[i].scanline_pad) return FALSE; + old->bePixmapFormats[i].scanline_pad) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "scanline_pad of screen pixmap format " + "index %d is not %d", + i, old->bePixmapFormats[i].scanline_pad); + return FALSE; + } } - if (new->beNumVisuals != old->beNumVisuals) return FALSE; + if (new->beNumVisuals != old->beNumVisuals) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen number of visuals is not %d", + old->beNumVisuals); + return FALSE; + } for (i = 0; i < old->beNumVisuals; i++) { if (new->beVisuals[i].visualid != - old->beVisuals[i].visualid) return FALSE; + old->beVisuals[i].visualid) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "visualid of screen visual " + "index %d is not %d", + i, old->beVisuals[i].visualid); + return FALSE; + } if (new->beVisuals[i].screen != - old->beVisuals[i].screen) return FALSE; + old->beVisuals[i].screen) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "screen of screen visual " + "index %d is not %d", + i, old->beVisuals[i].screen); + return FALSE; + } if (new->beVisuals[i].depth != - old->beVisuals[i].depth) return FALSE; + old->beVisuals[i].depth) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "depth of screen visual " + "index %d is not %d", + i, old->beVisuals[i].depth); + return FALSE; + } if (new->beVisuals[i].class != - old->beVisuals[i].class) return FALSE; + old->beVisuals[i].class) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "class of screen visual " + "index %d is not %d", + i, old->beVisuals[i].class); + return FALSE; + } if (new->beVisuals[i].red_mask != - old->beVisuals[i].red_mask) return FALSE; + old->beVisuals[i].red_mask) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "red_mask of screen visual " + "index %d is not %d", + i, old->beVisuals[i].red_mask); + return FALSE; + } if (new->beVisuals[i].green_mask != - old->beVisuals[i].green_mask) return FALSE; + old->beVisuals[i].green_mask) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "green_mask of screen visual " + "index %d is not %d", + i, old->beVisuals[i].green_mask); + return FALSE; + } if (new->beVisuals[i].blue_mask != - old->beVisuals[i].blue_mask) return FALSE; + old->beVisuals[i].blue_mask) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "blue_mask of screen visual " + "index %d is not %d", + i, old->beVisuals[i].blue_mask); + return FALSE; + } if (new->beVisuals[i].colormap_size != - old->beVisuals[i].colormap_size) return FALSE; + old->beVisuals[i].colormap_size) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "colormap_size of screen visual " + "index %d is not %d", + i, old->beVisuals[i].colormap_size); + return FALSE; + } if (new->beVisuals[i].bits_per_rgb != - old->beVisuals[i].bits_per_rgb) return FALSE; + old->beVisuals[i].bits_per_rgb) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "bits_per_rgb of screen visual " + "index %d is not %d", + i, old->beVisuals[i].bits_per_rgb); + return FALSE; + } } - if (new->beDefVisualIndex != old->beDefVisualIndex) return FALSE; + if (new->beDefVisualIndex != old->beDefVisualIndex) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Screen default visual index is not %d", + old->beDefVisualIndex); + return FALSE; + } return TRUE; } @@ -1063,20 +1283,23 @@ static void dmxBERestoreRenderPict(pointer value, XID id, pointer n) DrawablePtr pDraw = pPicture->pDrawable; /* The picture's drawable */ int scrnNum = (int)n; - if (pDraw->pScreen->myNum != scrnNum) { - /* Picture not on the screen we are restoring*/ - return; - } + if (pDraw) + { + if (pDraw->pScreen->myNum != scrnNum) { + /* Picture not on the screen we are restoring*/ + return; + } - if (pDraw->type == DRAWABLE_PIXMAP) { - PixmapPtr pPixmap = (PixmapPtr)pDraw; + if (pDraw->type == DRAWABLE_PIXMAP) { + PixmapPtr pPixmap = (PixmapPtr)pDraw; - /* Create and restore the pixmap drawable */ - dmxBECreatePixmap(pPixmap); - dmxBERestorePixmap(pPixmap); + /* Create and restore the pixmap drawable */ + dmxBECreatePixmap(pPixmap); + dmxBERestorePixmap(pPixmap); + } } - dmxBECreatePicture(pPicture); + dmxBECreatePicture(scrnNum, pPicture); } /** Restore Render's glyphs */ @@ -1093,7 +1316,7 @@ static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) char *pos; int beret; int len_images = 0; - int i; + int i, size; int ctr; if (glyphPriv->glyphSets[scrnNum]) { @@ -1117,9 +1340,18 @@ static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) GlyphPtr gl = gr->glyph; if (!gl || gl == DeletedGlyph) continue; - len_images += gl->size - sizeof(gl->info); + + size = gl->info.height * PixmapBytePad (gl->info.width, + glyphSet->format->depth); + if (size & 3) + size += 4 - (size & 3); + + len_images += size; } + if (!len_images) + return; + /* Now allocate the memory we need */ images = xalloc(len_images*sizeof(char)); gids = xalloc(glyphSet->hash.tableEntries*sizeof(Glyph)); @@ -1133,6 +1365,7 @@ static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) for (i = 0; i < glyphSet->hash.hashSet->size; i++) { GlyphRefPtr gr = &table[i]; GlyphPtr gl = gr->glyph; + char *data; if (!gl || gl == DeletedGlyph) continue; @@ -1147,32 +1380,62 @@ static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) glyphs[ctr].xOff = gl->info.xOff; glyphs[ctr].yOff = gl->info.yOff; - /* Copy the images from the DIX's data into the buffer */ - memcpy(pos, gl+1, gl->size - sizeof(gl->info)); - pos += gl->size - sizeof(gl->info); + size = gl->info.height * PixmapBytePad (gl->info.width, + glyphSet->format->depth); + if (size & 3) + size += 4 - (size & 3); + + data = dixLookupPrivate (&(gl)->devPrivates, dmxGlyphPrivateKey); + if (data) + { + memcpy (pos, data, size); + } + else + { + dmxLog (dmxWarning, + "Cannot restore glyph image: %dx%d %d\n", + gl->info.width, + gl->info.height, + glyphSet->format->depth); + + memset (pos, 0xff, size); + } + + pos += size; ctr++; } - + /* Now restore the glyph data */ + XLIB_PROLOGUE (dmxScreen); XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[scrnNum], - gids,glyphs, glyphSet->hash.tableEntries, images, - len_images); + gids, glyphs, ctr, images, len_images); + XLIB_EPILOGUE (dmxScreen); /* Clean up */ - xfree(len_images); + xfree(images); xfree(gids); xfree(glyphs); } #endif /** Reattach previously detached back-end screen. */ -int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) +int +dmxAttachScreen (int idx, + DMXScreenAttributesPtr attr, + unsigned int window, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen, + dmxErrorSetProcPtr errorSet, + void *error, + const char *errorName) { - ScreenPtr pScreen; + ScreenPtr pScreen; DMXScreenInfo *dmxScreen; - CARD32 scrnNum = idx; - DMXScreenInfo oldDMXScreen; - int i; + DMXScreenInfo oldDMXScreen; + Bool beShape = FALSE; + int errorBase; /* Return failure if dynamic addition/removal of screens is disabled */ if (!dmxAddRemoveScreens) { @@ -1184,19 +1447,28 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) "add the \"-addremovescreens\" option either to the command\n"); dmxLog(dmxWarning, "line or in the configuration file.\n"); + dmxErrorSet (errorSet, error, errorName, + "Screen attach extension has not been enabled"); return 1; } /* Cannot add a screen that does not exist */ - if (idx < 0 || idx >= dmxNumScreens) return 1; + if (idx < 0 || idx >= dmxNumScreens) + { + dmxErrorSet (errorSet, error, errorName, + "Screen %d does not exist", idx); + return 1; + } + pScreen = screenInfo.screens[idx]; dmxScreen = &dmxScreens[idx]; /* Cannot attach to a screen that is already opened */ - if (dmxScreen->beDisplay) { - dmxLog(dmxWarning, - "Attempting to add screen #%d but a screen already exists\n", - idx); + if (dmxScreen->name && *dmxScreen->name) { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Attempting to attach back-end server to screen #%d " + "but back-end server is already attached to this " + "screen", idx); return 1; } @@ -1205,28 +1477,59 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) /* Save old info */ oldDMXScreen = *dmxScreen; - /* Copy the name to the new screen */ - dmxScreen->name = strdup(attr->displayName); + dmxScreen->scrnWin = window; + dmxScreen->virtualFb = FALSE; /* Open display and get all of the screen info */ - if (!dmxOpenDisplay(dmxScreen)) { - dmxLog(dmxWarning, - "dmxOpenDisplay: Unable to open display %s\n", - dmxScreen->name); + if (!dmxOpenDisplay(dmxScreen, + attr->displayName, + authType, + authTypeLen, + authData, + authDataLen)) { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "Can't open display: %s", + attr->displayName); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + XLIB_PROLOGUE (dmxScreen); + beShape = XShapeQueryExtension (dmxScreen->beDisplay, + &dmxScreen->beShapeEventBase, + &errorBase); + XLIB_EPILOGUE (dmxScreen); + + if (!beShape) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "SHAPE extension missing"); + dmxCloseDisplay (dmxScreen); /* Restore the old screen */ *dmxScreen = oldDMXScreen; return 1; } + if (!dmxScreen->scrnWin) + dmxScreen->scrnWin = DefaultRootWindow (dmxScreen->beDisplay); + + XLIB_PROLOGUE (dmxScreen); + XSelectInput (dmxScreen->beDisplay, + dmxScreen->scrnWin, + StructureNotifyMask); + XLIB_EPILOGUE (dmxScreen); + dmxSetErrorHandler(dmxScreen); - dmxCheckForWM(dmxScreen); dmxGetScreenAttribs(dmxScreen); if (!dmxGetVisualInfo(dmxScreen)) { - dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n"); + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "No matching visuals found"); XFree(dmxScreen->beVisuals); - XCloseDisplay(dmxScreen->beDisplay); + dmxCloseDisplay (dmxScreen); /* Restore the old screen */ *dmxScreen = oldDMXScreen; @@ -1238,28 +1541,82 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) /* Verify that the screen to be added has the same info as the * previously added screen. */ - if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) { + if (!dmxCompareScreens(dmxScreen, + &oldDMXScreen, + errorSet, + error, + errorName)) + { dmxLog(dmxWarning, "New screen data (%s) does not match previously\n", dmxScreen->name); dmxLog(dmxWarning, - "attached screen data (%s)\n", - oldDMXScreen.name); + "attached screen data\n"); dmxLog(dmxWarning, "All data must match in order to attach to screen #%d\n", idx); XFree(dmxScreen->beVisuals); XFree(dmxScreen->beDepths); XFree(dmxScreen->bePixmapFormats); - XCloseDisplay(dmxScreen->beDisplay); + dmxCloseDisplay (dmxScreen); /* Restore the old screen */ *dmxScreen = oldDMXScreen; return 1; } + /* Create the default font */ + if (!dmxBELoadFont(pScreen, defaultFont)) + { + dmxErrorSet (errorSet, error, errorName, + "Failed to load default font"); + XFree(dmxScreen->beVisuals); + XFree(dmxScreen->beDepths); + XFree(dmxScreen->bePixmapFormats); + dmxCloseDisplay (dmxScreen); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + /* We used these to compare the old and new screens. They are no + * longer needed since we have a newly attached screen, so we can + * now free the old screen's resources. */ + if (oldDMXScreen.beVisuals) + XFree(oldDMXScreen.beVisuals); + if (oldDMXScreen.beDepths) + XFree(oldDMXScreen.beDepths); + if (oldDMXScreen.bePixmapFormats) + XFree(oldDMXScreen.bePixmapFormats); + + if (attr->name) + dmxScreen->name = strdup(attr->name); + else + dmxScreen->name = strdup(attr->displayName); + + dmxScreen->beAttachedDisplay = dmxScreen->beDisplay; + dmxScreen->beDisplay = NULL; + + return 0; /* Success */ +} + +void +dmxEnableScreen (int idx) +{ + ScreenPtr pScreen; + DMXScreenInfo *dmxScreen; + int i; + + pScreen = screenInfo.screens[idx]; + dmxScreen = &dmxScreens[idx]; + + dmxLogOutput(dmxScreen, "Enable screen #%d\n", idx); + + dmxScreen->beDisplay = dmxScreen->beAttachedDisplay; + /* Initialize the BE screen resources */ - dmxBEScreenInit(idx, screenInfo.screens[idx]); + dmxBEScreenInit(screenInfo.screens[idx]); /* TODO: Handle GLX visual initialization. GLXProxy needs to be * updated to handle dynamic addition/removal of screens. */ @@ -1271,8 +1628,9 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) /* Create the scratch GCs */ dmxBECreateScratchGCs(idx); - /* Create the default font */ - (void)dmxBELoadFont(pScreen, defaultFont); + /* Create the scratch pixmap */ + if (pScreen->pScratchPixmap) + dmxBECreatePixmap(pScreen->pScratchPixmap); /* Create all resources that don't depend on windows */ for (i = currentMaxClients; --i >= 0; ) @@ -1282,6 +1640,7 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) /* Create window hierarchy (top down) */ dmxBECreateWindowTree(idx); + dmxBECreateWindowProperties(idx); #ifdef RENDER /* Restore the picture state for RENDER */ @@ -1297,25 +1656,13 @@ int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) dmxBERestoreRenderGlyph,(pointer)idx); #endif - /* Refresh screen by generating exposure events for all windows */ - dmxForceExposures(idx); - - dmxSync(&dmxScreens[idx], TRUE); - - /* We used these to compare the old and new screens. They are no - * longer needed since we have a newly attached screen, so we can - * now free the old screen's resources. */ - XFree(oldDMXScreen.beVisuals); - XFree(oldDMXScreen.beDepths); - XFree(oldDMXScreen.bePixmapFormats); - /* TODO: should oldDMXScreen.name be freed?? */ + dmxBEMapRootWindow(idx); -#ifdef PANORAMIX - if (!noPanoramiXExtension) - return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL); - else +#ifdef RANDR + RRGetInfo (screenInfo.screens[0]); #endif - return 0; /* Success */ + + dmxInputEnable (&dmxScreen->input); } /* @@ -1373,6 +1720,7 @@ static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, int i; pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); + if (pPix != pDst) return; /* Not a match.... Next! */ for (i = 0; i < PanoramiXNumScreens; i++) { @@ -1383,6 +1731,7 @@ static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, pSrc = (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); if (pSrcPriv->pixmap) { FoundPixImage = True; @@ -1390,6 +1739,87 @@ static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, } } } + +#ifdef RENDER + else if ((type & TypeMask) == (XRT_PICTURE & TypeMask)) + { + PixmapPtr pDst = (PixmapPtr) p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPic = (PanoramiXRes *) value; + PicturePtr pPic; + int i; + + pPic = (PicturePtr) LookupIDByType (pXinPic->info[idx].id, + PictureType); + + /* Not a match.... Next! */ + if (!pPic || !pPic->pDrawable) return; + if (pPic->pDrawable->type != DRAWABLE_PIXMAP) return; + if (pPic->pDrawable != (DrawablePtr) pDst) return; + + for (i = 0; i < PanoramiXNumScreens; i++) { + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pPic = (PicturePtr) LookupIDByType (pXinPic->info[i].id, + PictureType); + + pSrcPriv = DMX_GET_PIXMAP_PRIV ((PixmapPtr) pPic->pDrawable); + if (pSrcPriv->pixmap) + { + FoundPixImage = True; + return; + } + } + } +#endif + + else if ((type & TypeMask) == (XRT_WINDOW & TypeMask)) + { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinWin = (PanoramiXRes *) value; + Bool border; + WindowPtr pWin; + int i; + + pWin = (WindowPtr) LookupIDByType (pXinWin->info[idx].id, RT_WINDOW); + + if (!pWin) return; + if (!pWin->borderIsPixel && pWin->border.pixmap == pDst) + { + border = TRUE; + } + else if (pWin->backgroundState == BackgroundPixmap && + pWin->background.pixmap == pDst) + { + border = FALSE; + } + else + { + return; + } + + for (i = 0; i < PanoramiXNumScreens; i++) { + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pWin = (WindowPtr) LookupIDByType (pXinWin->info[i].id, RT_WINDOW); + + if (border) + pSrcPriv = DMX_GET_PIXMAP_PRIV (pWin->border.pixmap); + else + pSrcPriv = DMX_GET_PIXMAP_PRIV (pWin->background.pixmap); + + if (pSrcPriv->pixmap) + { + FoundPixImage = True; + return; + } + } + } } #endif @@ -1426,6 +1856,7 @@ static void dmxBESavePixmap(PixmapPtr pPixmap) ScreenPtr pScreen = pPixmap->drawable.pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XLIB_PROLOGUE (dmxScreen); pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, @@ -1433,8 +1864,15 @@ static void dmxBESavePixmap(PixmapPtr pPixmap) pPixmap->drawable.height, -1, ZPixmap); + XLIB_EPILOGUE (dmxScreen); + if (!pPixPriv->detachedImage) - dmxLog(dmxWarning, "Cannot save pixmap image\n"); + { + dmxLog(dmxWarning, "Cannot save pixmap image: %p - %dx%d %d\n", + pPixmap, pPixmap->drawable.width, + pPixmap->drawable.height, + pPixmap->drawable.depth); + } } } #else @@ -1476,22 +1914,31 @@ static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { dmxBEFreeFont(pScreen, (FontPtr)value); } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { - dmxBEFreeCursor(pScreen, (CursorPtr)value); + dmxBEFreeCursor (pScreen, (CursorPtr) value); } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { ColormapPtr pCmap = value; if (pCmap->pScreen->myNum == scrnNum) dmxBEFreeColormap((ColormapPtr)value); + } else if ((type & TypeMask) == (DMX_SHMSEG & TypeMask)) { + dmxBEDetachShmSeg (&dmxScreens[scrnNum], (dmxShmSegInfoPtr) value); #ifdef RENDER } else if ((type & TypeMask) == (PictureType & TypeMask)) { PicturePtr pPict = value; - if (pPict->pDrawable->pScreen->myNum == scrnNum) { - /* Free the pixmaps on the backend if needed */ - if (pPict->pDrawable->type == DRAWABLE_PIXMAP) { - PixmapPtr pPixmap = (PixmapPtr)(pPict->pDrawable); - dmxBESavePixmap(pPixmap); - dmxBEFreePixmap(pPixmap); + if (pPict->pDrawable) { + if (pPict->pDrawable->pScreen->myNum == scrnNum) { + /* Free the pixmaps on the backend if needed */ + if (pPict->pDrawable->type == DRAWABLE_PIXMAP) { + PixmapPtr pPixmap = (PixmapPtr)(pPict->pDrawable); + dmxBESavePixmap(pPixmap); + dmxBEFreePixmap(pPixmap); + } + + dmxBEFreePicture(pScreen, (PicturePtr)value); } - dmxBEFreePicture((PicturePtr)value); + } + else + { + dmxBEFreePicture(pScreen, (PicturePtr)value); } } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); @@ -1531,6 +1978,10 @@ static void dmxBEDestroyWindowTree(int idx) /* Destroy the window */ dmxBEDestroyWindow(pChild); + if (wUseDefault(pChild, cursor, 0)) + dmxBEFreeCursor (screenInfo.screens[idx], + pChild->optional->cursor); + /* Make sure we destroy the window's border and background * pixmaps if they exist */ if (!pChild->borderIsPixel) { @@ -1545,6 +1996,9 @@ static void dmxBEDestroyWindowTree(int idx) while (!pChild->nextSib && (pChild != pWin)) { pChild = pChild->parent; dmxBEDestroyWindow(pChild); + if (wUseDefault(pChild, cursor, 0)) + dmxBEFreeCursor (screenInfo.screens[idx], + pChild->optional->cursor); if (!pChild->borderIsPixel) { dmxBESavePixmap(pChild->border.pixmap); dmxBEFreePixmap(pChild->border.pixmap); @@ -1562,11 +2016,68 @@ static void dmxBEDestroyWindowTree(int idx) } } +void +dmxDisableScreen (int idx) +{ + ScreenPtr pScreen; + DMXScreenInfo *dmxScreen; + int i; + + pScreen = screenInfo.screens[idx]; + dmxScreen = &dmxScreens[idx]; + + dmxLogOutput(dmxScreen, "Disable screen #%d\n", idx); + + dmxInputDisable (&dmxScreen->input); + +#ifdef XV + dmxBEXvScreenFini (pScreen); +#endif + +#ifdef RANDR + dmxBERRScreenFini (pScreen); +#endif + + /* Save all relevant state (TODO) */ + + /* Free all non-window resources related to this screen */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEDestroyResources, + (pointer)idx); + + /* Free scratch GCs */ + dmxBEDestroyScratchGCs(idx); + + /* Free window resources related to this screen */ + dmxBEDestroyWindowTree(idx); + + /* Free default stipple */ + dmxBESavePixmap(pScreen->PixmapPerDepth[0]); + dmxBEFreePixmap(pScreen->PixmapPerDepth[0]); + + if (pScreen->pScratchPixmap) + dmxBEFreePixmap(pScreen->pScratchPixmap); + + /* Free the remaining screen resources and close the screen */ + dmxBECloseScreen(pScreen); + + /* Screen is now disabled */ + dmxScreen->beDisplay = NULL; + + /* Make sure we don't have any pending sync replies */ + dmxScreenSyncReply (pScreen, 0, NULL, NULL, 0); + +#ifdef RANDR + RRGetInfo (screenInfo.screens[0]); +#endif + +} + /** Detach back-end screen. */ int dmxDetachScreen(int idx) { - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - int i; + DMXScreenInfo *dmxScreen; /* Return failure if dynamic addition/removal of screens is disabled */ if (!dmxAddRemoveScreens) { @@ -1584,8 +2095,17 @@ int dmxDetachScreen(int idx) /* Cannot remove a screen that does not exist */ if (idx < 0 || idx >= dmxNumScreens) return 1; + dmxScreen = &dmxScreens[idx]; + + if (idx == 0) { + dmxLog(dmxWarning, + "Attempting to remove screen #%d\n", + idx); + return 1; + } + /* Cannot detach from a screen that is not opened */ - if (!dmxScreen->beDisplay) { + if (!dmxScreen->beAttachedDisplay && !dmxScreen->beDisplay) { dmxLog(dmxWarning, "Attempting to remove screen #%d but it has not been opened\n", idx); @@ -1594,32 +2114,60 @@ int dmxDetachScreen(int idx) dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx); - /* Detach input */ - dmxInputDetachAll(dmxScreen); + if (dmxScreen->beDisplay) + dmxDisableScreen (idx); - /* Save all relevant state (TODO) */ + /* Detach input */ + dmxInputDetach (&dmxScreen->input); + + dmxScreen->beDisplay = dmxScreen->beAttachedDisplay; + dmxCloseDisplay (dmxScreen); + + dmxScreen->beAttachedDisplay = NULL; + dmxScreen->beDisplay = NULL; + + dmxScreen->scrnWidth = 1; + dmxScreen->scrnHeight = 1; + dmxScreen->rootX = 0; + dmxScreen->rootY = 0; + dmxScreen->beWidth = 1; + dmxScreen->beHeight = 1; + dmxScreen->beXDPI = 75; + dmxScreen->beYDPI = 75; + dmxScreen->beDepth = 24; + dmxScreen->beBPP = 32; + + if (dmxScreen->name) + { + free (dmxScreen->name); + dmxScreen->name = NULL; + } - /* Free all non-window resources related to this screen */ - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindAllClientResources(clients[i], dmxBEDestroyResources, - (pointer)idx); + if (dmxScreen->display) + { + free (dmxScreen->display); + dmxScreen->display = NULL; + } - /* Free scratch GCs */ - dmxBEDestroyScratchGCs(idx); + if (dmxScreen->authType) + { + free (dmxScreen->authType); + dmxScreen->authType = NULL; + } - /* Free window resources related to this screen */ - dmxBEDestroyWindowTree(idx); + dmxScreen->authTypeLen = 0; - /* Free default stipple */ - dmxBESavePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); - dmxBEFreePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + if (dmxScreen->authData) + { + free (dmxScreen->authData); + dmxScreen->authData = NULL; + } - /* Free the remaining screen resources and close the screen */ - dmxBECloseScreen(screenInfo.screens[idx]); + dmxScreen->authDataLen = 0; - /* Adjust the cursor boundaries (paints detached console window) */ - dmxAdjustCursorBoundaries(); +#ifdef RANDR + RRGetInfo (screenInfo.screens[0]); +#endif return 0; /* Success */ } diff --git a/hw/dmx/dmxextension.h b/hw/dmx/dmxextension.h index 342d8c5..c1cbc39 100644 --- a/hw/dmx/dmxextension.h +++ b/hw/dmx/dmxextension.h @@ -42,6 +42,7 @@ /** Screen attributes. Used by #ProcDMXGetScreenAttributes and * #ProcDMXChangeScreenAttributes. */ typedef struct { + const char *name; const char *displayName; int logicalScreen; @@ -95,6 +96,8 @@ extern Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr); extern Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr); +extern Bool dmxGetDrawableAttributes(DrawablePtr pDraw, + DMXWindowAttributesPtr attr); extern void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr); extern int dmxGetInputCount(void); extern int dmxGetInputAttributes(int deviceId, @@ -113,6 +116,24 @@ extern int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs); extern void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h); -extern int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr); + +typedef void (*dmxErrorSetProcPtr) (void *error, + const char *name, + const char *format, + ...); + +extern void dmxEnableScreen(int idx); +extern void dmxDisableScreen(int idx); + +extern int dmxAttachScreen (int idx, + DMXScreenAttributesPtr attr, + unsigned int window, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen, + dmxErrorSetProcPtr errorSet, + void *error, + const char *errorName); extern int dmxDetachScreen(int idx); #endif diff --git a/hw/dmx/dmxfont.c b/hw/dmx/dmxfont.c index b70f7d2..f7d7d77 100644 --- a/hw/dmx/dmxfont.c +++ b/hw/dmx/dmxfont.c @@ -38,8 +38,6 @@ #include <dmx-config.h> #endif -#define DMX_FONTPATH_DEBUG 0 - #include "dmx.h" #include "dmxsync.h" #include "dmxfont.h" @@ -49,202 +47,6 @@ #include "dixfont.h" #include "dixstruct.h" -static int (*dmxSaveProcVector[256])(ClientPtr); -static int dmxFontLastError; - -static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev) -{ - dmxFontLastError = ev->error_code; - - return 0; -} - -static char **dmxGetFontPath(int *npaths) -{ - char **fp; - unsigned char *c, *paths; - char *newfp; - int len, l, i; - - GetFontPath(serverClient, npaths, &len, &paths); - - newfp = xalloc(*npaths + len); - c = (unsigned char *)newfp; - fp = xalloc(*npaths * sizeof(*fp)); - - memmove(newfp, paths+1, *npaths + len - 1); - l = *paths; - for (i = 0; i < *npaths; i++) { - fp[i] = (char *)c; - c += l; - l = *c; - *c++ = '\0'; - } - -#if DMX_FONTPATH_DEBUG - for (i = 0; i < *npaths; i++) - dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]); -#endif - - return fp; -} - -static void dmxFreeFontPath(char **fp) -{ - xfree(fp[0]); - xfree(fp); -} - -static Bool dmxCheckFontPathElement(DMXScreenInfo *dmxScreen, char *fp) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - - if (!dmxScreen->beDisplay) - return TRUE; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, &fp, 1); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - return (dmxFontLastError == 0); -} - -static int dmxSetFontPath(DMXScreenInfo *dmxScreen) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - char **fp; - int result = Success; - int npaths; - - if (!dmxScreen->beDisplay) - return result; - - fp = dmxGetFontPath(&npaths); - if (!fp) return BadAlloc; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, fp, npaths); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - if (dmxFontLastError) { - result = dmxFontLastError; - /* We could set *error here to the offending path, but it is - * ignored, so we don't bother figuring out which path is bad. - * If we do add this support in the future, we'll need to add - * error to the function's argument list. - */ - } - - dmxFreeFontPath(fp); - - return result; -} - -static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error) -{ - char **oldFontPath; - int nOldPaths; - int result = Success; - - if (!dmxScreen->beDisplay) - return result; - - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - result = dmxSetFontPath(dmxScreen); - - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); - dmxSync(dmxScreen, FALSE); - - return result; -} - -static int dmxProcSetFontPath(ClientPtr client) -{ - unsigned char *ptr; - unsigned long nbytes, total, n; - long nfonts; - int i, result; - int error; - unsigned char *oldFontPath, *tmpFontPath; - int nOldPaths; - int lenOldPaths; - REQUEST(xSetFontPathReq); - - REQUEST_AT_LEAST_SIZE(xSetFontPathReq); - - nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); - total = nbytes; - ptr = (unsigned char *)&stuff[1]; - nfonts = stuff->nFonts; - - while (--nfonts >= 0) { - if ((total == 0) || (total < (n = (*ptr + 1)))) - return BadLength; - total -= n; - ptr += n; - } - if (total >= 4) - return BadLength; - - GetFontPath(serverClient, &nOldPaths, &lenOldPaths, &tmpFontPath); - oldFontPath = xalloc(nOldPaths + lenOldPaths); - memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths); - - result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1], - &error); - if (!result) { - for (i = 0; i < dmxNumScreens; i++) - if ((result = dmxCheckFontPath(&dmxScreens[i], &error))) - break; - - if (result) { - int ignoreresult, ignoreerror; - - /* Restore old fontpath in the DMX server */ - ignoreresult = SetFontPath(client, nOldPaths, oldFontPath, - &ignoreerror); - } else { - result = client->noClientException; - client->errorValue = error; - } - } - - xfree(oldFontPath); - return result; -} - -/** Initialize font support. In addition to the screen function call - * pointers, DMX also hooks in at the ProcVector[] level. Here the old - * ProcVector function pointers are saved and the new ProcVector - * function pointers are initialized. */ -void dmxInitFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - dmxSaveProcVector[i] = ProcVector[i]; - - ProcVector[X_SetFontPath] = dmxProcSetFontPath; -} - -/** Reset font support by restoring the original ProcVector function - * pointers. */ -void dmxResetFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - ProcVector[i] = dmxSaveProcVector[i]; -} - /** Load the font, \a pFont, on the back-end server associated with \a * pScreen. When a font is loaded, the font path on back-end server is * first initialized to that specified on the command line with the @@ -254,8 +56,6 @@ Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); char *name; - char **oldFontPath = NULL; - int nOldPaths; Atom name_atom, value_atom; int i; @@ -268,141 +68,6 @@ Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) return TRUE; /* Already loaded font */ } - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - /* Set the font path for the font about to be loaded on the back-end */ - if (dmxSetFontPath(dmxScreen)) { - char **fp; - int npaths; - Bool *goodfps; - - /* This could fail only when first starting the X server and - * loading the default font. If it fails here, then the default - * font path is invalid, no default font path will be set, the - * DMX server will fail to load the default font, and it will - * exit with an error unless we remove the offending font paths - * with the -ignorebadfontpaths command line option. - */ - - fp = dmxGetFontPath(&npaths); - if (!fp) { - dmxLog(dmxError, - "No default font path set.\n"); - dmxLog(dmxError, - "Please see the Xdmx man page for information on how to\n"); - dmxLog(dmxError, - "initialize the DMX server's default font path.\n"); - XFreeFontPath(oldFontPath); - return FALSE; - } - - if (!dmxFontPath) - dmxLog(dmxWarning, "No default font path is set.\n"); - - goodfps = xalloc(npaths * sizeof(*goodfps)); - - dmxLog(dmxError, - "The DMX server failed to set the following font paths on " - "screen #%d:\n", pScreen->myNum); - - for (i = 0; i < npaths; i++) - if (!(goodfps[i] = dmxCheckFontPathElement(dmxScreen, fp[i]))) - dmxLog(dmxError, " %s\n", fp[i]); - - if (dmxIgnoreBadFontPaths) { - char *newfp; - int newnpaths = 0; - int len = 0; - int j = 0; - int error; - - dmxLog(dmxError, - "These font paths will not be used because the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "option is set.\n"); - - for (i = 0; i < npaths; i++) - if (goodfps[i]) { - len += strlen(fp[i]) + 1; - newnpaths++; - } - - if (!newnpaths) { - /* No valid font paths were found */ - dmxLog(dmxError, - "After removing the font paths above, no valid font " - "paths were\n"); - dmxLog(dmxError, - "available. Please check that the font paths set on " - "the command\n"); - dmxLog(dmxError, - "line or in the configuration file via the " - "\"-fontpath\" option\n"); - dmxLog(dmxError, - "are valid on all back-end servers. See the Xdmx man " - "page for\n"); - dmxLog(dmxError, - "more information on font paths.\n"); - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - - newfp = xalloc(len * sizeof(*newfp)); - for (i = 0; i < npaths; i++) { - if (goodfps[i]) { - int n = strlen(fp[i]); - newfp[j++] = n; - strncpy(&newfp[j], fp[i], n); - j += n; - } - } - - if (SetFontPath(serverClient, newnpaths, (unsigned char *)newfp, - &error)) { - /* Note that this should never happen since all of the - * FPEs were previously valid. */ - dmxLog(dmxError, "Cannot reset the default font path.\n"); - } - } else if (dmxFontPath) { - dmxLog(dmxError, - "Please remove these font paths from the command line " - "or\n"); - dmxLog(dmxError, - "configuration file, or set the \"-ignorebadfontpaths\" " - "option to\n"); - dmxLog(dmxError, - "ignore them. For more information on these options, see " - "the\n"); - dmxLog(dmxError, - "Xdmx man page.\n"); - } else { - dmxLog(dmxError, - "Please specify the font paths that are available on all " - "back-end\n"); - dmxLog(dmxError, - "servers with the \"-fontpath\" option, or use the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "to ignore bad defaults. For more information on " - "these and other\n"); - dmxLog(dmxError, - "font-path-related options, see the Xdmx man page.\n"); - } - - if (!dmxIgnoreBadFontPaths || - (dmxIgnoreBadFontPaths && dmxSetFontPath(dmxScreen))) { - /* We still have errors so return with error */ - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - } - /* Find requested font on back-end server */ name_atom = MakeAtom("FONT", 4, TRUE); value_atom = 0L; @@ -418,12 +83,13 @@ Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) name = (char *)NameForAtom(value_atom); if (!name) return FALSE; - pFontPriv->font[pScreen->myNum] = + pFontPriv->font[pScreen->myNum] = None; + + XLIB_PROLOGUE (dmxScreen); + pFontPriv->font[pScreen->myNum] = XLoadQueryFont(dmxScreen->beDisplay, name); + XLIB_EPILOGUE (dmxScreen); - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); dmxSync(dmxScreen, FALSE); if (!pFontPriv->font[pScreen->myNum]) return FALSE; @@ -472,7 +138,9 @@ Bool dmxBEFreeFont(ScreenPtr pScreen, FontPtr pFont) dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); if (pFontPriv && pFontPriv->font[pScreen->myNum]) { + XLIB_PROLOGUE (dmxScreen); XFreeFont(dmxScreen->beDisplay, pFontPriv->font[pScreen->myNum]); + XLIB_EPILOGUE (dmxScreen); pFontPriv->font[pScreen->myNum] = NULL; return TRUE; } diff --git a/hw/dmx/dmxfont.h b/hw/dmx/dmxfont.h index 086e71b..70195ec 100644 --- a/hw/dmx/dmxfont.h +++ b/hw/dmx/dmxfont.h @@ -45,9 +45,6 @@ typedef struct _dmxFontPriv { XFontStruct **font; } dmxFontPrivRec, *dmxFontPrivPtr; -extern void dmxInitFonts(void); -extern void dmxResetFonts(void); - extern Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont); extern Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont); diff --git a/hw/dmx/dmxgc.c b/hw/dmx/dmxgc.c index eb21d3c..0d3524a 100644 --- a/hw/dmx/dmxgc.c +++ b/hw/dmx/dmxgc.c @@ -60,8 +60,8 @@ static GCFuncs dmxGCFuncs = { }; static GCOps dmxGCOps = { - dmxFillSpans, - dmxSetSpans, + NULL, /* dmxFillSpans */ + NULL, /* dmxSetSpans */ dmxPutImage, dmxCopyArea, dmxCopyPlane, @@ -77,8 +77,8 @@ static GCOps dmxGCOps = { dmxPolyText16, dmxImageText8, dmxImageText16, - dmxImageGlyphBlt, - dmxPolyGlyphBlt, + NULL, /* dmxImageGlyphBlt */ + NULL, /* dmxPolyGlyphBlt */ dmxPushPixels }; @@ -106,9 +106,13 @@ void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) gcvals.graphics_exposures = FALSE; /* Create GC in the back-end servers */ + pGCPriv->gc = None; + + XLIB_PROLOGUE (dmxScreen); pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], mask, &gcvals); + XLIB_EPILOGUE (dmxScreen); break; } } @@ -275,14 +279,20 @@ void dmxChangeGC(GCPtr pGC, unsigned long mask) if (mask & GCDashList) { mask &= ~GCDashList; if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, pGC->dashOffset, (char *)pGC->dash, pGC->numInDashList); + XLIB_EPILOGUE (dmxScreen); + } } if (mask & GCArcMode) v.arc_mode = pGC->arcMode; if (mask && dmxScreen->beDisplay) { + XLIB_PROLOGUE (dmxScreen); XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -303,7 +313,11 @@ void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) /* Copy the GC on the back-end server */ if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); + XLIB_EPILOGUE (dmxScreen); + } DMX_GC_FUNC_EPILOGUE(pGCDst); } @@ -316,7 +330,9 @@ Bool dmxBEFreeGC(GCPtr pGC) dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); if (pGCPriv->gc) { + XLIB_PROLOGUE (dmxScreen); XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); + XLIB_EPILOGUE (dmxScreen); pGCPriv->gc = NULL; return TRUE; } @@ -358,7 +374,11 @@ void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) switch (pGC->clientClipType) { case CT_NONE: if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + XLIB_EPILOGUE (dmxScreen); + } break; case CT_REGION: @@ -374,20 +394,18 @@ void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) pRects[i].height = pBox[i].y2 - pBox[i].y1; } + XLIB_PROLOGUE (dmxScreen); XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, pGC->clipOrg.x, pGC->clipOrg.y, pRects, nRects, Unsorted); + XLIB_EPILOGUE (dmxScreen); xfree(pRects); } break; - case CT_PIXMAP: - case CT_UNSORTED: - case CT_YSORTED: - case CT_YXSORTED: - case CT_YXBANDED: - /* These clip types are condensed down to either NONE or REGION + default: + /* Other clip types are condensed down to either NONE or REGION in the mi code */ break; } @@ -407,7 +425,11 @@ void dmxDestroyClip(GCPtr pGC) /* Set the client clip on the back-end server to None */ if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + XLIB_EPILOGUE (dmxScreen); + } DMX_GC_FUNC_EPILOGUE(pGC); } diff --git a/hw/dmx/dmxgcops.c b/hw/dmx/dmxgcops.c index eaabf16..3499c86 100644 --- a/hw/dmx/dmxgcops.c +++ b/hw/dmx/dmxgcops.c @@ -44,6 +44,7 @@ #include "dmxgcops.h" #include "dmxwindow.h" #include "dmxpixmap.h" +#include "dmxlog.h" #include "mi.h" #include "gcstruct.h" @@ -52,6 +53,13 @@ #include "panoramiXsrv.h" +#include <xcb/xcb_image.h> + +/* hm, conflicting definition of xcb_popcount in xcbext.h and xcb_bitops.h */ +#define xcb_popcount xcb_popcount2 +#include <xcb/xcb_bitops.h> +#undef xcb_popcount + #define DMX_GCOPS_SET_DRAWABLE(_pDraw, _draw) \ do { \ if ((_pDraw)->type == DRAWABLE_WINDOW) { \ @@ -67,26 +75,11 @@ do { \ #define DMX_GCOPS_OFFSCREEN(_pDraw) \ (!dmxScreens[(_pDraw)->pScreen->myNum].beDisplay || \ - (dmxOffScreenOpt && \ - (_pDraw)->type == DRAWABLE_WINDOW && \ - (DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->offscreen || \ - !DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->window))) - -/** Fill spans -- this function should never be called. */ -void dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC, - int nInit, DDXPointPtr pptInit, int *pwidthInit, - int fSorted) -{ - /* Error -- this should never happen! */ -} - -/** Set spans -- this function should never be called. */ -void dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC, - char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, - int fSorted) -{ - /* Error -- this should never happen! */ -} + (((_pDraw)->type == DRAWABLE_WINDOW) ? \ + ((!DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->window || \ + (dmxOffScreenOpt && \ + DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->offscreen))) : \ + (!(DMX_GET_PIXMAP_PRIV((PixmapPtr)(_pDraw)))->pixmap))) /** Transfer \a pBits image to back-end server associated with \a * pDrawable's screen. If primitive subdivision optimization is @@ -98,16 +91,18 @@ void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC, { DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum]; dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XImage *img; + XImage *img = NULL; if (DMX_GCOPS_OFFSCREEN(pDrawable)) return; + XLIB_PROLOGUE (dmxScreen); img = XCreateImage(dmxScreen->beDisplay, dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, depth, format, leftPad, pBits, w, h, BitmapPad(dmxScreen->beDisplay), (format == ZPixmap) ? PixmapBytePad(w, depth) : BitmapBytePad(w+leftPad)); + XLIB_EPILOGUE (dmxScreen); if (img) { Drawable draw; @@ -136,6 +131,7 @@ void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC, nBox = REGION_NUM_RECTS(pSubImages); pBox = REGION_RECTS(pSubImages); + XLIB_PROLOGUE (dmxScreen); while (nBox--) { XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc, img, pBox->x1 - box.x1, @@ -146,11 +142,14 @@ void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC, pBox->y2 - pBox->y1); pBox++; } + XLIB_EPILOGUE (dmxScreen); REGION_DESTROY(pGC->pScreen, pClip); REGION_DESTROY(pGC->pScreen, pSubImages); } else { + XLIB_PROLOGUE (dmxScreen); XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc, img, 0, 0, x, y, w, h); + XLIB_EPILOGUE (dmxScreen); } XFree(img); /* Use XFree instead of XDestroyImage * because pBits is passed in from the @@ -159,6 +158,7 @@ void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC, dmxSync(dmxScreen, FALSE); } else { /* Error -- this should not happen! */ + FatalError ("XCreateImage failed\n"); } } @@ -180,8 +180,10 @@ RegionPtr dmxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw); DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw); + XLIB_PROLOGUE (dmxScreen); XCopyArea(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc, srcx, srcy, w, h, dstx, dsty); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, @@ -207,8 +209,10 @@ RegionPtr dmxCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw); DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw); + XLIB_PROLOGUE (dmxScreen); XCopyPlane(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc, srcx, srcy, width, height, dstx, dsty, bitPlane); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, width, height, @@ -230,8 +234,10 @@ void dmxPolyPoint(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawPoints(dmxScreen->beDisplay, draw, pGCPriv->gc, (XPoint *)pptInit, npt, mode); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -250,8 +256,10 @@ void dmxPolylines(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawLines(dmxScreen->beDisplay, draw, pGCPriv->gc, (XPoint *)pptInit, npt, mode); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -270,8 +278,10 @@ void dmxPolySegment(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawSegments(dmxScreen->beDisplay, draw, pGCPriv->gc, (XSegment *)pSegs, nseg); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -290,8 +300,10 @@ void dmxPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc, (XRectangle *)pRects, nrects); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -311,8 +323,10 @@ void dmxPolyArc(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawArcs(dmxScreen->beDisplay, draw, pGCPriv->gc, (XArc *)parcs, narcs); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -331,8 +345,10 @@ void dmxFillPolygon(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XFillPolygon(dmxScreen->beDisplay, draw, pGCPriv->gc, (XPoint *)pPts, count, shape, mode); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -351,8 +367,10 @@ void dmxPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XFillRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc, (XRectangle *)prectInit, nrectFill); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -371,8 +389,10 @@ void dmxPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XFillArcs(dmxScreen->beDisplay, draw, pGCPriv->gc, (XArc *)parcs, narcs); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -400,8 +420,10 @@ int dmxPolyText8(DrawablePtr pDrawable, GCPtr pGC, if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) { DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawString(dmxScreen->beDisplay, draw, pGCPriv->gc, x, y, chars, count); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -433,8 +455,10 @@ int dmxPolyText16(DrawablePtr pDrawable, GCPtr pGC, if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) { DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawString16(dmxScreen->beDisplay, draw, pGCPriv->gc, x, y, (XChar2b *)chars, count); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -456,8 +480,10 @@ void dmxImageText8(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawImageString(dmxScreen->beDisplay, draw, pGCPriv->gc, x, y, chars, count); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -476,71 +502,110 @@ void dmxImageText16(DrawablePtr pDrawable, GCPtr pGC, DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); + XLIB_PROLOGUE (dmxScreen); XDrawImageString16(dmxScreen->beDisplay, draw, pGCPriv->gc, x, y, (XChar2b *)chars, count); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } -/** Image Glyph Blt -- this function should never be called. */ -void dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) -{ - /* Error -- this should never happen! */ -} - -/** Poly Glyph Blt -- this function should never be called. */ -void dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase) +void dmxPushPixels(GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDst, + int width, int height, int x, int y) { - /* Error -- this should never happen! */ -} - -/** Push Pixels -- this function should never be called. */ -void dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, - int w, int h, int x, int y) -{ - /* Error -- this should never happen! */ + /* only works for solid bitmaps */ + if (pGC->fillStyle == FillSolid) + { + DMXScreenInfo *dmxScreen = &dmxScreens[pDst->pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pBitmap); + Drawable draw; + + if (DMX_GCOPS_OFFSCREEN(pDst)) return; + + DMX_GCOPS_SET_DRAWABLE(pDst, draw); + + XLIB_PROLOGUE (dmxScreen); + XSetStipple (dmxScreen->beDisplay, pGCPriv->gc, pPixPriv->pixmap); + XSetTSOrigin (dmxScreen->beDisplay, pGCPriv->gc, x, y); + XSetFillStyle (dmxScreen->beDisplay, pGCPriv->gc, FillStippled); + XFillRectangle (dmxScreen->beDisplay, draw, + pGCPriv->gc, x, y, width, height); + XSetFillStyle (dmxScreen->beDisplay, pGCPriv->gc, FillSolid); + XLIB_EPILOGUE (dmxScreen); + dmxSync(dmxScreen, FALSE); + } + else + { + dmxLog (dmxWarning, "function dmxPushPixels fillStyle != FillSolid " + "not implemented\n"); + } } /********************************************************************** * Miscellaneous drawing commands */ -/** When Xinerama is active, the client pixmaps are always obtained from - * screen 0. When screen 0 is detached, the pixmaps must be obtained - * from any other screen that is not detached. Usually, this is screen - * 1. */ -static DMXScreenInfo *dmxFindAlternatePixmap(DrawablePtr pDrawable, XID *draw) +static DMXScreenInfo * +dmxGetAlternateWindow (DrawablePtr pDrawable, + int i, + XID *draw) { + +#ifdef PANORAMIX + PanoramiXRes *pXinWin; + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (noPanoramiXExtension) return NULL; + if (!dmxScreen->beDisplay) return NULL; + + if ((pXinWin = (PanoramiXRes *) LookupIDByType (pDrawable->id, + XRT_WINDOW))) + { + WindowPtr pSrc; + dmxWinPrivPtr pSrcPriv; + + pSrc = (WindowPtr) LookupIDByType (pXinWin->info[i].id, RT_WINDOW); + pSrcPriv = DMX_GET_WINDOW_PRIV (pSrc); + if (pSrcPriv->window) + { + *draw = pSrcPriv->window; + return dmxScreen; + } + } +#endif + + return NULL; +} + +static DMXScreenInfo * +dmxGetAlternatePixmap (DrawablePtr pDrawable, + int i, + XID *draw) +{ + #ifdef PANORAMIX PanoramiXRes *pXinPix; - int i; - DMXScreenInfo *dmxScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (noPanoramiXExtension) return NULL; - if (pDrawable->type != DRAWABLE_PIXMAP) return NULL; + if (noPanoramiXExtension) return NULL; + if (!dmxScreen->beDisplay) return NULL; - if (!(pXinPix = (PanoramiXRes *)LookupIDByType(pDrawable->id, XRT_PIXMAP))) - return NULL; - - for (i = 1; i < PanoramiXNumScreens; i++) { - dmxScreen = &dmxScreens[i]; - if (dmxScreen->beDisplay) { - PixmapPtr pSrc; - dmxPixPrivPtr pSrcPriv; + if ((pXinPix = (PanoramiXRes *) LookupIDByType (pDrawable->id, + XRT_PIXMAP))) + { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv; - pSrc = (PixmapPtr)LookupIDByType(pXinPix->info[i].id, - RT_PIXMAP); - pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); - if (pSrcPriv->pixmap) { - *draw = pSrcPriv->pixmap; - return dmxScreen; - } - } + pSrc = (PixmapPtr) LookupIDByType (pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV (pSrc); + if (pSrcPriv->pixmap) + { + *draw = pSrcPriv->pixmap; + return dmxScreen; + } } #endif + return NULL; } @@ -553,8 +618,8 @@ void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, unsigned int format, unsigned long planeMask, char *pdstLine) { DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum]; - XImage *img; - Drawable draw; + Drawable draw; + int i = 0; /* Cannot get image from unviewable window */ if (pDrawable->type == DRAWABLE_WINDOW) { @@ -569,33 +634,90 @@ void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, return; } } - DMX_GCOPS_SET_DRAWABLE(&pWindow->drawable, draw); + DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); if (DMX_GCOPS_OFFSCREEN(&pWindow->drawable)) - return; + draw = None; } else { DMX_GCOPS_SET_DRAWABLE(pDrawable, draw); - if (DMX_GCOPS_OFFSCREEN(pDrawable)) { - /* Try to find the pixmap on a non-detached Xinerama screen */ - dmxScreen = dmxFindAlternatePixmap(pDrawable, &draw); - if (!dmxScreen) return; - } + if (DMX_GCOPS_OFFSCREEN(pDrawable)) + draw = None; } + + while (i < dmxNumScreens) + { + xcb_get_image_reply_t *reply; + + if (!draw) + { + if (pDrawable->type == DRAWABLE_WINDOW) + dmxScreen = dmxGetAlternateWindow (pDrawable, i++, &draw); + else + dmxScreen = dmxGetAlternatePixmap (pDrawable, i++, &draw); + + if (!dmxScreen) continue; + } - img = XGetImage(dmxScreen->beDisplay, draw, - sx, sy, w, h, planeMask, format); - if (img) { - int len = img->bytes_per_line * img->height; - memmove(pdstLine, img->data, len); - XDestroyImage(img); - } + reply = xcb_get_image_reply (dmxScreen->connection, + xcb_get_image (dmxScreen->connection, + format, + draw, + sx, sy, w, h, + planeMask), + NULL); + if (reply) + { + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + uint32_t bytes = xcb_get_image_data_length (reply); + uint8_t *data = xcb_get_image_data (reply); + + /* based on code in xcb_image.c, Copyright (C) 2007 Bart Massey */ + switch (format) { + case XCB_IMAGE_FORMAT_XY_PIXMAP: + planeMask &= xcb_mask (reply->depth); + if (planeMask != xcb_mask (reply->depth)) + { + uint32_t rpm = planeMask; + uint8_t *src_plane = data; + uint8_t *dst_plane = (uint8_t *) pdstLine; + uint32_t scanline_pad = setup->bitmap_format_scanline_pad; + uint32_t stride = xcb_roundup (w, scanline_pad) >> 3; + uint32_t size = h * stride; + int i; + + if (setup->image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST) + rpm = xcb_bit_reverse (planeMask, reply->depth); + + for (i = 0; i < reply->depth; i++) + { + if (rpm & 1) + { + memcpy (dst_plane, src_plane, size); + src_plane += size; + } + else + { + memset (dst_plane, 0, size); + } + + dst_plane += size; + } + break; + } + + /* fall through */ + case XCB_IMAGE_FORMAT_Z_PIXMAP: + memmove (pdstLine, data, bytes); + default: + break; + } - dmxSync(dmxScreen, FALSE); -} + free (reply); + break; + } -/** Get Spans -- this function should never be called. */ -void dmxGetSpans(DrawablePtr pDrawable, int wMax, - DDXPointPtr ppt, int *pwidth, int nspans, - char *pdstStart) -{ - /* Error -- this should never happen! */ + if (pDrawable->type != DRAWABLE_WINDOW) + break; + + draw = None; + } } diff --git a/hw/dmx/dmxgcops.h b/hw/dmx/dmxgcops.h index da14d4d..ceb1524 100644 --- a/hw/dmx/dmxgcops.h +++ b/hw/dmx/dmxgcops.h @@ -37,12 +37,6 @@ #ifndef DMXGCOPS_H #define DMXGCOPS_H -extern void dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC, - int nInit, DDXPointPtr pptInit, int *pwidthInit, - int fSorted); -extern void dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC, - char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, - int fSorted); extern void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *pBits); @@ -76,20 +70,11 @@ extern void dmxImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars); extern void dmxImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars); -extern void dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); -extern void dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, unsigned int nglyph, - CharInfoPtr *ppci, pointer pglyphBase); -extern void dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, - int w, int h, int x, int y); +extern void dmxPushPixels(GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, + int width, int height, int x, int y); extern void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, unsigned int format, unsigned long planeMask, char *pdstLine); -extern void dmxGetSpans(DrawablePtr pDrawable, int wMax, - DDXPointPtr ppt, int *pwidth, int nspans, - char *pdstStart); #endif /* DMXGCOPS_H */ diff --git a/hw/dmx/dmxgrab.c b/hw/dmx/dmxgrab.c new file mode 100644 index 0000000..297ea31 --- /dev/null +++ b/hw/dmx/dmxgrab.c @@ -0,0 +1,392 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxinput.h" +#include "dmxgrab.h" + +#include "windowstr.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +static int (*dmxSaveProcVector[256]) (ClientPtr); + +static void +dmxGrabKeyboard (DeviceIntPtr pDev, + GrabPtr pGrab) +{ + +#ifdef PANORAMIX + PanoramiXRes *win = NULL; +#endif + + WindowPtr pWin; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *)SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + } +#endif + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess); + } + else +#endif + + { + pWin = pGrab->window; + if (i != pWin->drawable.pScreen->myNum) + continue; + } + + dmxInputGrabKeyboard (&dmxScreen->input, pDev, pWin); + } +} + +static void +dmxUngrabKeyboard (DeviceIntPtr pDev, + GrabPtr pGrab) +{ + +#ifdef PANORAMIX + PanoramiXRes *win = NULL; +#endif + + WindowPtr pWin; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *)SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + } +#endif + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess); + } + else +#endif + + { + pWin = pGrab->window; + if (i != pWin->drawable.pScreen->myNum) + continue; + } + + dmxInputUngrabKeyboard (&dmxScreen->input, pDev, pWin); + } +} + +void +dmxActivateKeyboardGrab (DeviceIntPtr pDev, + GrabPtr pGrab, + TimeStamp time, + Bool autoGrab) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + dmxGrabKeyboard (pDev, pGrab); + + DMX_UNWRAP (ActivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.ActivateGrab) (pDev, pGrab, time, autoGrab); + DMX_WRAP (ActivateGrab, dmxActivateKeyboardGrab, pDevPriv, + &pDev->deviceGrab); +} + +void +dmxDeactivateKeyboardGrab (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + GrabPtr pGrab = pDev->deviceGrab.grab; + + /* DeactivateGrab might call ActivateGrab so make sure we ungrab here */ + dmxUngrabKeyboard (pDev, pGrab); + + DMX_UNWRAP (DeactivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.DeactivateGrab) (pDev); + DMX_WRAP (DeactivateGrab, dmxDeactivateKeyboardGrab, pDevPriv, + &pDev->deviceGrab); +} + +static void +dmxGrabPointer (DeviceIntPtr pDev, + GrabPtr pGrab) +{ + +#ifdef PANORAMIX + PanoramiXRes *win = NULL, *confineToWin = NULL; +#endif + + WindowPtr pWin, pConfineTo = NULL; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *)SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + if (pGrab->confineTo) + if (!(confineToWin = (PanoramiXRes *)SecurityLookupIDByType( + serverClient, pGrab->confineTo->drawable.id, + XRT_WINDOW, DixGetAttrAccess))) + return; + } +#endif + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess); + if (confineToWin) + dixLookupWindow (&pConfineTo, + confineToWin->info[i].id, + serverClient, + DixGetAttrAccess); + } + else +#endif + + { + pWin = pGrab->window; + if (i != pWin->drawable.pScreen->myNum) + continue; + } + + dmxInputGrabPointer (&dmxScreen->input, + pDev, + pWin, + pConfineTo, + pGrab->cursor); + } +} + +static void +dmxUngrabPointer (DeviceIntPtr pDev, + GrabPtr pGrab) +{ + +#ifdef PANORAMIX + PanoramiXRes *win = NULL; +#endif + + WindowPtr pWin; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *)SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + } +#endif + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess); + } + else +#endif + + { + pWin = pGrab->window; + if (i != pWin->drawable.pScreen->myNum) + continue; + } + + dmxInputUngrabPointer (&dmxScreen->input, pDev, pWin); + } +} + +void +dmxActivatePointerGrab (DeviceIntPtr pDev, + GrabPtr pGrab, + TimeStamp time, + Bool autoGrab) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + dmxGrabPointer (pDev, pGrab); + + DMX_UNWRAP (ActivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.ActivateGrab) (pDev, pGrab, time, autoGrab); + DMX_WRAP (ActivateGrab, dmxActivatePointerGrab, pDevPriv, + &pDev->deviceGrab); +} + +void +dmxDeactivatePointerGrab (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + GrabPtr pGrab = pDev->deviceGrab.grab; + + /* DeactivateGrab might call ActivateGrab so make sure we ungrab here */ + dmxUngrabPointer (pDev, pGrab); + + DMX_UNWRAP (DeactivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.DeactivateGrab) (pDev); + DMX_WRAP (DeactivateGrab, dmxDeactivatePointerGrab, pDevPriv, + &pDev->deviceGrab); +} + +Bool +dmxActivateFakeGrab (DeviceIntPtr pDev, + GrabPtr pGrab) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + if (pDevPriv->fakeGrab) + return TRUE; + + if (pDev->deviceGrab.grab) + return FALSE; + + pDevPriv->fakeGrab = TRUE; + + DMX_UNWRAP (ActivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.ActivateGrab) (pDev, pGrab, currentTime, FALSE); + DMX_WRAP (ActivateGrab, dmxActivatePointerGrab, pDevPriv, + &pDev->deviceGrab); + + return TRUE; +} + +void +dmxDeactivateFakeGrab (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + if (!pDevPriv->fakeGrab) + return; + + pDevPriv->fakeGrab = FALSE; + + DMX_UNWRAP (DeactivateGrab, pDevPriv, &pDev->deviceGrab); + (*pDev->deviceGrab.DeactivateGrab) (pDev); + DMX_WRAP (DeactivateGrab, dmxDeactivatePointerGrab, pDevPriv, + &pDev->deviceGrab); +} + +static int +dmxProcChangeActivePointerGrab (ClientPtr client) +{ + DeviceIntPtr pDev; + GrabPtr pGrab; + int err; + + err = (*dmxSaveProcVector[X_ChangeActivePointerGrab]) (client); + if (err != Success) + return err; + + pDev = PickPointer (client); + pGrab = pDev->deviceGrab.grab; + if (pGrab) + dmxGrabPointer (pDev, pGrab); + + return Success; +} + +void dmxInitGrabs (void) +{ + int i; + + for (i = 0; i < 256; i++) + dmxSaveProcVector[i] = ProcVector[i]; + + ProcVector[X_ChangeActivePointerGrab] = dmxProcChangeActivePointerGrab; +} + +void dmxResetGrabs (void) +{ + int i; + + for (i = 0; i < 256; i++) + ProcVector[i] = dmxSaveProcVector[i]; +} diff --git a/hw/dmx/dmxgrab.h b/hw/dmx/dmxgrab.h new file mode 100644 index 0000000..fe0dc0b --- /dev/null +++ b/hw/dmx/dmxgrab.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXGRAB_H +#define DMXGRAB_H + +#include "dmxinput.h" + +extern void dmxActivateKeyboardGrab (DeviceIntPtr pDev, + GrabPtr pGrab, + TimeStamp time, + Bool autoGrab); +extern void dmxDeactivateKeyboardGrab (DeviceIntPtr pDev); + +extern void dmxActivatePointerGrab (DeviceIntPtr pDev, + GrabPtr pGrab, + TimeStamp time, + Bool autoGrab); +extern void dmxDeactivatePointerGrab (DeviceIntPtr pDev); + +extern Bool dmxActivateFakeGrab (DeviceIntPtr pDev, + GrabPtr pGrab); +extern void dmxDeactivateFakeGrab (DeviceIntPtr pDev); + +extern void dmxInitGrabs (void); +extern void dmxResetGrabs (void); + +#endif /* DMXGRAB_H */ diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c index 6a0c259..e96c2d2 100644 --- a/hw/dmx/dmxinit.c +++ b/hw/dmx/dmxinit.c @@ -49,19 +49,35 @@ #include "dmxscrinit.h" #include "dmxcursor.h" #include "dmxfont.h" -#include "config/dmxconfig.h" #include "dmxcb.h" #include "dmxprop.h" #include "dmxstat.h" +#include "dmxlaunch.h" +#include "dmxgrab.h" +#include "dmxselection.h" +#include "dmxshm.h" #ifdef RENDER #include "dmxpict.h" #endif +#ifdef COMPOSITE +#include "dmxcomp.h" +#endif +#include "dmxextension.h" #include <X11/Xos.h> /* For gettimeofday */ #include "dixstruct.h" +#include "opaque.h" #include "panoramiXsrv.h" +#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ +# include <sha1.h> +#else /* Use OpenSSL's libcrypto */ +# include <stddef.h> /* buggy openssl/sha.h wants size_t */ +# include <openssl/sha.h> +#endif + #include <signal.h> /* For SIGQUIT */ +#include <execinfo.h> #ifdef GLXEXT #include <GL/glx.h> @@ -81,21 +97,16 @@ extern void GlxSetVisualConfigs( int dmxNumScreens; DMXScreenInfo *dmxScreens; -int dmxNumInputs; -DMXInputInfo *dmxInputs; - -int dmxShadowFB = FALSE; - XErrorEvent dmxLastErrorEvent; Bool dmxErrorOccurred = FALSE; char *dmxFontPath = NULL; -Bool dmxOffScreenOpt = TRUE; +Bool dmxOffScreenOpt = FALSE; Bool dmxSubdividePrimitives = TRUE; -Bool dmxLazyWindowCreation = TRUE; +Bool dmxLazyWindowCreation = FALSE; Bool dmxUseXKB = TRUE; @@ -104,7 +115,7 @@ int dmxDepth = 0; #ifndef GLXEXT static Bool dmxGLXProxy = FALSE; #else -Bool dmxGLXProxy = TRUE; +Bool dmxGLXProxy = FALSE; Bool dmxGLXSwapGroupSupport = TRUE; @@ -115,7 +126,52 @@ Bool dmxGLXFinishSwap = FALSE; Bool dmxIgnoreBadFontPaths = FALSE; -Bool dmxAddRemoveScreens = FALSE; +Bool dmxAddRemoveScreens = TRUE; + +int dmxLaunchIndex = 0; +char *dmxLaunchVT = NULL; + +int dmxNumDetached = 4; + +#ifdef RANDR +int xRROutputsPerScreen = 1; +int xRRCrtcsPerScreen = 1; +#endif + +DMXPropTrans *dmxPropTrans = NULL; +int dmxPropTransNum = 0; + +DMXSelectionMap *dmxSelectionMap = NULL; +int dmxSelectionMapNum = 0; + +#ifdef XV +char **dmxXvImageFormats = NULL; +int dmxXvImageFormatsNum = 0; +#endif + +char dmxDigest[64]; + +#include <execinfo.h> + +static void +dmxSigHandler (int signo) +{ + void *array[64]; + size_t size, i; + char **strings; + + ErrorF ("\nBacktrace:\n"); + + size = backtrace (array, 64); + strings = backtrace_symbols (array, size); + + for (i = 0; i < size; i++) + ErrorF ("%d: %s\n", i, strings[i]); + + free (strings); + + FatalError ("Caught signal %d. Server aborting\n", signo); +} /* dmxErrorHandler catches errors that occur when calling one of the * back-end servers. Some of this code is based on _XPrintDefaultError @@ -180,6 +236,30 @@ static int dmxErrorHandler(Display *dpy, XErrorEvent *ev) ev->serial); dmxLog(dmxWarning, " Current serial number: %d\n", dpy->request); + +// abort (); + + return 0; +} + +int _dmx_jumpbuf_set = 0; +int _dmx_io_error = 0; +jmp_buf _dmx_jumpbuf; + +static int dmxIOErrorHandler (Display *dpy) +{ + _dmx_io_error++; + + if (!_dmx_jumpbuf_set) + { + ErrorF ("_dmx_jumpbuf not set\n"); + abort (); + } + else + { + longjmp (_dmx_jumpbuf, 1); + } + return 0; } @@ -190,18 +270,125 @@ static int dmxNOPErrorHandler(Display *dpy, XErrorEvent *ev) } #endif -Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) +char * +dmxMemDup (const char *data, + int dataLen) +{ + char *d; + + d = malloc (dataLen); + if (!d) + return NULL; + + memcpy (d, data, dataLen); + + return d; +} + +DMXScreenInfo * +dmxAddScreen(const char *name, + const char *display, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen, + int virtualFb) +{ + DMXScreenInfo *dmxScreen; + + if (!(dmxScreens = realloc(dmxScreens, + (dmxNumScreens+1) * sizeof(*dmxScreens)))) + dmxLog(dmxFatal, + "dmxAddScreen: realloc failed for screen %d (%s)\n", + dmxNumScreens, name); + + dmxScreen = &dmxScreens[dmxNumScreens]; + memset(dmxScreen, 0, sizeof(*dmxScreen)); + dmxScreen->name = strdup (name); + dmxScreen->display = strdup (display); + dmxScreen->index = dmxNumScreens; + dmxScreen->scrnWidth = 0; + dmxScreen->scrnHeight = 0; + dmxScreen->rootX = 0; + dmxScreen->rootY = 0; + dmxScreen->stat = dmxStatAlloc(); + dmxScreen->authType = dmxMemDup (authType, authTypeLen); + dmxScreen->authTypeLen = authTypeLen; + dmxScreen->authData = dmxMemDup (authData, authDataLen); + dmxScreen->authDataLen = authDataLen; + dmxScreen->virtualFb = virtualFb; + ++dmxNumScreens; + + return dmxScreen; +} + +Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen, + const char *display, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen) { - if (!(dmxScreen->beDisplay = XOpenDisplay(dmxScreen->name))) + dmxScreen->beDisplay = NULL; + + if (!display || !*display) return FALSE; - dmxPropertyDisplay(dmxScreen); + if (authType && *authType) + XSetAuthorization ((char *) authType, authTypeLen, + (char *) authData, authDataLen); + + dmxScreen->alive = 1; + + XLIB_PROLOGUE (dmxScreen); + dmxScreen->beDisplay = XOpenDisplay (display); + XLIB_EPILOGUE (dmxScreen); + + if (!dmxScreen->beDisplay) + { + dmxScreen->alive = 0; + return FALSE; + } + + dmxScreen->alive = 1; + dmxScreen->broken = 0; + dmxScreen->inDispatch = FALSE; + dmxScreen->fd = XConnectionNumber (dmxScreen->beDisplay); + dmxScreen->connection = XGetXCBConnection (dmxScreen->beDisplay); + + XSetEventQueueOwner (dmxScreen->beDisplay, XCBOwnsEventQueue); + + dmxScreen->sync.sequence = 0; + + AddEnabledDevice (dmxScreen->fd); + + dmxScreen->atomTable = NULL; + dmxScreen->atomTableSize = 0; + + dmxScreen->beAtomTable = NULL; + dmxScreen->beAtomTableSize = 0; + return TRUE; } +void dmxCloseDisplay(DMXScreenInfo *dmxScreen) +{ + RemoveEnabledDevice (dmxScreen->fd); + + if (dmxScreen->atomTable) + xfree (dmxScreen->atomTable); + if (dmxScreen->beAtomTable) + xfree (dmxScreen->beAtomTable); + + xcb_disconnect (dmxScreen->connection); + + dmxScreen->alive = 0; +} + void dmxSetErrorHandler(DMXScreenInfo *dmxScreen) { XSetErrorHandler(dmxErrorHandler); + XSetIOErrorHandler(dmxIOErrorHandler); } static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen) @@ -269,14 +456,6 @@ static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen) (DoesBackingStore (s) == NotUseful) ? "no" : ((DoesBackingStore (s) == Always) ? "yes" : "when mapped"), DoesSaveUnders (s) ? "yes" : "no"); - dmxLogOutput(dmxScreen, "Window Manager running: %s\n", - (dmxScreen->WMRunningOnBE) ? "yes" : "no"); - - if (dmxScreen->WMRunningOnBE) { - dmxLogOutputWarning(dmxScreen, - "Window manager running " - "-- colormaps not supported\n"); - } XFree(depths); } @@ -292,41 +471,10 @@ void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) dmxScreen->beWidth = attribs.width; dmxScreen->beHeight = attribs.height; - - /* Fill in missing geometry information */ - if (dmxScreen->scrnXSign < 0) { - if (dmxScreen->scrnWidth) { - dmxScreen->scrnX = (attribs.width - dmxScreen->scrnWidth - - dmxScreen->scrnX); - } else { - dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; - dmxScreen->scrnX = 0; - } - } - if (dmxScreen->scrnYSign < 0) { - if (dmxScreen->scrnHeight) { - dmxScreen->scrnY = (attribs.height - dmxScreen->scrnHeight - - dmxScreen->scrnY); - } else { - dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; - dmxScreen->scrnY = 0; - } - } - if (!dmxScreen->scrnWidth) - dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; - if (!dmxScreen->scrnHeight) - dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; - - if (!dmxScreen->rootWidth) dmxScreen->rootWidth = dmxScreen->scrnWidth; - if (!dmxScreen->rootHeight) dmxScreen->rootHeight = dmxScreen->scrnHeight; - if (dmxScreen->rootWidth + dmxScreen->rootX > dmxScreen->scrnWidth) - dmxScreen->rootWidth = dmxScreen->scrnWidth - dmxScreen->rootX; - if (dmxScreen->rootHeight + dmxScreen->rootY > dmxScreen->scrnHeight) - dmxScreen->rootHeight = dmxScreen->scrnHeight - dmxScreen->rootY; /* FIXME: Get these from the back-end server */ - dmxScreen->beXDPI = 75; - dmxScreen->beYDPI = 75; + dmxScreen->beXDPI = 96; + dmxScreen->beYDPI = 96; dmxScreen->beDepth = attribs.depth; /* FIXME: verify that this * works always. In @@ -340,6 +488,12 @@ void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) else if (dmxScreen->beDepth <= 16) dmxScreen->beBPP = 16; else dmxScreen->beBPP = 32; + if (dmxScreen->scrnWin != DefaultRootWindow(dpy)) + XGetWindowAttributes(dpy, dmxScreen->scrnWin, &attribs); + + dmxScreen->scrnWidth = attribs.width; + dmxScreen->scrnHeight = attribs.height; + #ifdef GLXEXT /* get the majorOpcode for the back-end GLX extension */ XQueryExtension(dpy, "GLX", &dmxScreen->glxMajorOpcode, @@ -347,9 +501,8 @@ void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) #endif dmxPrintScreenInfo(dmxScreen); - dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n", + dmxLogOutput(dmxScreen, "%dx%d on %dx%d at depth=%d, bpp=%d\n", dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, dmxScreen->beWidth, dmxScreen->beHeight, dmxScreen->beDepth, dmxScreen->beBPP); if (dmxScreen->beDepth == 8) @@ -471,38 +624,70 @@ static Bool dmxSetPixmapFormats(ScreenInfo *pScreenInfo, return TRUE; } -void dmxCheckForWM(DMXScreenInfo *dmxScreen) -{ - Status status; - XWindowAttributes xwa; - - status = XGetWindowAttributes(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - &xwa); - dmxScreen->WMRunningOnBE = - (status && - ((xwa.all_event_masks & SubstructureRedirectMask) || - (xwa.all_event_masks & SubstructureNotifyMask))); -} - /** Initialize the display and collect relevant information about the * display properties */ -static void dmxDisplayInit(DMXScreenInfo *dmxScreen) +static Bool dmxDisplayInit(DMXScreenInfo *dmxScreen) { - if (!dmxOpenDisplay(dmxScreen)) - dmxLog(dmxFatal, - "dmxOpenDisplay: Unable to open display %s\n", - dmxScreen->name); + if (!dmxOpenDisplay(dmxScreen, + dmxScreen->display, + dmxScreen->authType, + dmxScreen->authTypeLen, + dmxScreen->authData, + dmxScreen->authDataLen)) + { + if (dmxScreen->display && *dmxScreen->display) + dmxLog(dmxWarning, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->display); + + dmxScreen->scrnWidth = 1; + dmxScreen->scrnHeight = 1; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + dmxScreen->scrnWidth = dmxScreens[0].scrnWidth; + dmxScreen->scrnHeight = dmxScreens[0].scrnHeight; + } +#endif - dmxSetErrorHandler(dmxScreen); - dmxCheckForWM(dmxScreen); - dmxGetScreenAttribs(dmxScreen); + dmxScreen->beWidth = 1; + dmxScreen->beHeight = 1; + dmxScreen->beXDPI = 96; + dmxScreen->beYDPI = 96; + dmxScreen->beDepth = 24; + dmxScreen->beBPP = 32; - if (!dmxGetVisualInfo(dmxScreen)) - dmxLog(dmxFatal, "dmxGetVisualInfo: No matching visuals found\n"); + return FALSE; + } + else + { + if (!dmxScreen->scrnWin) + dmxScreen->scrnWin = DefaultRootWindow (dmxScreen->beDisplay); + + dmxSetErrorHandler(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) + { + dmxLog(dmxWarning, + "dmxGetVisualInfo: No matching visuals found\n"); + + XLIB_PROLOGUE (dmxScreen); + XCloseDisplay(dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); + dmxScreen->beDisplay = NULL; + + return FALSE; + } + else + { + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); + } + } - dmxGetColormaps(dmxScreen); - dmxGetPixmapFormats(dmxScreen); + return TRUE; } /* If this doesn't compile, just add || defined(yoursystem) to the line @@ -558,7 +743,7 @@ static const char *dmxExecHost(void) /** This routine is called in Xserver/dix/main.c from \a main(). */ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) { - int i; + int i, nDetached; static unsigned long dmxGeneration = 0; #ifdef GLXEXT Bool glxSupported = TRUE; @@ -567,6 +752,37 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) if (dmxGeneration != serverGeneration) { int vendrel = VENDOR_RELEASE; int major, minor, year, month, day; + unsigned char sha1[20]; + const char *host = dmxExecHost (); + time_t t = time (NULL); + pid_t pid = getpid (); + +#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ + SHA1_CTX ctx; + + SHA1Init (&ctx); + SHA1Update (&ctx, display, strlen (display)); + SHA1Update (&ctx, host, strlen (host)); + SHA1Update (&ctx, &t, sizeof (time_t)); + SHA1Update (&ctx, &pid, sizeof (pid_t)); + SHA1Final (sha1, &ctx); +#else /* Use OpenSSL's libcrypto */ + SHA_CTX ctx; + + if (!SHA1_Init (&ctx) || + !SHA1_Update (&ctx, display, strlen (display)) || + !SHA1_Update (&ctx, host, strlen (host)) || + !SHA1_Update (&ctx, &t, sizeof (time_t)) || + !SHA1_Update (&ctx, &pid, sizeof (pid_t)) || + !SHA1_Final (sha1, &ctx)) + { + dmxLog(dmxFatal, "SHA1_Init failed\n"); + } +#endif + + for (i = 0; i < sizeof (sha1); i++) + snprintf(dmxDigest + 2 * i, sizeof (dmxDigest) - 2 * i, "%02x", + sha1[i]); dmxGeneration = serverGeneration; @@ -584,6 +800,7 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) if (major > 0 && minor > 0) year += 2000; dmxLog(dmxInfo, "Generation: %d\n", dmxGeneration); + dmxLog(dmxInfo, "DMX digest: %s\n", dmxDigest); dmxLog(dmxInfo, "DMX version: %d.%d.%02d%02d%02d (%s)\n", major, minor, year, month, day, VENDOR_STRING); @@ -601,17 +818,13 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) for (i = 0; i < dmxNumScreens; i++) { if (dmxScreens[i].beDisplay) dmxLog(dmxWarning, "Display \"%s\" still open\n", - dmxScreens[i].name); + dmxScreens[i].display); dmxStatFree(dmxScreens[i].stat); dmxScreens[i].stat = NULL; } - for (i = 0; i < dmxNumInputs; i++) dmxInputFree(&dmxInputs[i]); if (dmxScreens) free(dmxScreens); - if (dmxInputs) free(dmxInputs); dmxScreens = NULL; - dmxInputs = NULL; dmxNumScreens = 0; - dmxNumInputs = 0; } /* Make sure that the command-line arguments are sane. */ @@ -633,14 +846,49 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) "Dynamic screen addition/removal error (see above).\n"); } - /* ddxProcessArgument has been called at this point, but any data - * from the configuration file has not been applied. Do so, and be - * sure we have at least one back-end display. */ - dmxConfigConfigure(); + for (i = 0; i < dmxPropTransNum; i++) + dmxPropTrans[i].type = MakeAtom ((char *) dmxPropTrans[i].name, + strlen (dmxPropTrans[i].name), + TRUE); + + for (i = 0; i < dmxSelectionMapNum; i++) + { + char *beName; + + dmxSelectionMap[i].atom = MakeAtom ((char *) dmxSelectionMap[i].name, + strlen (dmxSelectionMap[i].name), + TRUE); + + beName = xalloc (strlen (dmxSelectionMap[i].name) + + strlen (dmxDigest) + 2); + if (!beName) + dmxLog (dmxFatal, "InitOutput: not enough memory\n"); + + sprintf (beName, "%s_%s", dmxSelectionMap[i].name, dmxDigest); + dmxSelectionMap[i].beAtom = MakeAtom ((char *) beName, + strlen (beName), + TRUE); + xfree (beName); + } + if (!dmxNumScreens) - dmxLog(dmxFatal, "InitOutput: no back-end displays found\n"); - if (!dmxNumInputs) - dmxLog(dmxInfo, "InitOutput: no inputs found\n"); + { + dmxLaunchDisplay (argc, argv, dmxLaunchIndex, dmxLaunchVT); + if (!dmxNumScreens) + dmxLog(dmxFatal, "InitOutput: no back-end displays found\n"); + } + + nDetached = dmxNumDetached; + if (dmxNumScreens + nDetached > MAXSCREENS) + nDetached = MAXSCREENS - dmxNumScreens; + + if (nDetached > 0) + { + dmxLog (dmxInfo, "Adding %d detached displays\n", nDetached); + + while (nDetached--) + dmxAddScreen ("", "", NULL, 0, NULL, 0, 0); + } /* Disable lazy window creation optimization if offscreen * optimization is disabled */ @@ -656,7 +904,10 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) /* Open each display and gather information about it. */ for (i = 0; i < dmxNumScreens; i++) - dmxDisplayInit(&dmxScreens[i]); + if (!dmxDisplayInit(&dmxScreens[i]) && i == 0) + dmxLog(dmxFatal, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreens[i].display); #if PANORAMIX /* Register a Xinerama callback which will run from within @@ -682,7 +933,11 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) * same as the behavior of SIGINT. However, leaving the modifier * map of the input devices empty is even more unexpected.) --RF */ - OsSignal(SIGQUIT, GiveUp); + OsSignal (SIGQUIT, GiveUp); + OsSignal (SIGSEGV, dmxSigHandler); + OsSignal (SIGILL, dmxSigHandler); + OsSignal (SIGFPE, dmxSigHandler); + OsSignal (SIGABRT, dmxSigHandler); #ifdef GLXEXT /* Check if GLX extension exists on all back-end servers */ @@ -779,19 +1034,16 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) AddScreen(dmxScreenInit, argc, argv); } - /* Compute origin information. */ - dmxInitOrigins(); - - /* Compute overlap information. */ - dmxInitOverlap(); - /* Make sure there is a global width/height available */ - dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + dmxComputeWidthHeight (); - /* FIXME: The following is temporarily placed here. When the DMX - * extension is available, it will be move there. - */ - dmxInitFonts(); + dmxInitProps(); + dmxInitGrabs(); + dmxInitSelections(); + +#ifdef MITSHM + dmxInitShm(); +#endif #ifdef RENDER /* Initialize the render extension */ @@ -799,12 +1051,19 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) dmxInitRender(); #endif +#ifdef COMPOSITE + /* Initialize the composite extension */ + if (!noCompositeExtension) + dmxInitComposite(); +#endif + /* Initialized things that need timer hooks */ dmxStatInit(); dmxSyncInit(); /* Calls RegisterBlockAndWakeupHandlers */ - dmxLog(dmxInfo, "Shadow framebuffer support %s\n", - dmxShadowFB ? "enabled" : "disabled"); + for (i = 0; i < dmxNumScreens; i++) + if (dmxScreens[i].beDisplay) + dmxBEScreenInit (screenInfo.screens[i]); } /* RATS: Assuming the fp string (which comes from the command-line argv @@ -842,6 +1101,8 @@ void AbortDDX(void) if (dmxScreen->beDisplay) XCloseDisplay(dmxScreen->beDisplay); dmxScreen->beDisplay = NULL; } + + dmxAbortDisplay (); } /** This function is called in Xserver/dix/main.c from \a main() when @@ -852,9 +1113,73 @@ void ddxGiveUp(void) AbortDDX(); } +#ifdef PANORAMIX +static Bool dmxNoPanoramiXExtension = FALSE; +#endif + /** This function is called in Xserver/os/osinit.c from \a OsInit(). */ void OsVendorInit(void) { + if (!dmxPropTrans) + { + dmxPropTrans = xalloc (sizeof (DMXPropTrans) * 2); + dmxPropTrans[0].name = "ATOM_PAIR"; + dmxPropTrans[0].format = "aa.."; + dmxPropTrans[0].type = 0; + dmxPropTrans[1].name = "_COMPIZ_WINDOW_DECOR"; + dmxPropTrans[1].format = "xP"; + dmxPropTrans[1].type = 0; + dmxPropTransNum = 2; + } + + if (!dmxSelectionMap) + { + dmxSelectionMap = xalloc (sizeof (DMXSelectionMap) * 9); + dmxSelectionMap[0].name = "WM_S0"; + dmxSelectionMap[0].atom = 0; + dmxSelectionMap[0].beAtom = 0; + dmxSelectionMap[1].name = "_NET_WM_CM_S0"; + dmxSelectionMap[1].atom = 0; + dmxSelectionMap[1].beAtom = 0; + dmxSelectionMap[2].name = "_NET_SYSTEM_TRAY_S0"; + dmxSelectionMap[2].atom = 0; + dmxSelectionMap[2].beAtom = 0; + dmxSelectionMap[3].name = "_NET_DESKTOP_LAYOUT_S0"; + dmxSelectionMap[3].atom = 0; + dmxSelectionMap[3].beAtom = 0; + dmxSelectionMap[4].name = "_NET_DESKTOP_MANAGER_S0"; + dmxSelectionMap[4].atom = 0; + dmxSelectionMap[4].beAtom = 0; + dmxSelectionMap[5].name = "_XSETTINGS_S0"; + dmxSelectionMap[5].atom = 0; + dmxSelectionMap[5].beAtom = 0; + dmxSelectionMap[6].name = "CLIPBOARD_MANAGER"; + dmxSelectionMap[6].atom = 0; + dmxSelectionMap[6].beAtom = 0; + dmxSelectionMap[7].name = "GVM_SELECTION"; + dmxSelectionMap[7].atom = 0; + dmxSelectionMap[7].beAtom = 0; + dmxSelectionMap[8].name = "_COMPIZ_DM_S0"; + dmxSelectionMap[8].atom = 0; + dmxSelectionMap[8].beAtom = 0; + dmxSelectionMapNum = 9; + } + +#ifdef PANORAMIX + noPanoramiXExtension = dmxNoPanoramiXExtension; + PanoramiXExtensionDisabledHack = TRUE; +#endif + +#ifdef XV + if (!dmxXvImageFormats) + { + dmxXvImageFormats = xalloc (sizeof (char *) * 2); + dmxXvImageFormats[0] = "YV12"; + dmxXvImageFormats[1] = "YUY2"; + dmxXvImageFormatsNum = 2; + } +#endif + } /** This function is called in Xserver/os/utils.c from \a FatalError() @@ -870,33 +1195,12 @@ void OsVendorFatalError(void) int ddxProcessArgument(int argc, char *argv[], int i) { int retval = 0; - + if (!strcmp(argv[i], "-display")) { - if (++i < argc) dmxConfigStoreDisplay(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-inputfrom") || !strcmp(argv[i], "-input")) { - if (++i < argc) dmxConfigStoreInput(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-xinputfrom") || !strcmp(argv[i],"-xinput")) { - if (++i < argc) dmxConfigStoreXInput(argv[i]); - retval = 2; - } else if (!strcmp(argv[i], "-noshadowfb")) { - dmxLog(dmxWarning, - "-noshadowfb has been deprecated " - "since it is now the default\n"); - dmxShadowFB = FALSE; - retval = 1; - } else if (!strcmp(argv[i], "-nomulticursor")) { - dmxCursorNoMulti(); - retval = 1; - } else if (!strcmp(argv[i], "-shadowfb")) { - dmxShadowFB = TRUE; - retval = 1; - } else if (!strcmp(argv[i], "-configfile")) { - if (++i < argc) dmxConfigStoreFile(argv[i]); + if (++i < argc) dmxAddScreen(argv[i], argv[i], NULL, 0, NULL, 0, 0); retval = 2; - } else if (!strcmp(argv[i], "-config")) { - if (++i < argc) dmxConfigStoreConfig(argv[i]); + } else if (!strcmp(argv[i], "-numDetached")) { + if (++i < argc) dmxNumDetached = atoi (argv[i]); retval = 2; } else if (!strcmp(argv[i], "-fontpath")) { if (++i < argc) dmxSetDefaultFontPath(argv[i]); @@ -907,14 +1211,14 @@ int ddxProcessArgument(int argc, char *argv[], int i) } else if (!strcmp(argv[i], "-syncbatch")) { if (++i < argc) dmxSyncActivate(argv[i]); retval = 2; - } else if (!strcmp(argv[i], "-nooffscreenopt")) { - dmxOffScreenOpt = FALSE; + } else if (!strcmp(argv[i], "-offscreenopt")) { + dmxOffScreenOpt = TRUE; retval = 1; } else if (!strcmp(argv[i], "-nosubdivprims")) { dmxSubdividePrimitives = FALSE; retval = 1; - } else if (!strcmp(argv[i], "-nowindowopt")) { - dmxLazyWindowCreation = FALSE; + } else if (!strcmp(argv[i], "-windowopt")) { + dmxLazyWindowCreation = TRUE; retval = 1; } else if (!strcmp(argv[i], "-noxkb")) { dmxUseXKB = FALSE; @@ -942,29 +1246,94 @@ int ddxProcessArgument(int argc, char *argv[], int i) } else if (!strcmp(argv[i], "-ignorebadfontpaths")) { dmxIgnoreBadFontPaths = TRUE; retval = 1; - } else if (!strcmp(argv[i], "-addremovescreens")) { - dmxAddRemoveScreens = TRUE; + } else if (!strcmp(argv[i], "-noaddremovescreens")) { + dmxAddRemoveScreens = FALSE; retval = 1; - } else if (!strcmp(argv[i], "-param")) { - if ((i += 2) < argc) { - if (!strcasecmp(argv[i-1], "xkbrules")) - dmxConfigSetXkbRules(argv[i]); - else if (!strcasecmp(argv[i-1], "xkbmodel")) - dmxConfigSetXkbModel(argv[i]); - else if (!strcasecmp(argv[i-1], "xkblayout")) - dmxConfigSetXkbLayout(argv[i]); - else if (!strcasecmp(argv[i-1], "xkbvariant")) - dmxConfigSetXkbVariant(argv[i]); - else if (!strcasecmp(argv[i-1], "xkboptions")) - dmxConfigSetXkbOptions(argv[i]); - else - dmxLog(dmxWarning, - "-param requires: XkbRules, XkbModel, XkbLayout," - " XkbVariant, or XkbOptions\n"); - } +#ifdef PANORAMIX + } else if (!strcmp (argv[i], "-xinerama")) { + dmxNoPanoramiXExtension = TRUE; + retval = 1; +#endif +#ifdef RANDR + } else if (!strcmp(argv[i], "-outputs")) { + if (++i < argc) xRROutputsPerScreen = atoi(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-crtcs")) { + if (++i < argc) xRRCrtcsPerScreen = atoi(argv[i]); + retval = 2; + } +#endif + else if (!strcmp (argv[i], "-prop")) + { + if ((i + 2) < argc) + { + DMXPropTrans *prop; + + prop = xrealloc (dmxPropTrans, sizeof (DMXPropTrans) * + (dmxPropTransNum + 1)); + if (prop) + { + prop[dmxPropTransNum].name = argv[i + 1]; + prop[dmxPropTransNum].format = argv[i + 2]; + prop[dmxPropTransNum].type = 0; + + dmxPropTransNum++; + dmxPropTrans = prop; + } + } retval = 3; } - if (!serverGeneration) dmxConfigSetMaxScreens(); + else if (!strcmp (argv[i], "-selection")) + { + if (++i < argc) + { + DMXSelectionMap *selection; + + selection = xrealloc (dmxSelectionMap, sizeof (DMXSelectionMap) * + (dmxSelectionMapNum + 1)); + if (selection) + { + selection[dmxSelectionMapNum].name = argv[i]; + selection[dmxSelectionMapNum].atom = 0; + selection[dmxSelectionMapNum].beAtom = 0; + + dmxSelectionMapNum++; + dmxSelectionMap = selection; + } + } + retval = 2; + } +#ifdef XV + else if (!strcmp (argv[i], "-xvimage")) + { + if (++i < argc) + { + char **formats; + + formats = xrealloc (dmxXvImageFormats, + sizeof (char *) * + (dmxXvImageFormatsNum + 1)); + if (formats) + { + formats[dmxXvImageFormatsNum] = argv[i]; + + dmxXvImageFormatsNum++; + dmxXvImageFormats = formats; + } + } + retval = 2; + } +#endif + else if ((argv[i][0] == 'v') && (argv[i][1] == 't')) + { + dmxLaunchVT = argv[i]; + retval = 1; + } + else if (!strcmp(argv[i], "--")) { + dmxLaunchIndex = i + 1; + retval = argc - i; + } + return retval; } @@ -973,61 +1342,36 @@ void ddxUseMsg(void) { ErrorF("\n\nDevice Dependent Usage:\n"); ErrorF("-display string Specify the back-end display(s)\n"); - ErrorF("-input string Specify input source for core device\n"); - ErrorF("-xinput string Specify input source for XInput device\n"); + ErrorF("-numDetached num Specify detached back-end display(s)\n"); ErrorF("-shadowfb Enable shadow frame buffer\n"); - ErrorF("-configfile file Read from a configuration file\n"); - ErrorF("-config config Select a specific configuration\n"); - ErrorF("-nomulticursor Turn of multiple cursor support\n"); ErrorF("-fontpath Sets the default font path\n"); ErrorF("-stat inter scrns Print out performance statistics\n"); ErrorF("-syncbatch inter Set interval for XSync batching\n"); - ErrorF("-nooffscreenopt Disable offscreen optimization\n"); + ErrorF("-offscreenopt Enable offscreen optimization\n"); ErrorF("-nosubdivprims Disable primitive subdivision\n"); ErrorF(" optimization\n"); - ErrorF("-nowindowopt Disable lazy window creation optimization\n"); + ErrorF("-windowopt Enable lazy window creation optimization\n"); ErrorF("-noxkb Disable use of the XKB extension with\n"); ErrorF(" backend displays (cf. -kb).\n"); ErrorF("-depth Specify the default root window depth\n"); ErrorF("-norender Disable RENDER extension support\n"); #ifdef GLXEXT - ErrorF("-noglxproxy Disable GLX Proxy\n"); + ErrorF("-glxproxy Enable GLX Proxy\n"); ErrorF("-noglxswapgroup Disable swap group and swap barrier\n"); ErrorF(" extensions in GLX proxy\n"); ErrorF("-glxsyncswap Force XSync after swap buffers\n"); ErrorF("-glxfinishswap Force glFinish after swap buffers\n"); #endif ErrorF("-ignorebadfontpaths Ignore bad font paths during initialization\n"); - ErrorF("-addremovescreens Enable dynamic screen addition/removal\n"); - ErrorF("-param ... Specify configuration parameters (e.g.,\n"); - ErrorF(" XkbRules, XkbModel, XkbLayout, etc.)\n"); - ErrorF("\n"); - ErrorF(" If the -input string matches a -display string, then input\n" - " is taken from that backend display. (XInput cannot be taken\n" - " from a backend display.) Placing \",console\" after the\n" - " display name will force a console window to be opened on\n" - " that display in addition to the backend input. This is\n" - " useful if the backend window does not cover the whole\n" - " physical display.\n\n"); - - ErrorF(" Otherwise, if the -input or -xinput string specifies another\n" - " X display, then a console window will be created on that\n" - " display. Placing \",windows\" or \",nowindows\" after the\n" - " display name will control the display of window outlines in\n" - " the console.\n\n"); - - ErrorF(" -input or -xinput dummy specifies no input.\n"); - ErrorF(" -input or -xinput local specifies the use of a raw keyboard,\n" - " mouse, or other (extension) device:\n" - " -input local,kbd,ps2 will use a ps2 mouse\n" - " -input local,kbd,ms will use a serial mouse\n" - " -input local,usb-kbd,usb-mou will use USB devices \n" - " -xinput local,usb-oth will use a non-mouse and\n" - " non-keyboard USB device with XInput\n\n"); - - ErrorF(" Special Keys:\n"); - ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n"); - ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n"); - ErrorF(" Ctrl-Alt-q Quit (core devices only)\n"); - ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n"); + ErrorF("-noaddremovescreens Disable dynamic screen addition/removal\n"); +#ifdef RANDR + ErrorF("-outputs num RANDR outputs for each back-end display\n"); + ErrorF("-crtcs num RANDR crtcs for each back-end display\n"); +#endif + ErrorF("-prop name format Specify property translation\n"); + ErrorF("-selection name Specify selection that needs unique prefix\n"); +#ifdef XV + ErrorF("-xvimage fourcc Enable XVideo image format\n"); +#endif + ErrorF("-- [ server ] [ display ] [ options ]\n"); } diff --git a/hw/dmx/dmxinit.h b/hw/dmx/dmxinit.h index 7d166fd..43f5a91 100644 --- a/hw/dmx/dmxinit.h +++ b/hw/dmx/dmxinit.h @@ -38,10 +38,21 @@ #define DMXINIT_H #include "scrnintstr.h" - -extern Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen); +extern DMXScreenInfo *dmxAddScreen(const char *name, + const char *display, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen, + int virtualFb); +extern Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen, + const char *display, + const char *authType, + int authTypeLen, + const char *authData, + int authDataLen); +extern void dmxCloseDisplay(DMXScreenInfo *dmxScreen); extern void dmxSetErrorHandler(DMXScreenInfo *dmxScreen); -extern void dmxCheckForWM(DMXScreenInfo *dmxScreen); extern void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen); extern Bool dmxGetVisualInfo(DMXScreenInfo *dmxScreen); extern void dmxGetColormaps(DMXScreenInfo *dmxScreen); diff --git a/hw/dmx/dmxinput.c b/hw/dmx/dmxinput.c index 83f8a4a..91a52b6 100644 --- a/hw/dmx/dmxinput.c +++ b/hw/dmx/dmxinput.c @@ -1,41 +1,26 @@ /* - * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. + * Copyright © 2008 Novell, Inc. * - * All Rights Reserved. + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Authors: - * David H. Dawes <dawes@xfree86.org> - * Kevin E. Martin <kem@redhat.com> - * Rickard E. (Rik) Faith <faith@redhat.com> + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. * - */ - -/** \file - * Provide the main entry points for input initialization and processing - * that arequired by the dix layer. + * Author: David Reveman <davidr@novell.com> */ #ifdef HAVE_DMX_CONFIG_H @@ -45,74 +30,2384 @@ #include "dmx.h" #include "dmxlog.h" #include "dmxinput.h" +#include "dmxgrab.h" +#include "dmxdnd.h" +#include "dmxwindow.h" +#include "dmxcursor.h" +#include "dmxscrinit.h" +#include "dmxxlibio.h" #include "inputstr.h" #include "input.h" #include "mi.h" +#include "exevents.h" +#include "XIstubs.h" +#include "xace.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include <X11/keysym.h> +#include <xcb/xinput.h> + +#define DMX_KEYBOARD_EVENT_MASK \ + (KeyPressMask | KeyReleaseMask | KeymapStateMask | FocusChangeMask) + +#define DMX_POINTER_EVENT_MASK \ + (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \ + LeaveWindowMask) + +static EventListPtr dmxEvents = NULL; + +static void +dmxUpdateKeycodeMap (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + KeySymsPtr dst = &pDevice->key->curKeySyms; + KeySymsPtr src = &pDevPriv->keySyms; + int width = src->mapWidth; + int i; + + if (!pDevice->isMaster && pDevice->u.master) + { + if (IsKeyboardDevice (pDevice->u.master)) + dst = &pDevice->u.master->key->curKeySyms; + } + + if (dst->mapWidth < width) + width = dst->mapWidth; + + memset (pDevPriv->keycode, 0, + sizeof (KeyCode) * (setup->max_keycode - setup->min_keycode)); + + for (i = src->minKeyCode - setup->min_keycode; + i < (src->maxKeyCode - src->minKeyCode); + i++) + { + int j; -/** Returns TRUE if the key is a valid modifier. For PC-class - * keyboards, all keys can be used as modifiers, so return TRUE - * always. */ -Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) + for (j = 0; j < (dst->maxKeyCode - dst->minKeyCode); j++) + { + int k; + + for (k = 0; k < i; k++) + if (pDevPriv->keycode[k] == (dst->minKeyCode + j)) + break; + + /* make sure the keycode is not already in use */ + if (k < i) + continue; + + for (k = 0; k < width; k++) + if (dst->map[j * dst->mapWidth + k] != NoSymbol && + src->map[i * src->mapWidth + k] != NoSymbol) + if (dst->map[j * dst->mapWidth + k] != + src->map[i * src->mapWidth + k]) + break; + + if (k == width) + break; + } + + if (j < (dst->maxKeyCode - dst->minKeyCode)) + pDevPriv->keycode[i] = dst->minKeyCode + j; + } +} + +static void +dmxUpdateKeyboardMapping (DeviceIntPtr pDevice, + int first, + int count) { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + KeySymsRec keysyms; + xcb_keysym_t *syms; + int n; + + if (pDevPriv->deviceId >= 0) + { + xcb_input_get_device_key_mapping_reply_t *reply; + + reply = xcb_input_get_device_key_mapping_reply + (dmxScreen->connection, + xcb_input_get_device_key_mapping (dmxScreen->connection, + pDevPriv->deviceId, + first, + count), + NULL); + + if (reply) + { + syms = xcb_input_get_device_key_mapping_keysyms (reply); + n = xcb_input_get_device_key_mapping_keysyms_length (reply); + + keysyms.minKeyCode = first; + keysyms.maxKeyCode = first + n - 1; + keysyms.mapWidth = reply->keysyms_per_keycode; + keysyms.map = (KeySym *) syms; + + SetKeySymsMap (&pDevPriv->keySyms, &keysyms); + + free (reply); + } + } + else + { + xcb_get_keyboard_mapping_reply_t *reply; + + reply = xcb_get_keyboard_mapping_reply + (dmxScreen->connection, + xcb_get_keyboard_mapping (dmxScreen->connection, + first, + count), + NULL); + + if (reply) + { + syms = xcb_get_keyboard_mapping_keysyms (reply); + n = xcb_get_keyboard_mapping_keysyms_length (reply); + + keysyms.minKeyCode = first; + keysyms.maxKeyCode = first + n - 1; + keysyms.mapWidth = reply->keysyms_per_keycode; + keysyms.map = (KeySym *) syms; + + SetKeySymsMap (&pDevPriv->keySyms, &keysyms); + + free (reply); + } + } + + dmxUpdateKeycodeMap (pDevice); +} + +static DeviceIntPtr +dmxGetButtonDevice (DMXInputInfo *dmxInput, + XID deviceId) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (dmxInput->devs[i]); + + if (!IsPointerDevice (dmxInput->devs[i])) + continue; + + if (deviceId >= 0) + { + if (pDevPriv->deviceId != deviceId) + continue; + } + + return dmxInput->devs[i]; + } + + return NULL; +} + +static DeviceIntPtr +dmxGetPairedButtonDevice (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + return dmxGetButtonDevice (pDevPriv->dmxInput, pDevPriv->masterId); +} + +static int +dmxButtonEvent (DeviceIntPtr pDevice, + int button, + int x, + int y, + int type) +{ + int v[2] = { x, y }; + int nEvents, i; + + GetEventList (&dmxEvents); + nEvents = GetPointerEvents (dmxEvents, + pDevice, + type, + button, + POINTER_ABSOLUTE, + 0, 2, + v); + + for (i = 0; i < nEvents; i++) + mieqEnqueue (pDevice, dmxEvents[i].event); + + if (button > 0 && button <= 255) + { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + switch (type) { + case XCB_BUTTON_PRESS: + pDevPriv->state[button >> 3] |= 1 << (button & 7); + break; + case XCB_BUTTON_RELEASE: + pDevPriv->state[button >> 3] &= ~(1 << (button & 7)); + default: + break; + } + } + + return nEvents; +} + +static int +dmxKeyEvent (DeviceIntPtr pDevice, + int key, + int type) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + int nEvents = 0; + + if (key >= setup->min_keycode && key <= setup->max_keycode) + { + int keycode = pDevPriv->keycode[key - setup->min_keycode]; + + if (keycode) + { + int i; + + GetEventList (&dmxEvents); + nEvents = GetKeyboardEvents (dmxEvents, pDevice, type, keycode); + for (i = 0; i < nEvents; i++) + mieqEnqueue (pDevice, dmxEvents[i].event); + } + } + + if (key > 0 && key <= 255) + { + switch (type) { + case XCB_KEY_PRESS: + pDevPriv->state[key >> 3] |= 1 << (key & 7); + break; + case XCB_KEY_RELEASE: + pDevPriv->state[key >> 3] &= ~(1 << (key & 7)); + default: + break; + } + } + + return nEvents; +} + +static int +dmxUpdateButtonState (DeviceIntPtr pDevice, + const char *buttons) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + int i, j, nEvents = 0; + + for (i = 0; i < 32; i++) + { + if (!(pDevPriv->state[i] ^ buttons[i])) + continue; + + for (j = 0; j < 8; j++) + { + /* button is down, but shouldn't be */ + if ((pDevPriv->state[i] & (1 << j)) && !(buttons[i] & (1 << j))) + nEvents += dmxButtonEvent (pDevice, + (i << 3) + j, + pDevice->last.valuators[0], + pDevice->last.valuators[1], + XCB_BUTTON_RELEASE); + + /* button should be down, but isn't */ + if (!(pDevPriv->state[i] & (1 << j)) && (buttons[i] & (1 << j))) + nEvents += dmxButtonEvent (pDevice, + (i << 3) + j, + pDevice->last.valuators[0], + pDevice->last.valuators[1], + XCB_BUTTON_PRESS); + } + } + + return nEvents; +} + +static int +dmxUpdateKeyState (DeviceIntPtr pDevice, + const char *keys) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + int i, j, nEvents = 0; + + for (i = 0; i < 32; i++) + { + if (!(pDevPriv->state[i] ^ keys[i])) + continue; + + for (j = 0; j < 8; j++) + { + /* key is down, but shouldn't be */ + if ((pDevPriv->state[i] & (1 << j)) && !(keys[i] & (1 << j))) + nEvents += dmxKeyEvent (pDevice, + (i << 3) + j, + XCB_KEY_RELEASE); + + /* key should be down, but isn't */ + if (!(pDevPriv->state[i] & (1 << j)) && (keys[i] & (1 << j))) + nEvents += dmxKeyEvent (pDevice, + (i << 3) + j, + XCB_KEY_PRESS); + } + } + + return nEvents; +} + +static int +dmxChangeButtonState (DeviceIntPtr pDevice, + int button, + int how) +{ + int nEvents = 0; + + if (button > 0 && button <= 255) + { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + char buttons[32]; + + memcpy (buttons, pDevPriv->state, sizeof (buttons)); + + switch (how) { + case XCB_BUTTON_PRESS: + buttons[button >> 3] |= 1 << (button & 7); + break; + case XCB_BUTTON_RELEASE: + buttons[button >> 3] &= ~(1 << (button & 7)); + default: + break; + } + + dmxUpdateButtonState (pDevice, buttons); + } + + return nEvents; +} + +static int +dmxChangeKeyState (DeviceIntPtr pDevice, + int key, + int how) +{ + int nEvents = 0; + + if (key > 0 && key <= 255) + { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + char keys[32]; + + memcpy (keys, pDevPriv->state, sizeof (keys)); + + switch (how) { + case XCB_KEY_PRESS: + keys[key >> 3] |= 1 << (key & 7); + break; + case XCB_KEY_RELEASE: + keys[key >> 3] &= ~(1 << (key & 7)); + default: + break; + } + + dmxUpdateKeyState (pDevice, keys); + } + + return nEvents; +} + +static int +dmxUpdateSpritePosition (DeviceIntPtr pDevice, + int x, + int y) +{ + ScreenPtr pScreen = miPointerGetScreen (pDevice); + + if (x >= pScreen->width) + x = pScreen->width - 1; + else if (x < 0) + x = 0; + + if (y >= pScreen->height) + y = pScreen->height - 1; + else if (y < 0) + y = 0; + + if (x == pDevice->last.valuators[0] && y == pDevice->last.valuators[1]) + return 0; + + return dmxButtonEvent (pDevice, 0, x, y, XCB_MOTION_NOTIFY); +} + +static Bool +dmxFakePointerGrab (DMXInputInfo *dmxInput) +{ + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + WindowPtr pWin = WindowTable[dmxScreen->index]; + GrabRec newGrab; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pWin = WindowTable[0]; +#endif + + memset (&newGrab, 0, sizeof (GrabRec)); + + newGrab.window = pWin; + newGrab.resource = 0; + newGrab.ownerEvents = xFalse; + newGrab.cursor = NULL; + newGrab.confineTo = NullWindow; + newGrab.eventMask = NoEventMask; + newGrab.genericMasks = NULL; + newGrab.next = NULL; + newGrab.keyboardMode = GrabModeAsync; + newGrab.pointerMode = GrabModeAsync; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + + if (!pDevice->isMaster && pDevice->u.master) + pDevice = pDevice->u.master; + + if (!IsPointerDevice (pDevice)) + continue; + + newGrab.device = pDevice; + + if (!dmxActivateFakeGrab (pDevice, &newGrab)) + return FALSE; + } + return TRUE; } -/** Called from dix/main.c on each server generation to initialize - * inputs. All the work is done in dmxInputInit. \see - * dmxInputInit() */ -void InitInput(int argc, char **argv) +static void +dmxReleaseFakePointerGrab (DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + + if (!pDevice->isMaster && pDevice->u.master) + pDevice = pDevice->u.master; + + if (!IsPointerDevice (pDevice)) + continue; + + dmxDeactivateFakeGrab (pDevice); + } +} + +static Bool +dmxFakeKeyboardGrab (DMXInputInfo *dmxInput) { + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + WindowPtr pWin = WindowTable[dmxScreen->index]; + GrabRec newGrab; + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + pWin = WindowTable[0]; +#endif + + memset (&newGrab, 0, sizeof (GrabRec)); + + newGrab.window = pWin; + newGrab.resource = 0; + newGrab.ownerEvents = xFalse; + newGrab.cursor = NULL; + newGrab.confineTo = NullWindow; + newGrab.eventMask = NoEventMask; + newGrab.genericMasks = NULL; + newGrab.next = NULL; + newGrab.keyboardMode = GrabModeAsync; + newGrab.pointerMode = GrabModeAsync; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + + if (!pDevice->isMaster && pDevice->u.master) + pDevice = pDevice->u.master; + + if (!IsKeyboardDevice (pDevice)) + continue; + + newGrab.device = pDevice; + + if (!dmxActivateFakeGrab (pDevice, &newGrab)) + return FALSE; + } + + return TRUE; +} + +static void +dmxReleaseFakeKeyboardGrab (DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + + if (!pDevice->isMaster && pDevice->u.master) + pDevice = pDevice->u.master; + + if (!IsKeyboardDevice (pDevice)) + continue; + + dmxDeactivateFakeGrab (pDevice); + } +} + +Bool +dmxFakeMotion (DMXInputInfo *dmxInput, + int x, + int y) +{ + int i; + + if (!dmxFakePointerGrab (dmxInput)) + return FALSE; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + + if (!IsPointerDevice (pDevice)) + continue; + + dmxUpdateSpritePosition (pDevice, x, y); + } + + return TRUE; +} + +void +dmxEndFakeMotion (DMXInputInfo *dmxInput) +{ + dmxReleaseFakePointerGrab (dmxInput); +} + +static void +dmxInputGrabDeviceReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXInputInfo *dmxInput = &dmxScreens[pScreen->myNum].input; int i; - DMXInputInfo *dmxInput; - if (!dmxNumInputs) - dmxLog(dmxFatal, "InitInput: no inputs specified\n"); + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if ((*pDevPriv->ReplyCheck) (pDevice, sequence, reply)) + break; + } +} + +/* not in xcb-xinput yet */ + +#define DMX_XCB_WARP_DEVICE_POINTER 41 + +typedef struct dmx_xcb_warp_device_pointer_request_t { + uint8_t major_opcode; + uint8_t minor_opcode; + uint16_t length; + xcb_window_t src_win; + xcb_window_t dst_win; + int16_t src_x; + int16_t src_y; + uint16_t src_width; + uint16_t src_height; + int16_t dst_x; + int16_t dst_y; + uint8_t deviceid; + uint8_t pad0; + uint16_t pad1; +} dmx_xcb_warp_device_pointer_request_t; + +#define DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE 45 + +typedef struct dmx_xcb_input_extended_grab_device_request_t { + uint8_t major_opcode; + uint8_t minor_opcode; + uint16_t length; + xcb_window_t grab_window; + xcb_timestamp_t time; + uint8_t deviceid; + uint8_t device_mode; + uint8_t owner_events; + uint8_t pad0; + xcb_window_t confine_to; + xcb_cursor_t cursor; + uint16_t event_count; + uint16_t generic_event_count; +} dmx_xcb_input_extended_grab_device_request_t; + +#define DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY 17 + +typedef struct dmx_xcb_input_device_state_notify_event_t { + uint8_t response_type; + uint8_t detail; + uint16_t sequence; + xcb_timestamp_t time; + xcb_window_t root; + xcb_window_t event; + xcb_window_t child; + int16_t root_x; + int16_t root_y; + int16_t event_x; + int16_t event_y; + uint16_t state; + uint8_t mode; + uint8_t device_id; +} dmx_xcb_input_device_state_notify_event_t; + +typedef xcb_input_focus_in_event_t dmx_xcb_input_focus_out_event_t; + +static void +dmxDeviceGrabKeyboard (DeviceIntPtr pDevice, + WindowPtr pWindow) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + Window window = (DMX_GET_WINDOW_PRIV (pWindow))->window; + + if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && !pDevPriv->active) + return; + + if (pDevPriv->deviceId >= 0) + { + dmx_xcb_input_extended_grab_device_request_t grab = { + .grab_window = window, + .deviceid = pDevPriv->deviceId, + .device_mode = XCB_GRAB_MODE_ASYNC, + .owner_events = TRUE, + .event_count = 2 + }; + xcb_protocol_request_t request = { + 2, + &xcb_input_id, + DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE, + FALSE + }; + XEventClass cls[3]; + int type; + struct iovec vector[] = { + { &grab, sizeof (grab) }, + { cls, sizeof (cls) } + }; + + DeviceKeyPress (pDevPriv->device, type, cls[1]); + DeviceKeyRelease (pDevPriv->device, type, cls[2]); + + pDevPriv->grab.sequence = + xcb_send_request (dmxScreen->connection, + 0, + vector, + &request); + } + else + { + pDevPriv->grab.sequence = + xcb_grab_keyboard (dmxScreen->connection, + TRUE, + window, + 0, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC).sequence; + } + + dmxAddRequest (&dmxScreen->request, + dmxInputGrabDeviceReply, + pDevPriv->grab.sequence, + 0); +} + +static void +dmxDeviceUngrabKeyboard (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->deviceId >= 0) + { + xcb_input_ungrab_device (dmxScreen->connection, + 0, + pDevPriv->deviceId); + } + else + { + xcb_ungrab_keyboard (dmxScreen->connection, 0); + } + + pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS; +} + +static Bool +dmxDeviceKeyboardReplyCheck (DeviceIntPtr pDevice, + unsigned int request, + xcb_generic_reply_t *reply) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if (request == pDevPriv->grab.sequence) + { + if (reply) + { + if (pDevPriv->deviceId >= 0) + { + xcb_input_grab_device_reply_t *xgrab = + (xcb_input_grab_device_reply_t *) reply; + + pDevPriv->grabStatus = xgrab->status; + } + else + { + xcb_grab_keyboard_reply_t *xgrab = + (xcb_grab_keyboard_reply_t *) reply; + + pDevPriv->grabStatus = xgrab->status; + } + } + + pDevPriv->grab.sequence = 0; + return TRUE; + } + + return FALSE; +} + +static void +dmxDeviceGrabPointer (DeviceIntPtr pDevice, + WindowPtr pWindow, + WindowPtr pConfineTo, + CursorPtr pCursor) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; + Window window = (DMX_GET_WINDOW_PRIV (pWindow))->window; + Window confineTo = None; + Cursor cursor = None; + + if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && !pDevPriv->active) + return; + + if (pConfineTo) + confineTo = (DMX_GET_WINDOW_PRIV (pConfineTo))->window; + + if (pCursor) + cursor = (DMX_GET_CURSOR_PRIV (pCursor, pScreen))->cursor; + + if (pDevPriv->deviceId >= 0) + { + dmx_xcb_input_extended_grab_device_request_t grab = { + .grab_window = window, + .deviceid = pDevPriv->deviceId, + .device_mode = XCB_GRAB_MODE_ASYNC, + .owner_events = TRUE, + .confine_to = confineTo, + .cursor = cursor, + .event_count = 3 + }; + xcb_protocol_request_t request = { + 2, + &xcb_input_id, + DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE, + FALSE + }; + XEventClass cls[3]; + int type; + struct iovec vector[] = { + { &grab, sizeof (grab) }, + { cls, sizeof (cls) } + }; + + DeviceMotionNotify (pDevPriv->device, type, cls[0]); + DeviceButtonPress (pDevPriv->device, type, cls[1]); + DeviceButtonRelease (pDevPriv->device, type, cls[2]); + + pDevPriv->grab.sequence = + xcb_send_request (dmxScreen->connection, + 0, + vector, + &request); + } + else + { + pDevPriv->grab.sequence = + xcb_grab_pointer (dmxScreen->connection, + TRUE, + window, + DMX_POINTER_EVENT_MASK, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC, + confineTo, + cursor, + 0).sequence; + } + + dmxAddRequest (&dmxScreen->request, + dmxInputGrabDeviceReply, + pDevPriv->grab.sequence, + 0); +} + +static void +dmxDeviceUngrabPointer (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->deviceId >= 0) + { + xcb_input_ungrab_device (dmxScreen->connection, + 0, + pDevPriv->deviceId); + } + else + { + xcb_ungrab_pointer (dmxScreen->connection, 0); + } + + pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS; +} + +static Bool +dmxDevicePointerReplyCheck (DeviceIntPtr pDevice, + unsigned int request, + xcb_generic_reply_t *reply) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if (request == pDevPriv->grab.sequence) + { + if (reply) + { + if (pDevPriv->deviceId >= 0) + { + xcb_input_grab_device_reply_t *xgrab = + (xcb_input_grab_device_reply_t *) reply; + + pDevPriv->grabStatus = xgrab->status; + } + else + { + xcb_grab_pointer_reply_t *xgrab = + (xcb_grab_pointer_reply_t *) reply; + + pDevPriv->grabStatus = xgrab->status; + } + } + + pDevPriv->grab.sequence = 0; + return TRUE; + } + + return FALSE; +} + +static void +dmxDevicePointerActivate (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->active) + return; + + pDevPriv->active = TRUE; + + dmxReleaseFakePointerGrab (pDevPriv->dmxInput); + + if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && + pDevPriv->grab.sequence == 0) + { + DeviceIntPtr pMaster = pDevice; + + if (!pDevice->isMaster && pDevice->u.master) + pMaster = pDevice->u.master; + + if (pMaster->deviceGrab.grab) + { + GrabPtr pGrab = pMaster->deviceGrab.grab; + WindowPtr pWin, pConfineTo = NULL; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win, *confineToWin = NULL; + int i = dmxScreen->index; + + if (!(win = (PanoramiXRes *) + SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + if (pGrab->confineTo) + if (!(confineToWin = (PanoramiXRes *) + SecurityLookupIDByType( + serverClient, pGrab->confineTo->drawable.id, + XRT_WINDOW, DixGetAttrAccess))) + return; + + if (dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess) != Success) + return; + + if (confineToWin) + if (dixLookupWindow (&pConfineTo, + confineToWin->info[i].id, + serverClient, + DixGetAttrAccess) != Success) + return; + } + else +#endif + { + pWin = pGrab->window; + pConfineTo = pGrab->confineTo; + } + + dmxDeviceGrabPointer (pDevice, + pWin, + pConfineTo, + pGrab->cursor); + } + } +} + +static void +dmxDevicePointerDeactivate (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if (!pDevPriv->active) + return; + + pDevPriv->active = FALSE; + + dmxFakePointerGrab (pDevPriv->dmxInput); +} + +static void +dmxUpdateSpriteFromEvent (DeviceIntPtr pDevice, + xcb_window_t event, + int x, + int y, + int rootX, + int rootY) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; + + if (event != dmxScreen->rootWin) + { + DeviceIntPtr pMaster = pDevice; + WindowPtr pWin; + + if (!pDevice->isMaster && pDevice->u.master) + pMaster = pDevice->u.master; + + if (!pMaster->deviceGrab.grab) + { + dmxDeviceUngrabPointer (pDevice); + dmxLog (dmxWarning, "non-root window event without active grab\n"); + return; + } + + pWin = WindowTable[dmxScreen->index]; + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + + if (pWinPriv->window == event) + break; + + if (pWin->firstChild) + { + pWin = pWin->firstChild; + continue; + } + + while (!pWin->nextSib && (pWin != WindowTable[dmxScreen->index])) + pWin = pWin->parent; + + if (pWin == WindowTable[dmxScreen->index]) + break; + + pWin = pWin->nextSib; + } + + if (!pWin) + return; + + x += pWin->drawable.x; + y += pWin->drawable.y; + } + + dmxEndFakeMotion (&dmxScreen->input); + dmxBEDnDSpriteUpdate (pScreen, event, rootX, rootY); + dmxUpdateSpritePosition (pDevice, x, y); + dmxDevicePointerActivate (pDevice); +} + +static Bool +dmxDevicePointerEventCheck (DeviceIntPtr pDevice, + xcb_generic_event_t *event) +{ + DeviceIntPtr pButtonDev = pDevice; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pButtonDev); + DMXInputInfo *dmxInput = pDevPriv->dmxInput; + int reltype, type = event->response_type & 0x7f; + int id = pDevPriv->deviceId; + + switch (type) { + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *xmotion = + (xcb_motion_notify_event_t *) event; + + dmxUpdateSpriteFromEvent (pButtonDev, + xmotion->event, + xmotion->event_x, + xmotion->event_y, + xmotion->root_x, + xmotion->root_y); + } break; + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: { + xcb_button_press_event_t *xbutton = + (xcb_button_press_event_t *) event; + + dmxUpdateSpriteFromEvent (pButtonDev, + xbutton->event, + xbutton->event_x, + xbutton->event_y, + xbutton->root_x, + xbutton->root_y); + dmxChangeButtonState (pButtonDev, + xbutton->detail, + type); + } break; + case XCB_LEAVE_NOTIFY: { + xcb_leave_notify_event_t *xcrossing = + (xcb_leave_notify_event_t *) event; + + if (xcrossing->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDevicePointerDeactivate (pButtonDev); + } break; + default: + if (id < 0) + return FALSE; + + reltype = type - dmxInput->eventBase; + + switch (reltype) { + case XCB_INPUT_DEVICE_VALUATOR: { + xcb_input_device_valuator_event_t *xvaluator = + (xcb_input_device_valuator_event_t *) event; + + if (id != (xvaluator->device_id & DEVICE_BITS)) + return FALSE; + + /* eat valuator events */ + } break; + case XCB_INPUT_DEVICE_MOTION_NOTIFY: { + xcb_input_device_motion_notify_event_t *xmotion = + (xcb_input_device_motion_notify_event_t *) event; + + if (id != (xmotion->device_id & DEVICE_BITS)) + return FALSE; + + dmxUpdateSpriteFromEvent (pButtonDev, + xmotion->event, + xmotion->event_x, + xmotion->event_y, + xmotion->root_x, + xmotion->root_y); + } break; + case XCB_INPUT_DEVICE_BUTTON_PRESS: + case XCB_INPUT_DEVICE_BUTTON_RELEASE: { + xcb_input_device_button_press_event_t *xbutton = + (xcb_input_device_button_press_event_t *) event; + + if (id != (xbutton->device_id & DEVICE_BITS)) + return FALSE; + + dmxUpdateSpriteFromEvent (pButtonDev, + xbutton->event, + xbutton->event_x, + xbutton->event_y, + xbutton->root_x, + xbutton->root_y); + dmxChangeButtonState (pButtonDev, + xbutton->detail, XCB_BUTTON_RELEASE + + (reltype - + XCB_INPUT_DEVICE_BUTTON_RELEASE)); + } break; + case XCB_INPUT_DEVICE_STATE_NOTIFY: { + xcb_input_device_state_notify_event_t *xstate = + (xcb_input_device_state_notify_event_t *) event; + + if (id != (xstate->device_id & DEVICE_BITS)) + return FALSE; + + if (!(xstate->classes_reported & (1 << ButtonClass))) + return FALSE; + + memset (pDevPriv->keysbuttons, 0, 32); + + if (xstate->response_type & MORE_EVENTS) + { + memcpy (pDevPriv->keysbuttons, xstate->buttons, 4); + } + else + { + memcpy (pDevPriv->keysbuttons, xstate->buttons, 4); + dmxUpdateButtonState (pButtonDev, + pDevPriv->keysbuttons); + } + } break; + case XCB_INPUT_DEVICE_BUTTON_STATE_NOTIFY: { + xcb_input_device_button_state_notify_event_t *xstate = + (xcb_input_device_button_state_notify_event_t *) event; + + if (id != (xstate->device_id & DEVICE_BITS)) + return FALSE; + + memcpy (&pDevPriv->keysbuttons[4], xstate->buttons, 28); + dmxUpdateButtonState (pButtonDev, pDevPriv->keysbuttons); + } break; + case DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY: { + dmx_xcb_input_device_state_notify_event_t *xcrossing = + (dmx_xcb_input_device_state_notify_event_t *) event; + + if (id != (xcrossing->device_id & DEVICE_BITS)) + return FALSE; + + if (xcrossing->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDevicePointerDeactivate (pButtonDev); + } break; + default: + return FALSE; + } + } + + return TRUE; +} + +static void +dmxDeviceKeyboardActivate (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->active) + return; + + dmxReleaseFakeKeyboardGrab (pDevPriv->dmxInput); + + pDevPriv->active = TRUE; + + if (pDevPriv->grabStatus != XCB_GRAB_STATUS_SUCCESS && + pDevPriv->grab.sequence == 0) + { + DeviceIntPtr pMaster = pDevice; + + if (!pDevice->isMaster && pDevice->u.master) + pMaster = pDevice->u.master; + + if (pMaster->deviceGrab.grab) + { + GrabPtr pGrab = pMaster->deviceGrab.grab; + WindowPtr pWin; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int i = dmxScreen->index; + + if (!(win = (PanoramiXRes *) + SecurityLookupIDByType( + serverClient, pGrab->window->drawable.id, XRT_WINDOW, + DixGetAttrAccess))) + return; + + if (dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixGetAttrAccess) != Success) + return; + } + else +#endif + { + pWin = pGrab->window; + } + + dmxDeviceGrabKeyboard (pDevice, pWin); + } + } +} + +static void +dmxDeviceKeyboardDeactivate (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if (!pDevPriv->active) + return; + + pDevPriv->active = FALSE; + + dmxFakeKeyboardGrab (pDevPriv->dmxInput); +} + +static void +dmxUpdateKeyStateFromEvent (DeviceIntPtr pDevice, + xcb_window_t event, + int detail, + int x, + int y, + int rootX, + int rootY, + int type) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; + DeviceIntPtr pButtonDev; + + if (event != dmxScreen->rootWin) + { + DeviceIntPtr pMaster = pDevice; + WindowPtr pWin; + + if (!pDevice->isMaster && pDevice->u.master) + pMaster = pDevice->u.master; + + if (!pMaster->deviceGrab.grab) + { + dmxDeviceUngrabKeyboard (pDevice); + dmxLog (dmxWarning, "non-root window event without active grab\n"); + return; + } + + pWin = WindowTable[dmxScreen->index]; + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + + if (pWinPriv->window == event) + break; + + if (pWin->firstChild) + { + pWin = pWin->firstChild; + continue; + } + + while (!pWin->nextSib && (pWin != WindowTable[dmxScreen->index])) + pWin = pWin->parent; + + if (pWin == WindowTable[dmxScreen->index]) + break; + + pWin = pWin->nextSib; + } + + if (!pWin) + return; + + x += pWin->drawable.x; + y += pWin->drawable.y; + } + + pButtonDev = dmxGetPairedButtonDevice (pDevice); + if (pButtonDev && DMX_GET_DEVICE_PRIV (pButtonDev)->active) + { + dmxEndFakeMotion (&dmxScreen->input); + dmxBEDnDSpriteUpdate (pScreen, event, rootX, rootY); + dmxUpdateSpritePosition (pButtonDev, x, y); + } + + dmxChangeKeyState (pDevice, detail, type); +} + +static Bool +dmxDeviceKeyboardEventCheck (DeviceIntPtr pDevice, + xcb_generic_event_t *event) +{ + DeviceIntPtr pKeyDev = pDevice; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pKeyDev); + DMXInputInfo *dmxInput = pDevPriv->dmxInput; + int reltype, type = event->response_type & 0x7f; + int id = pDevPriv->deviceId; + + switch (type) { + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE: { + xcb_key_press_event_t *xkey = (xcb_key_press_event_t *) event; + + dmxUpdateKeyStateFromEvent (pKeyDev, + xkey->event, + xkey->detail, + xkey->event_x, + xkey->event_y, + xkey->root_x, + xkey->root_y, + type); + } break; + case XCB_KEYMAP_NOTIFY: { + xcb_keymap_notify_event_t *xkeymap = + (xcb_keymap_notify_event_t *) event; + char state[32]; + + state[0] = 0; + memcpy (&state[1], xkeymap->keys, 31); - for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) - dmxInputInit(dmxInput); - if (!dmxeqInitialized()) { - dmxLog(dmxWarning, "Use keyboard/mouse pair with the first -input\n"); - dmxLog(dmxFatal, "At least one core keyboard/mouse pair required\n"); + dmxUpdateKeyState (pKeyDev, state); + } break; + case XCB_MAPPING_NOTIFY: { + xcb_mapping_notify_event_t *xmapping = + (xcb_mapping_notify_event_t *) event; + + if (xmapping->request == XCB_MAPPING_KEYBOARD) + dmxUpdateKeyboardMapping (pKeyDev, + xmapping->first_keycode, + xmapping->count); + } break; + case XCB_FOCUS_IN: { + xcb_focus_in_event_t *xfocus = (xcb_focus_in_event_t *) event; + + if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDeviceKeyboardActivate (pKeyDev); + } break; + case XCB_FOCUS_OUT: { + xcb_focus_out_event_t *xfocus = (xcb_focus_out_event_t *) event; + + if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDeviceKeyboardDeactivate (pKeyDev); + } break; + default: + if (id < 0) + return FALSE; + + reltype = type - dmxInput->eventBase; + + switch (reltype) { + case XCB_INPUT_DEVICE_VALUATOR: { + xcb_input_device_valuator_event_t *xvaluator = + (xcb_input_device_valuator_event_t *) event; + + if (id != (xvaluator->device_id & DEVICE_BITS)) + return FALSE; + + /* eat valuator events */ + } break; + case XCB_INPUT_DEVICE_KEY_PRESS: + case XCB_INPUT_DEVICE_KEY_RELEASE: { + xcb_input_device_key_press_event_t *xkey = + (xcb_input_device_key_press_event_t *) event; + + if (id != (xkey->device_id & DEVICE_BITS)) + return FALSE; + + dmxUpdateKeyStateFromEvent (pKeyDev, + xkey->event, + xkey->detail, + xkey->event_x, + xkey->event_y, + xkey->root_x, + xkey->root_y, + XCB_KEY_PRESS + + (reltype - XCB_INPUT_DEVICE_KEY_PRESS)); + } break; + case XCB_INPUT_DEVICE_STATE_NOTIFY: { + xcb_input_device_state_notify_event_t *xstate = + (xcb_input_device_state_notify_event_t *) event; + + if (id != (xstate->device_id & DEVICE_BITS)) + return FALSE; + + if (!(xstate->classes_reported & (1 << KeyClass))) + return FALSE; + + memset (pDevPriv->keysbuttons, 0, 32); + + if (xstate->response_type & MORE_EVENTS) + { + memcpy (pDevPriv->keysbuttons, xstate->keys, 4); + } + else + { + memcpy (pDevPriv->keysbuttons, xstate->keys, 4); + dmxUpdateKeyState (pKeyDev, pDevPriv->keysbuttons); + } + } break; + case XCB_INPUT_DEVICE_KEY_STATE_NOTIFY: { + xcb_input_device_key_state_notify_event_t *xstate = + (xcb_input_device_key_state_notify_event_t *) event; + + if (id != (xstate->device_id & DEVICE_BITS)) + return FALSE; + + memcpy (&pDevPriv->keysbuttons[4], xstate->keys, 28); + dmxUpdateKeyState (pKeyDev, pDevPriv->keysbuttons); + } break; + case XCB_INPUT_DEVICE_MAPPING_NOTIFY: { + xcb_input_device_mapping_notify_event_t *xmapping = + (xcb_input_device_mapping_notify_event_t *) event; + + if (id != (xmapping->device_id & DEVICE_BITS)) + return FALSE; + + if (xmapping->request == XCB_MAPPING_KEYBOARD) + dmxUpdateKeyboardMapping (pKeyDev, + xmapping->first_keycode, + xmapping->count); + } break; + case XCB_INPUT_FOCUS_IN: { + xcb_input_focus_in_event_t *xfocus = + (xcb_input_focus_in_event_t *) event; + + if (id != (xfocus->device_id & DEVICE_BITS)) + return FALSE; + + if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDeviceKeyboardActivate (pKeyDev); + } break; + case XCB_INPUT_FOCUS_OUT: { + dmx_xcb_input_focus_out_event_t *xfocus = + (dmx_xcb_input_focus_out_event_t *) event; + + if (id != (xfocus->device_id & DEVICE_BITS)) + return FALSE; + + if (xfocus->detail != XCB_NOTIFY_DETAIL_INFERIOR) + dmxDeviceKeyboardDeactivate (pKeyDev); + } break; + default: + return FALSE; + } } - mieqInit(); + return TRUE; } -/** Called from dix/dispatch.c in Dispatch() whenever input events - * require processing. All the work is done in the lower level - * routines. */ -void ProcessInputEvents(void) +Bool +dmxInputEventCheck (DMXInputInfo *dmxInput, + xcb_generic_event_t *event) { - int i; - DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pDevice = dmxInput->devs[i]; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + if ((*pDevPriv->EventCheck) (pDevice, event)) + return TRUE; + } - for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) - if (!dmxInput->detached && dmxInput->processInputEvents) - dmxInput->processInputEvents(dmxInput); + return FALSE; } -/** This routine is called from #dmxwindow.c whenever the layout of - * windows on the display might have changed. This information is used - * by input drivers (currently only the console driver) that provide - * information about window layout to the user. */ -void dmxUpdateWindowInfo(DMXUpdateType type, WindowPtr pWindow) +void +dmxInputGrabKeyboard (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow) { - int i; - DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pExtDevice = dmxInput->devs[i]; + + if (pExtDevice->u.master != pDevice) + continue; - for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) - if (!dmxInput->detached && dmxInput->updateWindowInfo) - dmxInput->updateWindowInfo(dmxInput, type, pWindow); + if (!IsKeyboardDevice (pExtDevice)) + continue; + + dmxDeviceGrabKeyboard (pExtDevice, pWindow); + } +} + +void +dmxInputUngrabKeyboard (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pExtDevice = dmxInput->devs[i]; + + if (pExtDevice->u.master != pDevice) + continue; + + if (!IsKeyboardDevice (pExtDevice)) + continue; + + dmxDeviceUngrabKeyboard (pExtDevice); + } +} + +void +dmxInputGrabPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow, + WindowPtr pConfineTo, + CursorPtr pCursor) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pExtDevice = dmxInput->devs[i]; + + if (pExtDevice->u.master != pDevice) + continue; + + if (!IsPointerDevice (pExtDevice)) + continue; + + dmxDeviceGrabPointer (pExtDevice, + pWindow, + pConfineTo, + pCursor); + } +} + +void +dmxInputUngrabPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pExtDevice = dmxInput->devs[i]; + + if (pExtDevice->u.master != pDevice) + continue; + + if (!IsPointerDevice (pExtDevice)) + continue; + + dmxDeviceUngrabPointer (pExtDevice); + } +} + +void +dmxInputWarpPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + int x, + int y) +{ + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + DeviceIntPtr pExtDevice = dmxInput->devs[i]; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pExtDevice); + + if (pExtDevice->u.master != pDevice) + continue; + + if (!IsPointerDevice (pExtDevice)) + continue; + + if (!pDevPriv->active) + continue; + + if (pDevPriv->deviceId >= 0) + { + dmx_xcb_warp_device_pointer_request_t warp = { + .src_win = dmxScreen->rootWin, + .dst_win = dmxScreen->rootWin, + .dst_x = x, + .dst_y = y, + .deviceid = pDevPriv->deviceId + }; + xcb_protocol_request_t request = { + 1, + &xcb_input_id, + DMX_XCB_WARP_DEVICE_POINTER, + FALSE + }; + struct iovec vector[] = { + { &warp, sizeof (warp) } + }; + + xcb_send_request (dmxScreen->connection, + 0, + vector, + &request); + } + else + { + xcb_warp_pointer (dmxScreen->connection, + dmxScreen->rootWin, dmxScreen->rootWin, + 0, 0, + 0, 0, + x, y); + } + } +} + +static void +dmxKeyboardBell (int volume, + DeviceIntPtr pDevice, + pointer arg, + int something) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (dmxScreen) + xcb_bell (dmxScreen->connection, volume); +} + +static int +dmxKeyboardOn (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + int nKeycode = setup->max_keycode - setup->min_keycode; + + pDevPriv->keycode = xalloc (nKeycode * sizeof (KeyCode)); + if (!pDevPriv->keycode) + return -1; + + pDevPriv->keySyms.map = (KeySym *) NULL; + pDevPriv->keySyms.mapWidth = 0; + pDevPriv->keySyms.minKeyCode = setup->min_keycode; + pDevPriv->keySyms.maxKeyCode = setup->max_keycode; + + dmxUpdateKeyboardMapping (pDevice, setup->min_keycode, nKeycode); + + if (pDevPriv->deviceId >= 0) + { + XEventClass cls[5]; + int type; + + pDevPriv->device = XOpenDevice (dmxScreen->beDisplay, + pDevPriv->deviceId); + if (!pDevPriv->device) + { + dmxLog (dmxWarning, "Cannot open %s device (id=%d) on %s\n", + pDevice->name, pDevPriv->deviceId, dmxScreen->name); + xfree (pDevPriv->keycode); + return -1; + } + + DeviceKeyPress (pDevPriv->device, type, cls[0]); + DeviceKeyRelease (pDevPriv->device, type, cls[1]); + DeviceStateNotify (pDevPriv->device, type, cls[2]); + DeviceFocusIn (pDevPriv->device, type, cls[3]); + DeviceFocusOut (pDevPriv->device, type, cls[4]); + + XLIB_PROLOGUE (dmxScreen); + XSelectExtensionEvent (dmxScreen->beDisplay, dmxScreen->rootWin, + cls, 5); + XLIB_EPILOGUE (dmxScreen); + } + else + { + dmxScreen->rootEventMask |= DMX_KEYBOARD_EVENT_MASK; + + XLIB_PROLOGUE (dmxScreen); + XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin, + dmxScreen->rootEventMask); + XLIB_EPILOGUE (dmxScreen); + } + + return Success; +} + +static void +dmxKeyboardOff (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->deviceId >= 0) + { + if (pDevPriv->device) + { + XLIB_PROLOGUE (dmxScreen); + XCloseDevice (dmxScreen->beDisplay, pDevPriv->device); + XLIB_EPILOGUE (dmxScreen); + + pDevPriv->device = NULL; + } + } + else + { + dmxScreen->rootEventMask &= ~DMX_KEYBOARD_EVENT_MASK; + + if (dmxScreen->scrnWin) + { + XLIB_PROLOGUE (dmxScreen); + XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin, + dmxScreen->rootEventMask); + XLIB_EPILOGUE (dmxScreen); + } + } + + if (pDevPriv->keySyms.map) + xfree (pDevPriv->keySyms.map); + + xfree (pDevPriv->keycode); +} + +static int +dmxKeyboardProc (DeviceIntPtr pDevice, + int what) +{ + DevicePtr pDev = (DevicePtr) pDevice; + CARD8 modMap[MAP_LENGTH]; + KeySymsRec keySyms; + +#ifdef XKB + XkbComponentNamesRec names; +#endif + + switch (what) { + case DEVICE_INIT: + keySyms.minKeyCode = 8; + keySyms.maxKeyCode = 255; + keySyms.mapWidth = 4; + keySyms.map = (KeySym *) Xcalloc (sizeof (KeySym), + (keySyms.maxKeyCode - + keySyms.minKeyCode + 1) * + keySyms.mapWidth); + if (!keySyms.map) + { + ErrorF ("[dmx] Couldn't allocate keymap\n"); + return BadAlloc; + } + + bzero ((char *) modMap, MAP_LENGTH); + +#ifdef XKB + if (!noXkbExtension) + { + bzero (&names, sizeof (names)); + + XkbSetRulesDflts ("base", "pc105", "us", NULL, NULL); + XkbInitKeyboardDeviceStruct (pDevice, + &names, + &keySyms, + modMap, + dmxKeyboardBell, + (KbdCtrlProcPtr) NoopDDA); + } + else +#endif + { + /* FIXME Our keymap here isn't exactly useful. */ + InitKeyboardDeviceStruct (pDev, + &keySyms, + modMap, + dmxKeyboardBell, + (KbdCtrlProcPtr) NoopDDA); + } + + xfree (keySyms.map); + break; + case DEVICE_ON: + pDev->on = 1; + dmxKeyboardOn (pDevice); + break; + case DEVICE_OFF: + pDev->on = 0; + dmxKeyboardOff (pDevice); + break; + case DEVICE_CLOSE: + if (pDev->on) + { + pDev->on = 0; + dmxKeyboardOff (pDevice); + } + break; + } + + return Success; +} + +static int +dmxPointerOn (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXInputInfo *dmxInput = pDevPriv->dmxInput; + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + + if (pDevPriv->deviceId >= 0) + { + XEventClass cls[6]; + int type; + + pDevPriv->device = XOpenDevice (dmxScreen->beDisplay, + pDevPriv->deviceId); + if (!pDevPriv->device) + { + dmxLog (dmxWarning, "Cannot open %s device (id=%d) on %s\n", + pDevice->name, pDevPriv->deviceId, dmxScreen->name); + return -1; + } + + DeviceMotionNotify (pDevPriv->device, type, cls[0]); + DeviceButtonPress (pDevPriv->device, type, cls[1]); + DeviceButtonRelease (pDevPriv->device, type, cls[2]); + DeviceButtonPressGrab (pDevPriv->device, type, cls[3]); + DeviceStateNotify (pDevPriv->device, type, cls[4]); + + cls[5] = (pDevPriv->device->device_id << 8) | + (dmxInput->eventBase + DMX_XCB_INPUT_DEVICE_LEAVE_NOTIFY); + + XLIB_PROLOGUE (dmxScreen); + XSelectExtensionEvent (dmxScreen->beDisplay, dmxScreen->rootWin, + cls, 6); + XLIB_EPILOGUE (dmxScreen); + } + else + { + dmxScreen->rootEventMask |= DMX_POINTER_EVENT_MASK; + + XLIB_PROLOGUE (dmxScreen); + XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin, + dmxScreen->rootEventMask); + XLIB_EPILOGUE (dmxScreen); + } + + return -1; +} + +static void +dmxPointerOff (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + + if (pDevPriv->deviceId >= 0) + { + if (pDevPriv->device) + { + XLIB_PROLOGUE (dmxScreen); + XCloseDevice (dmxScreen->beDisplay, pDevPriv->device); + XLIB_EPILOGUE (dmxScreen); + + pDevPriv->device = NULL; + } + } + else + { + dmxScreen->rootEventMask &= ~DMX_POINTER_EVENT_MASK; + + if (dmxScreen->scrnWin) + { + XLIB_PROLOGUE (dmxScreen); + XSelectInput (dmxScreen->beDisplay, dmxScreen->rootWin, + dmxScreen->rootEventMask); + XLIB_EPILOGUE (dmxScreen); + } + } +} + +static int +dmxPointerProc (DeviceIntPtr pDevice, + int what) +{ + DevicePtr pDev = (DevicePtr) pDevice; + BYTE map[33]; + int i; + + switch (what) { + case DEVICE_INIT: + for (i = 1; i <= 32; i++) + map[i] = i; + + InitPointerDeviceStruct (pDev, + map, 32, + (PtrCtrlProcPtr) NoopDDA, + GetMotionHistorySize (), 2); + + pDevice->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + pDevice->last.valuators[0] = pDevice->valuator->axisVal[0]; + pDevice->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + pDevice->last.valuators[1] = pDevice->valuator->axisVal[1]; + break; + case DEVICE_ON: + pDev->on = 1; + dmxPointerOn (pDevice); + break; + case DEVICE_OFF: + pDev->on = 0; + dmxPointerOff (pDevice); + break; + case DEVICE_CLOSE: + if (pDev->on) + { + pDev->on = 0; + dmxPointerOff (pDevice); + } + break; + } + + return Success; +} + +static char * +dmxMakeUniqueDeviceName (DMXInputInfo *dmxInput, + const char *deviceName) +{ + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + char *name; + int i, n = 2; + +#define LEN 32 + + name = xalloc (strlen (dmxScreen->name) + strlen (deviceName) + LEN); + if (!name) + return NULL; + + sprintf (name, "%s's %s", dmxScreen->name, deviceName); + + do { + for (i = 0; i < dmxInput->numDevs; i++) + { + if (strcmp (dmxInput->devs[i]->name, name) == 0) + { + sprintf (name, "%s's %s%d", dmxScreen->name, deviceName, n++); + break; + } + } + } while (i < dmxInput->numDevs); + + return name; +} + +static DeviceIntPtr +dmxAddInputDevice (DMXInputInfo *dmxInput, + DeviceProc deviceProc, + const char *deviceName, + int deviceId, + int masterId, + Bool (*EventCheck) (DeviceIntPtr, + xcb_generic_event_t *), + Bool (*ReplyCheck) (DeviceIntPtr, + unsigned int, + xcb_generic_reply_t *)) +{ + DeviceIntPtr pDevice, *devs; + char *name; + + devs = xrealloc (dmxInput->devs, sizeof (DeviceIntPtr) * + (dmxInput->numDevs + 1)); + if (!devs) + return NULL; + + dmxInput->devs = devs; + + name = dmxMakeUniqueDeviceName (dmxInput, deviceName); + if (!name) + return NULL; + + pDevice = AddInputDevice (serverClient, deviceProc, TRUE); + if (pDevice) + { + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + + pDevice->name = name; + + pDevPriv->dmxInput = dmxInput; + pDevPriv->deviceId = deviceId; + pDevPriv->masterId = masterId; + pDevPriv->device = NULL; + pDevPriv->fakeGrab = xFalse; + pDevPriv->grabStatus = !XCB_GRAB_STATUS_SUCCESS; + pDevPriv->active = xFalse; + pDevPriv->EventCheck = EventCheck; + pDevPriv->ReplyCheck = ReplyCheck; + + memset (pDevPriv->state, 0, sizeof (pDevPriv->state)); + memset (pDevPriv->keysbuttons, 0, sizeof (pDevPriv->keysbuttons)); + + pDevPriv->grab.sequence = 0; + + RegisterOtherDevice (pDevice); + + dmxInput->devs[dmxInput->numDevs] = pDevice; + dmxInput->numDevs++; + + dmxLogInput (dmxInput, "Added extension device called %s\n", name); + } + else + { + xfree (name); + } + + return pDevice; +} + +static XID +dmxGetMasterDevice (XDeviceInfo *device) +{ + XAttachInfoPtr ai; + int i; + + for (i = 0, ai = (XAttachInfoPtr) device->inputclassinfo; + i < device->num_classes; + ai = (XAttachInfoPtr) ((char *) ai + ai->length), i++) + if (ai->class == AttachClass) + return ai->attached; + + return -1; +} + +static Bool +dmxInputAddExtensionDevices (DMXInputInfo *dmxInput) +{ + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput; + XExtensionVersion *ext; + XDeviceInfo *devices; + int num; + int i; + + ext = XQueryInputVersion (dmxScreen->beDisplay, XI_2_Major, XI_2_Minor); + if (!ext || ext == (XExtensionVersion *) NoSuchExtension) + { + dmxLogInput (dmxInput, "%s is not available\n", INAME); + return FALSE; + } + + /* Only use XInput Extension if 2.0 or greater */ + if (ext->major_version < 2) + { + dmxLogInput (dmxInput, "%s version %d.%d is too old\n", + INAME, ext->major_version, ext->minor_version); + XFree (ext); + return FALSE; + } + + XQueryExtension (dmxScreen->beDisplay, + INAME, + &i, + &dmxInput->eventBase, + &i); + + dmxLogInput (dmxInput, "Locating devices on %s (%s version %d.%d)\n", + dmxScreen->name, INAME, + ext->major_version, ext->minor_version); + + XFree (ext); + + devices = XListInputDevices (dmxScreen->beDisplay, &num); + if (devices) + { + for (i = 0; i < num; i++) + { + switch (devices[i].use) { + case IsXKeyboard: + dmxAddInputDevice (dmxInput, + dmxKeyboardProc, + devices[i].name, + devices[i].id, + dmxGetMasterDevice (&devices[i]), + dmxDeviceKeyboardEventCheck, + dmxDeviceKeyboardReplyCheck); + break; + case IsXPointer: + dmxAddInputDevice (dmxInput, + dmxPointerProc, + devices[i].name, + devices[i].id, + dmxGetMasterDevice (&devices[i]), + dmxDevicePointerEventCheck, + dmxDevicePointerReplyCheck); + break; + } + } + + XFreeDeviceList (devices); + } + + return TRUE; +} + +static void +dmxInputAddDevices (DMXInputInfo *dmxInput) +{ + if (!dmxInputAddExtensionDevices (dmxInput)) + { + dmxLogInput (dmxInput, "Using core devices from %s\n", + ((DMXScreenInfo *) dmxInput)->name); + + dmxAddInputDevice (dmxInput, + dmxKeyboardProc, "core keyboard", + -1, -1, + dmxDeviceKeyboardEventCheck, + dmxDeviceKeyboardReplyCheck); + dmxAddInputDevice (dmxInput, + dmxPointerProc, "core pointer", + -1, -1, + dmxDevicePointerEventCheck, + dmxDevicePointerReplyCheck); + } +} + +static void +dmxInputRemoveDevices (DMXInputInfo *dmxInput) +{ + dmxLogInput (dmxInput, "Removing devices from %s\n", + ((DMXScreenInfo *) dmxInput)->name); + + while (dmxInput->numDevs) + DeleteInputDeviceRequest (*dmxInput->devs); +} + +int +dmxInputEnable (DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + { + dmxLogInput (dmxInput, "Activate device id %d: %s\n", + dmxInput->devs[i]->id, dmxInput->devs[i]->name); + + if (ActivateDevice (dmxInput->devs[i]) != Success) + return BadImplementation; + + if (!EnableDevice (dmxInput->devs[i])) + return BadImplementation; + } + + return 0; +} + +int +dmxInputDisable (DMXInputInfo *dmxInput) +{ + char state[32]; + int i; + + memset (state, 0, sizeof (state)); + + for (i = 0; i < dmxInput->numDevs; i++) + { + dmxLogInput (dmxInput, "Disable device id %d: %s\n", + dmxInput->devs[i]->id, dmxInput->devs[i]->name); + + if (IsKeyboardDevice (dmxInput->devs[i])) + dmxUpdateKeyState (dmxInput->devs[i], state); + else if (IsPointerDevice (dmxInput->devs[i])) + dmxUpdateButtonState (dmxInput->devs[i], state); + + DisableDevice (dmxInput->devs[i]); + } + + return 0; +} + +int +dmxInputAttach (DMXInputInfo *dmxInput) +{ + dmxInputAddDevices (dmxInput); + + return 0; +} + +int +dmxInputDetach (DMXInputInfo *dmxInput) +{ + ProcessInputEvents (); + + dmxInputRemoveDevices (dmxInput); + + return 0; +} + +void +dmxInputInit (DMXInputInfo *dmxInput) +{ + dmxInput->devs = NULL; + dmxInput->numDevs = 0; + dmxInput->eventBase = 0; +} + +void +dmxInputFini (DMXInputInfo *dmxInput) +{ + if (dmxInput->devs) + xfree (dmxInput->devs); +} + +Bool +LegalModifier (unsigned int key, + DeviceIntPtr pDev) +{ + return TRUE; +} + +static void +dmxInitMasterKeyboard (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + DMX_WRAP (ActivateGrab, dmxActivateKeyboardGrab, pDevPriv, + &pDev->deviceGrab); + DMX_WRAP (DeactivateGrab, dmxDeactivateKeyboardGrab, pDevPriv, + &pDev->deviceGrab); +} + +static void +dmxInitMasterPointer (DeviceIntPtr pDev) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDev); + + DMX_WRAP (ActivateGrab, dmxActivatePointerGrab, pDevPriv, + &pDev->deviceGrab); + DMX_WRAP (DeactivateGrab, dmxDeactivatePointerGrab, pDevPriv, + &pDev->deviceGrab); +} + +void +InitInput (int argc, char **argv) +{ + int i; + + GetEventList (&dmxEvents); + + for (i = 0; i < dmxNumScreens; i++) + if (dmxScreens[i].beDisplay && !dmxScreens[i].virtualFb) + dmxInputAddDevices (&dmxScreens[i].input); + + /* XXX: init devices created using XChangeDeviceHierarchy */ + dmxInitMasterKeyboard (inputInfo.keyboard); + dmxInitMasterPointer (inputInfo.pointer); + + mieqInit (); +} + +void +ProcessInputEvents (void) +{ + mieqProcessInputEvents (); +} + +void +CloseInputDevice (DeviceIntPtr pDevice, + ClientPtr client) +{ +} + +void +AddOtherInputDevices (void) +{ +} + +void +OpenInputDevice (DeviceIntPtr pDevice, + ClientPtr client, + int *status) +{ + *status = XaceHook (XACE_DEVICE_ACCESS, client, pDevice, DixReadAccess); } int -NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev) +SetDeviceMode (ClientPtr client, + DeviceIntPtr pDevice, + int mode) +{ + return BadMatch; +} + +int +SetDeviceValuators (ClientPtr client, + DeviceIntPtr pDevice, + int *valuators, + int first_valuator, + int num_valuators) +{ + return BadMatch; +} + +int +ChangeDeviceControl (ClientPtr client, + DeviceIntPtr pDevice, + xDeviceCtl *control) +{ + return BadMatch; +} + +int +NewInputDeviceRequest (InputOption *options, + DeviceIntPtr *ppDevice) { return BadRequest; } void -DeleteInputDeviceRequest(DeviceIntPtr pDev) +DeleteInputDeviceRequest (DeviceIntPtr pDevice) +{ + int i, j; + + RemoveDevice (pDevice); + + for (i = 0; i < dmxNumScreens; i++) + { + for (j = 0; j < dmxScreens[i].input.numDevs; j++) + { + if (dmxScreens[i].input.devs[j] == pDevice) + { + for (; j < dmxScreens[i].input.numDevs - 1; j++) + dmxScreens[i].input.devs[j] = + dmxScreens[i].input.devs[j + 1]; + + dmxScreens[i].input.numDevs--; + return; + } + } + } +} + +void +DDXRingBell (int volume, + int pitch, + int duration) { } diff --git a/hw/dmx/dmxinput.h b/hw/dmx/dmxinput.h index 7af7b18..caacab0 100644 --- a/hw/dmx/dmxinput.h +++ b/hw/dmx/dmxinput.h @@ -1,162 +1,121 @@ /* - * Copyright 2001,2002 Red Hat Inc., Durham, North Carolina. + * Copyright © 2008 Novell, Inc. * - * All Rights Reserved. + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Authors: - * David H. Dawes <dawes@xfree86.org> - * Kevin E. Martin <kem@redhat.com> - * Rickard E. (Rik) Faith <faith@redhat.com> + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. * + * Author: David Reveman <davidr@novell.com> */ -/** \file - * This file provides access to: - * - global variables available to all hw/dmx routines, and - * - enumerations and typedefs needed by input routines in hw/dmx (and - * hw/dmx/input). - * - * The goal is that no files in hw/dmx should include header files from - * hw/dmx/input -- the interface defined here should be the only - * interface exported to the hw/dmx layer. \see input/dmxinputinit.c. - */ - #ifndef DMXINPUT_H #define DMXINPUT_H -/** Maximum number of file descriptors for SIGIO handling */ -#define DMX_MAX_SIGIO_FDS 4 - -struct _DMXInputInfo; - -/** Reason why window layout was updated. */ -typedef enum { - DMX_UPDATE_REALIZE, /**< Window realized */ - DMX_UPDATE_UNREALIZE, /**< Window unrealized */ - DMX_UPDATE_RESTACK, /**< Stacking order changed */ - DMX_UPDATE_COPY, /**< Window copied */ - DMX_UPDATE_RESIZE, /**< Window resized */ - DMX_UPDATE_REPARENT /**< Window reparented */ -} DMXUpdateType; - -typedef void (*ProcessInputEventsProc)(struct _DMXInputInfo *); -typedef void (*UpdateWindowInfoProc)(struct _DMXInputInfo *, - DMXUpdateType, WindowPtr); - -/** An opaque structure that is only exposed in the dmx/input layer. */ -typedef struct _DMXLocalInputInfo *DMXLocalInputInfoPtr; - -/** State of the SIGIO engine */ -typedef enum { - DMX_NOSIGIO = 0, /**< Device does not use SIGIO at all. */ - DMX_USESIGIO, /**< Device can use SIGIO, but is not - * (e.g., because the VT is switch - * away). */ - DMX_ACTIVESIGIO /**< Device is currently using SIGIO. */ -} dmxSigioState; - -/** DMXInputInfo is typedef'd in #dmx.h so that all routines can have - * access to the global pointers. However, the elements are only - * available to input-related routines. */ -struct _DMXInputInfo { - const char *name; /**< Name of input display or device - * (from command line or config - * file) */ - Bool freename; /**< If true, free name on destroy */ - Bool detached; /**< If true, input screen is detached */ - int inputIdx; /**< Index into #dmxInputs global */ - int scrnIdx; /**< Index into #dmxScreens global */ - Bool core; /**< If True, initialize these - * devices as devices that send core - * events */ - Bool console; /**< True if console and backend - * input share the same backend - * display */ - - Bool windows; /**< True if window outlines are - * draw in console */ - - ProcessInputEventsProc processInputEvents; - UpdateWindowInfoProc updateWindowInfo; - - /* Local input information */ - dmxSigioState sigioState; /**< Current stat */ - int sigioFdCount; /**< Number of fds in use */ - int sigioFd[DMX_MAX_SIGIO_FDS]; /**< List of fds */ - Bool sigioAdded[DMX_MAX_SIGIO_FDS]; /**< Active fds */ - - - /** True if a VT switch is pending, but has not yet happened. */ - int vt_switch_pending; - - /** True if a VT switch has happened. */ - int vt_switched; - - /** Number of devices handled in this _DMXInputInfo structure. */ - int numDevs; - - /** List of actual input devices. Each _DMXInputInfo structure can - * refer to more than one device. For example, the keyboard and the - * pointer of a backend display; or all of the XInput extension - * devices on a backend display. */ - DMXLocalInputInfoPtr *devs; - - char *keycodes; /**< XKB keycodes from command line */ - char *symbols; /**< XKB symbols from command line */ - char *geometry; /**< XKB geometry from command line */ -}; - -extern int dmxNumInputs; /**< Number of #dmxInputs */ -extern DMXInputInfo *dmxInputs; /**< List of inputs */ - -extern void dmxInputInit(DMXInputInfo *dmxInput); -extern void dmxInputReInit(DMXInputInfo *dmxInput); -extern void dmxInputLateReInit(DMXInputInfo *dmxInput); -extern void dmxInputFree(DMXInputInfo *dmxInput); -extern void dmxInputLogDevices(void); -extern void dmxUpdateWindowInfo(DMXUpdateType type, WindowPtr pWindow); - -/* These functions are defined in input/dmxeq.c */ -extern Bool dmxeqInitialized(void); -extern void dmxeqEnqueue(DeviceIntPtr pDev, xEvent *e); -extern void dmxeqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool fromDIX); - -/* This type is used in input/dmxevents.c. Also, these functions are - * defined in input/dmxevents.c */ -typedef enum { - DMX_NO_BLOCK = 0, - DMX_BLOCK = 1 -} DMXBlockType; - -extern void dmxGetGlobalPosition(int *x, int *y); -extern DMXScreenInfo *dmxFindFirstScreen(int x, int y); -extern void dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, - DMXBlockType block); - -/* Support for dynamic addition of inputs. This functions is defined in - * config/dmxconfig.c */ -extern DMXInputInfo *dmxConfigAddInput(const char *name, int core); +extern DevPrivateKey dmxDevicePrivateKey; + +/** Device private area. */ +typedef struct _dmxDevicePriv { + DMXInputInfo *dmxInput; + long deviceId; + long masterId; + XDevice *device; + char state[32]; + char keysbuttons[32]; + KeySymsRec keySyms; + KeyCode *keycode; + xcb_void_cookie_t grab; + int grabStatus; + Bool fakeGrab; + Bool active; + + Bool (*EventCheck) (DeviceIntPtr, xcb_generic_event_t *); + Bool (*ReplyCheck) (DeviceIntPtr, unsigned int, xcb_generic_reply_t *); + + void (*ActivateGrab) (DeviceIntPtr, GrabPtr, TimeStamp, Bool); + void (*DeactivateGrab) (DeviceIntPtr); +} dmxDevicePrivRec, *dmxDevicePrivPtr; + +#define DMX_GET_DEVICE_PRIV(_pDev) \ + ((dmxDevicePrivPtr)dixLookupPrivate(&(_pDev)->devPrivates, \ + dmxDevicePrivateKey)) + +void +dmxInputInit (DMXInputInfo *dmxInput); + +void +dmxInputLogDevices (void); + +Bool +dmxInputEventCheck (DMXInputInfo *dmxInput, + xcb_generic_event_t *event); + +Bool +dmxFakeMotion (DMXInputInfo *dmxInput, + int x, + int y); + +void +dmxEndFakeMotion (DMXInputInfo *dmxInput); + +void +dmxInputGrabKeyboard (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow); + +void +dmxInputUngrabKeyboard (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow); + +void +dmxInputGrabPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow, + WindowPtr pConfineTo, + CursorPtr pCursor); + +void +dmxInputUngrabPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + WindowPtr pWindow); + +void +dmxInputWarpPointer (DMXInputInfo *dmxInput, + DeviceIntPtr pDevice, + int x, + int y); + +int +dmxInputEnable (DMXInputInfo *dmxInput); + +int +dmxInputDisable (DMXInputInfo *dmxInput); + +int +dmxInputAttach (DMXInputInfo *dmxInput); + +int +dmxInputDetach (DMXInputInfo *dmxInput); + +void +dmxInputInit (DMXInputInfo *dmxInput); + +void +dmxInputFini (DMXInputInfo *dmxInput); + #endif /* DMXINPUT_H */ diff --git a/hw/dmx/dmxlaunch.c b/hw/dmx/dmxlaunch.c new file mode 100644 index 0000000..4cab118 --- /dev/null +++ b/hw/dmx/dmxlaunch.c @@ -0,0 +1,432 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Authors: David Reveman <davidr@novell.com> + * Matthias Hopf <mhopf@suse.de> + */ + +#include "dmx.h" +#include "dmxlaunch.h" +#include "dmxinit.h" +#include "opaque.h" + +#include <X11/Xauth.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <signal.h> +#include <setjmp.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <libgen.h> +#include <fcntl.h> + +typedef void (*sighandler_t) (int); + +#define XBE_DIE_TIMEOUT 3 +#define XBE_DEV_RANDOM "/dev/urandom" + +static char xbeAuthBuf[256]; +static char *xbeAuthTempl = "/tmp/.Xdmx-auth-XXXXXX"; +static char *xbeAuth = NULL; + +static char *xbeProgs[] = { "/var/X11R6/bin/Xbackend", "/usr/bin/X" }; +static char *xbeProg = NULL; + +static char xbeDisplayBuf[256]; +static char *xbeDisplay = NULL; +static int xbeDisplayOffset = 53; + +static pid_t xbePid = 0; +static int receivedUsr1 = 0; +static jmp_buf jumpbuf; + +static char **xbeArgv = 0; +static int nXbeArgv = 0; + +static int +dmxAddXbeArguments (char **argv, + int n) +{ + char **newArgv; + int i; + + newArgv = xrealloc (xbeArgv, sizeof (char *) * (nXbeArgv + n)); + if (!newArgv) + return 0; + + for (i = 0; i < n; i++) + newArgv[nXbeArgv + i] = argv[i]; + + xbeArgv = newArgv; + nXbeArgv += n; + + return n; +} + +static void +sigAlarm (int sig) +{ + ErrorF ("%s won't die, killing it\n", basename (xbeProg)); + + kill (xbePid, SIGKILL); + if (xbePid) + while (waitpid (xbePid, NULL, 0) == -1 && errno == EINTR); +} + +void +dmxAbortDisplay (void) +{ + sighandler_t oldSigAlarm; + unsigned int oldAlarm; + int status = 0; + char *name; + + if (!xbePid) + return; + + name = basename (xbeProg); + + oldAlarm = alarm (0); + oldSigAlarm = signal (SIGALRM, sigAlarm); + + kill (xbePid, SIGTERM); + + alarm (XBE_DIE_TIMEOUT); + while (waitpid (xbePid, &status, 0) == -1 && errno == EINTR); + alarm (0); + + signal (SIGALRM, oldSigAlarm); + alarm (oldAlarm); + + if (WIFEXITED (status)) + { + if (WEXITSTATUS (status)) + ErrorF ("%s died, exit status %d\n", name, WEXITSTATUS (status)); + } + else if (WIFSIGNALED (status)) + ErrorF ("%s died, signal %d\n", name, WTERMSIG (status)); + else + ErrorF ("%s died, dubious exit\n", name); + + if (xbeAuth) + unlink (xbeAuth); + + xbePid = 0; +} + +static void +sigUsr1Waiting (int sig) +{ + signal (sig, sigUsr1Waiting); + receivedUsr1++; +} + +static void +sigUsr1Jump (int sig) +{ + +#ifdef SIG_BLOCK + sigset_t set; +#endif + + signal (sig, sigUsr1Waiting); + +#ifdef SIG_BLOCK + sigemptyset (&set); + sigaddset (&set, SIGUSR1); + sigprocmask (SIG_UNBLOCK, &set, NULL); +#endif + + longjmp (jumpbuf, 1); +} + +#define AUTH_DATA_LEN 16 /* bytes of authorization data */ + +static Bool +dmxSetupAuth (char *name, int authFd) +{ + Xauth auth; + int randomFd, i; + ssize_t bytes, size; + char authHost[256]; + char authData[AUTH_DATA_LEN]; + char realProg[PATH_MAX], buf[PATH_MAX]; + FILE *file; + int virtualFb = FALSE; + + auth.family = FamilyLocal; + + gethostname (authHost, sizeof (authHost)); + + auth.address = authHost; + auth.address_length = strlen (authHost); + + auth.number = strrchr (xbeDisplay, ':'); + if (!auth.number) + { + ErrorF ("Bad back-end X display name: %s\n", xbeDisplay); + return FALSE; + } + + auth.number++; + + auth.number_length = strlen (auth.number); + if (!auth.number_length) + { + ErrorF ("Bad back-end X display name: %s\n", xbeDisplay); + return FALSE; + } + + auth.name = "MIT-MAGIC-COOKIE-1"; + auth.name_length = strlen (auth.name); + + randomFd = open (XBE_DEV_RANDOM, O_RDONLY); + if (randomFd == -1) + { + ErrorF ("Failed to open " XBE_DEV_RANDOM "\n"); + return FALSE; + } + + bytes = 0; + do { + size = read (randomFd, authData + bytes, AUTH_DATA_LEN - bytes); + if (size <= 0) + break; + + bytes += size; + } while (bytes != AUTH_DATA_LEN); + + close (randomFd); + + if (bytes != AUTH_DATA_LEN) + { + ErrorF ("Failed to read %d random bytes from " XBE_DEV_RANDOM "\n", + AUTH_DATA_LEN); + return FALSE; + } + + auth.data = authData; + auth.data_length = AUTH_DATA_LEN; + + file = fdopen (authFd, "w"); + if (!file) + { + ErrorF ("Failed to open authorization file: %s\n", name); + close (authFd); + return FALSE; + } + + XauWriteAuth (file, &auth); + fclose (file); + + strcpy (realProg, xbeProg); + +#define MAX_SYMLINKS 32 + + for (i = 0; i < MAX_SYMLINKS; i++) + { + size = readlink (realProg, buf, sizeof (buf) - 1); + if (size == -1) + break; + + memcpy (realProg, buf, size); + realProg[size] = '\0'; + } + + /* a bit hackish but very useful */ + if (strcmp (basename (realProg), "Xvfb") == 0 || + strcmp (basename (realProg), "Xfake") == 0) + virtualFb = TRUE; + + dmxAddScreen (basename (realProg), + xbeDisplay, + auth.name, + auth.name_length, + auth.data, + auth.data_length, + virtualFb); + + return TRUE; +} + +Bool +dmxLaunchDisplay (int argc, char *argv[], int index, char *vt) +{ + sighandler_t oldSigUsr1; + pid_t pid; + char *name; + char *auth[] = { "-auth", xbeAuthBuf }; + char *defs[] = { "-terminate", "-nolisten", "tcp" }; + char *endArg = NULL; + int authFd; + int mask; + + if (xbePid) + return FALSE; + + if (xbeArgv) + { + free (xbeArgv); + xbeArgv = NULL; + nXbeArgv = 0; + } + + receivedUsr1 = 0; + + strcpy (xbeAuthBuf, xbeAuthTempl); + mask = umask (0077); + authFd = mkstemp (xbeAuthBuf); + umask (mask); + if (authFd == -1) + FatalError ("Failed to generate unique authorization file\n"); + + xbeAuth = xbeAuthBuf; + + if (index && index < argc) + { + xbeProg = argv[index]; + } + else + { + struct stat buf; + int i; + + for (i = 0; i < sizeof (xbeProgs) / sizeof (char *); i++) + { + if (stat (xbeProgs[i], &buf) == 0) + { + xbeProg = xbeProgs[i]; + break; + } + } + + if (!xbeProg) + FatalError ("Can't find X server executable\n"); + } + + if (!dmxAddXbeArguments (&xbeProg, 1)) + return FALSE; + + if (!dmxAddXbeArguments (auth, sizeof (auth) / sizeof (char *))) + return FALSE; + + xbeDisplay = xbeDisplayBuf; + sprintf (xbeDisplay, ":%d", xbeDisplayOffset + atoi (display)); + + if (index) + { + int i; + + for (i = index + 1; i < argc; i++) + { + if (*argv[i] == ':') + { + xbeDisplay = argv[i]; + break; + } + } + + if (i >= argc) + if (!dmxAddXbeArguments (&xbeDisplay, 1)) + return FALSE; + + if (argc > index) + if (!dmxAddXbeArguments (&argv[index + 1], argc - index)) + return FALSE; + } + else + { + if (!dmxAddXbeArguments (&xbeDisplay, 1)) + return FALSE; + + if (!dmxAddXbeArguments (defs, sizeof (defs) / sizeof (char *))) + return FALSE; + } + + if (vt) + if (!dmxAddXbeArguments (&vt, 1)) + return FALSE; + + if (!dmxAddXbeArguments (&endArg, 1)) + return FALSE; + + name = basename (xbeProg); + + if (!dmxSetupAuth (xbeAuth, authFd)) + FatalError ("Failed to set up authorization: %s\n", xbeAuth); + + oldSigUsr1 = signal (SIGUSR1, sigUsr1Waiting); + + pid = fork (); + + switch (pid) { + case -1: + perror ("fork"); + FatalError ("fork"); + break; + case 0: + signal (SIGUSR1, SIG_IGN); + execv (xbeArgv[0], xbeArgv); + perror (xbeArgv[0]); + exit (2); + break; + default: + xbePid = pid; + break; + } + + for (;;) + { + int status; + + signal (SIGUSR1, sigUsr1Waiting); + if (setjmp (jumpbuf)) + break; + + signal (SIGUSR1, sigUsr1Jump); + if (receivedUsr1) + break; + + if (waitpid (xbePid, &status, 0) != -1) + { + if (WIFEXITED (status)) + { + FatalError ("%s died, exit status %d\n", name, + WEXITSTATUS (status)); + } + else if (WIFSIGNALED (status)) + FatalError ("%s died, signal %d\n", name, WTERMSIG (status)); + else + FatalError ("%s died, dubious exit\n", name); + } + } + + signal (SIGUSR1, oldSigUsr1); + + return TRUE; +} diff --git a/hw/dmx/dmxlaunch.h b/hw/dmx/dmxlaunch.h new file mode 100644 index 0000000..beef622 --- /dev/null +++ b/hw/dmx/dmxlaunch.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Authors: David Reveman <davidr@novell.com> + */ + +#ifndef DMXLAUNCH_H +#define DMXLAUNCH_H + +extern Bool dmxLaunchDisplay (int argc, char *argv[], int index, char *vt); +extern void dmxAbortDisplay (void); + +#endif /* DMXLAUNCH_H */ diff --git a/hw/dmx/dmxlog.c b/hw/dmx/dmxlog.c index 94b8035..69bee7a 100644 --- a/hw/dmx/dmxlog.c +++ b/hw/dmx/dmxlog.c @@ -124,21 +124,12 @@ static void dmxHeader(dmxLogLevel logLevel, DMXInputInfo *dmxInput, case dmxFatal: type = "Fatal Error"; break; } - if (dmxInput && dmxScreen) { - ErrorF("(%s) dmx[i%d/%s;o%d/%s]: ", type, - dmxInput->inputIdx, dmxInput->name, - dmxScreen->index, dmxScreen->name); - } else if (dmxScreen) { - ErrorF("(%s) dmx[o%d/%s]: ", type, - dmxScreen->index, dmxScreen->name); - } else if (dmxInput) { - const char *pt = strchr(dmxInput->name, ','); - int len = (pt - ? (size_t)(pt-dmxInput->name) - : strlen(dmxInput->name)); - - ErrorF("(%s) dmx[i%d/%*.*s]: ", type, - dmxInput->inputIdx, len, len, dmxInput->name); + if (dmxInput) + dmxScreen = (DMXScreenInfo *) dmxInput; + + if (dmxScreen) { + ErrorF("(%s) dmx[o%d/%s/%s]: ", type, + dmxScreen->index, dmxScreen->display, dmxScreen->name); } else { ErrorF("(%s) dmx: ", type); } diff --git a/hw/dmx/dmxpict.c b/hw/dmx/dmxpict.c index 37dfa10..460cdff 100644 --- a/hw/dmx/dmxpict.c +++ b/hw/dmx/dmxpict.c @@ -64,27 +64,113 @@ static int (*dmxSaveRenderVector[RenderNumberRequests])(ClientPtr); static int dmxProcRenderCreateGlyphSet(ClientPtr client); -static int dmxProcRenderFreeGlyphSet(ClientPtr client); +static int dmxProcRenderReferenceGlyphSet(ClientPtr client); static int dmxProcRenderAddGlyphs(ClientPtr client); static int dmxProcRenderFreeGlyphs(ClientPtr client); static int dmxProcRenderCompositeGlyphs(ClientPtr client); static int dmxProcRenderSetPictureTransform(ClientPtr client); static int dmxProcRenderSetPictureFilter(ClientPtr client); +static int dmxProcRenderChangePicture (ClientPtr client); #if 0 /* FIXME: Not (yet) supported */ static int dmxProcRenderCreateCursor(ClientPtr client); static int dmxProcRenderCreateAnimCursor(ClientPtr client); #endif +static int dmxProcRenderCreateSolidFill (ClientPtr pClient); +static int dmxProcRenderCreateLinearGradient (ClientPtr pClient); +static int dmxProcRenderCreateRadialGradient (ClientPtr pClient); +static int dmxProcRenderCreateConicalGradient (ClientPtr pClient); -/** Catch errors that might occur when allocating Glyph Sets. Errors - * are saved in dmxGlyphLastError for later handling. */ -static int dmxGlyphLastError; -static int dmxGlyphErrorHandler(Display *dpy, XErrorEvent *ev) +unsigned long DMX_GLYPHSET; +unsigned long DMX_SOURCEPICT; + +static int +dmxFreeGlyphSet (pointer value, + XID gid) { - dmxGlyphLastError = ev->error_code; - return 0; + GlyphSetPtr glyphSet = (GlyphSetPtr) value; + + if (glyphSet->refcnt <= 2) { + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + int i; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) { + if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet)) + dmxSync(dmxScreen, FALSE); + } + } + + MAXSCREENSFREE(glyphPriv->glyphSets); + } + + return FreeGlyphSet (value, gid); } +static int +dmxFreeSourcePict (pointer value, + XID gid) +{ + PicturePtr pPicture = (PicturePtr) value; + + if (pPicture->refcnt <= 2) { + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + int i; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) + dmxBEFreePicture (screenInfo.screens[i], pPicture); + } + + MAXSCREENSFREE(pPictPriv->sourcePict); + } + + return FreePicture (value, gid); +} + +static Bool +dmxRealizeGlyph (ScreenPtr pScreen, + GlyphPtr glyph) +{ + PictureScreenPtr ps = GetPictureScreen (pScreen); + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int ret; + + if (pScreen->myNum == 0) + *((PrivateRec **) dixLookupPrivateAddr (&(glyph)->devPrivates, + dmxGlyphPrivateKey)) = NULL; + + DMX_UNWRAP (RealizeGlyph, dmxScreen, ps); + ret = (*ps->RealizeGlyph) (pScreen, glyph); + DMX_WRAP (RealizeGlyph, dmxRealizeGlyph, dmxScreen, ps); + + return ret; +} + +static void +dmxUnrealizeGlyph (ScreenPtr pScreen, + GlyphPtr glyph) +{ + PictureScreenPtr ps = GetPictureScreen (pScreen); + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (pScreen->myNum == 0) + { + char *data; + + data = dixLookupPrivate (&(glyph)->devPrivates, dmxGlyphPrivateKey); + if (data) + xfree (data); + } + + DMX_UNWRAP (UnrealizeGlyph, dmxScreen, ps); + (*ps->UnrealizeGlyph) (pScreen, glyph); + DMX_WRAP (UnrealizeGlyph, dmxUnrealizeGlyph, dmxScreen, ps); +} /** Initialize the Proc Vector for the RENDER extension. The functions * here cannot be handled by the mi layer RENDER hooks either because @@ -96,13 +182,16 @@ void dmxInitRender(void) { int i; + DMX_GLYPHSET = CreateNewResourceType (dmxFreeGlyphSet); + DMX_SOURCEPICT = CreateNewResourceType (dmxFreeSourcePict); + for (i = 0; i < RenderNumberRequests; i++) dmxSaveRenderVector[i] = ProcRenderVector[i]; ProcRenderVector[X_RenderCreateGlyphSet] = dmxProcRenderCreateGlyphSet; - ProcRenderVector[X_RenderFreeGlyphSet] - = dmxProcRenderFreeGlyphSet; + ProcRenderVector[X_RenderReferenceGlyphSet] + = dmxProcRenderReferenceGlyphSet; ProcRenderVector[X_RenderAddGlyphs] = dmxProcRenderAddGlyphs; ProcRenderVector[X_RenderFreeGlyphs] @@ -117,6 +206,16 @@ void dmxInitRender(void) = dmxProcRenderSetPictureTransform; ProcRenderVector[X_RenderSetPictureFilter] = dmxProcRenderSetPictureFilter; + ProcRenderVector[X_RenderChangePicture] + = dmxProcRenderChangePicture; + ProcRenderVector[X_RenderCreateSolidFill] = + dmxProcRenderCreateSolidFill; + ProcRenderVector[X_RenderCreateLinearGradient] = + dmxProcRenderCreateLinearGradient; + ProcRenderVector[X_RenderCreateRadialGradient] = + dmxProcRenderCreateRadialGradient; + ProcRenderVector[X_RenderCreateConicalGradient] = + dmxProcRenderCreateConicalGradient; } /** Reset the Proc Vector for the RENDER extension back to the original @@ -130,6 +229,245 @@ void dmxResetRender(void) ProcRenderVector[i] = dmxSaveRenderVector[i]; } +static int +dmxVisualDepth (ScreenPtr pScreen, VisualPtr pVisual) +{ + DepthPtr pDepth; + int d, v; + + for (d = 0; d < pScreen->numDepths; d++) + { + pDepth = &pScreen->allowedDepths[d]; + for (v = 0; v < pDepth->numVids; v++) + if (pDepth->vids[v] == pVisual->vid) + return pDepth->depth; + } + + return 0; +} + +typedef struct _dmxformatInit { + CARD32 format; + CARD8 depth; +} dmxFormatInitRec, *dmxFormatInitPtr; + +static int +dmxAddFormat (dmxFormatInitPtr formats, + int nformat, + CARD32 format, + CARD8 depth) +{ + int n; + + for (n = 0; n < nformat; n++) + if (formats[n].format == format && formats[n].depth == depth) + return nformat; + + formats[nformat].format = format; + formats[nformat].depth = depth; + + return ++nformat; +} + +#define Mask(n) ((n) == 32 ? 0xffffffff : ((1 << (n)) - 1)) + +static PictFormatPtr +dmxCreateDefaultFormats (ScreenPtr pScreen, int *nformatp) +{ + int f, nformats = 0; + PictFormatPtr pFormats; + dmxFormatInitRec formats[64]; + CARD32 format; + CARD8 depth; + VisualPtr pVisual; + int v; + int bpp; + int r, g, b; + int d; + DepthPtr pDepth; + + /* formats required by protocol */ + formats[nformats].format = PICT_a1; + formats[nformats].depth = 1; + nformats++; + formats[nformats].format = PICT_a4; + formats[nformats].depth = 4; + nformats++; + formats[nformats].format = PICT_a8; + formats[nformats].depth = 8; + nformats++; + formats[nformats].format = PICT_a8r8g8b8; + formats[nformats].depth = 32; + nformats++; + + /* now look through the depths and visuals adding other formats */ + for (v = 0; v < pScreen->numVisuals; v++) + { + pVisual = &pScreen->visuals[v]; + depth = dmxVisualDepth (pScreen, pVisual); + if (!depth || depth == 32) + continue; + + bpp = BitsPerPixel (depth); + switch (pVisual->class) { + case DirectColor: + case TrueColor: + r = Ones (pVisual->redMask); + g = Ones (pVisual->greenMask); + b = Ones (pVisual->blueMask); + if (pVisual->offsetBlue == 0 && + pVisual->offsetGreen == b && + pVisual->offsetRed == b + g) + { + format = PICT_FORMAT (bpp, PICT_TYPE_ARGB, 0, r, g, b); + nformats = dmxAddFormat (formats, nformats, format, depth); + } + break; + case StaticColor: + case PseudoColor: + case StaticGray: + case GrayScale: + break; + } + } + + /* + * Walk supported depths and add useful Direct formats + */ + for (d = 0; d < 0; d++) + { + pDepth = &pScreen->allowedDepths[d]; + bpp = BitsPerPixel (pDepth->depth); + format = 0; + switch (bpp) { + case 16: + /* depth 12 formats */ + if (pDepth->depth >= 12) + { + nformats = dmxAddFormat (formats, nformats, + PICT_x4r4g4b4, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_x4b4g4r4, pDepth->depth); + } + /* depth 15 formats */ + if (pDepth->depth >= 15) + { + nformats = dmxAddFormat (formats, nformats, + PICT_x1r5g5b5, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_x1b5g5r5, pDepth->depth); + } + /* depth 16 formats */ + if (pDepth->depth >= 16) + { + nformats = dmxAddFormat (formats, nformats, + PICT_a1r5g5b5, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_a1b5g5r5, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_r5g6b5, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_b5g6r5, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_a4r4g4b4, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_a4b4g4r4, pDepth->depth); + } + break; + case 24: + if (pDepth->depth >= 24) + { + nformats = dmxAddFormat (formats, nformats, + PICT_r8g8b8, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_b8g8r8, pDepth->depth); + } + break; + case 32: + if (pDepth->depth >= 24) + { + nformats = dmxAddFormat (formats, nformats, + PICT_x8r8g8b8, pDepth->depth); + nformats = dmxAddFormat (formats, nformats, + PICT_x8b8g8r8, pDepth->depth); + } + break; + } + } + + + pFormats = (PictFormatPtr) xalloc (nformats * sizeof (PictFormatRec)); + if (!pFormats) + return 0; + memset (pFormats, '\0', nformats * sizeof (PictFormatRec)); + for (f = 0; f < nformats; f++) + { + pFormats[f].id = FakeClientID (0); + pFormats[f].depth = formats[f].depth; + format = formats[f].format; + pFormats[f].format = format; + switch (PICT_FORMAT_TYPE(format)) { + case PICT_TYPE_ARGB: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + if (pFormats[f].direct.alphaMask) + pFormats[f].direct.alpha = (PICT_FORMAT_R(format) + + PICT_FORMAT_G(format) + + PICT_FORMAT_B(format)); + + pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format)); + pFormats[f].direct.red = (PICT_FORMAT_G(format) + + PICT_FORMAT_B(format)); + + pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format)); + pFormats[f].direct.green = PICT_FORMAT_B(format); + + pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format)); + pFormats[f].direct.blue = 0; + break; + + case PICT_TYPE_ABGR: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + if (pFormats[f].direct.alphaMask) + pFormats[f].direct.alpha = (PICT_FORMAT_B(format) + + PICT_FORMAT_G(format) + + PICT_FORMAT_R(format)); + + pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format)); + pFormats[f].direct.blue = (PICT_FORMAT_G(format) + + PICT_FORMAT_R(format)); + + pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format)); + pFormats[f].direct.green = PICT_FORMAT_R(format); + + pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format)); + pFormats[f].direct.red = 0; + break; + + case PICT_TYPE_A: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alpha = 0; + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + + /* remaining fields already set to zero */ + break; + + case PICT_TYPE_COLOR: + case PICT_TYPE_GRAY: + pFormats[f].type = PictTypeIndexed; + pFormats[f].index.vid = pScreen->visuals[PICT_FORMAT_VIS(format)].vid; + break; + } + } + + *nformatp = nformats; + return pFormats; +} + /** Initialize the RENDER extension, allocate the picture privates and * wrap mi function hooks. If the shadow frame buffer is used, then * call the appropriate fb initialization function. */ @@ -138,8 +476,12 @@ Bool dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps; - /* The shadow framebuffer only relies on FB to be initialized */ - if (dmxShadowFB) return fbPictureInit(pScreen, formats, nformats); + if (!formats) + { + formats = dmxCreateDefaultFormats (pScreen, &nformats); + if (!formats) + return FALSE; + } if (!miPictureInit(pScreen, formats, nformats)) return FALSE; @@ -147,6 +489,12 @@ Bool dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) if (!dixRequestPrivate(dmxPictPrivateKey, sizeof(dmxPictPrivRec))) return FALSE; + if (!dixRequestPrivate(dmxGlyphSetPrivateKey, sizeof(dmxGlyphPrivRec))) + return FALSE; + + if (!dixRequestPrivate(dmxGlyphPrivateKey, 0)) + return FALSE; + ps = GetPictureScreen(pScreen); DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps); @@ -167,6 +515,9 @@ Bool dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) DMX_WRAP(TriStrip, dmxTriStrip, dmxScreen, ps); DMX_WRAP(TriFan, dmxTriFan, dmxScreen, ps); + DMX_WRAP(RealizeGlyph, dmxRealizeGlyph, dmxScreen, ps); + DMX_WRAP(UnrealizeGlyph, dmxUnrealizeGlyph, dmxScreen, ps); + return TRUE; } @@ -184,7 +535,10 @@ static XRenderPictFormat *dmxFindFormat(DMXScreenInfo *dmxScreen, if (!pFmt || !dmxScreen->beDisplay) return pFormat; while (1) { + pFormat = NULL; + XLIB_PROLOGUE (dmxScreen); pFormat = XRenderFindFormat(dmxScreen->beDisplay, 0, 0, i++); + XLIB_EPILOGUE (dmxScreen); if (!pFormat) break; if (pFormat->type != pFmt->type) continue; @@ -213,7 +567,9 @@ Bool dmxBEFreeGlyphSet(ScreenPtr pScreen, GlyphSetPtr glyphSet) DMXScreenInfo *dmxScreen = &dmxScreens[idx]; if (glyphPriv->glyphSets[idx]) { + XLIB_PROLOGUE (dmxScreen); XRenderFreeGlyphSet(dmxScreen->beDisplay, glyphPriv->glyphSets[idx]); + XLIB_EPILOGUE (dmxScreen); glyphPriv->glyphSets[idx] = (GlyphSet)0; return TRUE; } @@ -228,25 +584,19 @@ int dmxBECreateGlyphSet(int idx, GlyphSetPtr glyphSet) DMXScreenInfo *dmxScreen = &dmxScreens[idx]; dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); PictFormatPtr pFmt = glyphSet->format; - int (*oldErrorHandler)(Display *, XErrorEvent *); pFormat = dmxFindFormat(dmxScreen, pFmt); if (!pFormat) { return BadMatch; } - dmxGlyphLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxGlyphErrorHandler); + glyphPriv->glyphSets[idx] = None; /* Catch when this fails */ + XLIB_PROLOGUE (dmxScreen); glyphPriv->glyphSets[idx] = XRenderCreateGlyphSet(dmxScreen->beDisplay, pFormat); - - XSetErrorHandler(oldErrorHandler); - - if (dmxGlyphLastError) { - return dmxGlyphLastError; - } + XLIB_EPILOGUE (dmxScreen); return Success; } @@ -273,68 +623,46 @@ static int dmxProcRenderCreateGlyphSet(ClientPtr client) glyphSet = SecurityLookupIDByType(client, stuff->gsid, GlyphSetType, DixDestroyAccess); - glyphPriv = xalloc(sizeof(dmxGlyphPrivRec)); - if (!glyphPriv) return BadAlloc; + glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); glyphPriv->glyphSets = NULL; MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc); - DMX_SET_GLYPH_PRIV(glyphSet, glyphPriv); + memset (glyphPriv->glyphSets, 0, + sizeof (*glyphPriv->glyphSets) * MAXSCREENS); + glyphSet->refcnt++; + AddResource (stuff->gsid, DMX_GLYPHSET, glyphSet); for (i = 0; i < dmxNumScreens; i++) { DMXScreenInfo *dmxScreen = &dmxScreens[i]; - int beret; - if (!dmxScreen->beDisplay) { - glyphPriv->glyphSets[i] = 0; + if (!dmxScreen->beDisplay) continue; - } - - if ((beret = dmxBECreateGlyphSet(i, glyphSet)) != Success) { - int j; - - /* Free the glyph sets we've allocated thus far */ - for (j = 0; j < i; j++) - dmxBEFreeGlyphSet(screenInfo.screens[j], glyphSet); - - /* Free the resource created by render */ - FreeResource(stuff->gsid, RT_NONE); - return beret; - } + dmxBECreateGlyphSet (i, glyphSet); + dmxSync (dmxScreen, FALSE); } } return ret; } -/** Free the previously allocated Glyph Sets for each screen. */ -static int dmxProcRenderFreeGlyphSet(ClientPtr client) +static int dmxProcRenderReferenceGlyphSet (ClientPtr client) { - GlyphSetPtr glyphSet; - REQUEST(xRenderFreeGlyphSetReq); + int ret; + REQUEST(xRenderReferenceGlyphSetReq); - REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq); - glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType, - DixDestroyAccess); - - if (glyphSet && glyphSet->refcnt == 1) { - dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); - int i; + ret = dmxSaveRenderVector[stuff->renderReqType](client); - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - - if (dmxScreen->beDisplay) { - if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet)) - dmxSync(dmxScreen, FALSE); - } - } + if (ret == Success) + { + GlyphSetPtr glyphSet; - MAXSCREENSFREE(glyphPriv->glyphSets); - xfree(glyphPriv); - DMX_SET_GLYPH_PRIV(glyphSet, NULL); + glyphSet = SecurityLookupIDByType (client, stuff->gsid, GlyphSetType, + DixDestroyAccess); + glyphSet->refcnt++; + AddResource (stuff->gsid, DMX_GLYPHSET, glyphSet); } - return dmxSaveRenderVector[stuff->renderReqType](client); + return ret; } /** Add glyphs to the Glyph Set on each screen. */ @@ -354,7 +682,8 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) Glyph *gidsCopy; xGlyphInfo *gi; CARD8 *bits; - int nbytes; + int nbytes, size; + void *data; glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType, DixReadAccess); @@ -369,13 +698,42 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs); gidsCopy = xalloc(sizeof(*gidsCopy) * nglyphs); - for (i = 0; i < nglyphs; i++) gidsCopy[i] = gids[i]; + for (i = 0; i < nglyphs; i++) + { + GlyphPtr glyph; + + gidsCopy[i] = gids[i]; + + size = gi[i].height * PixmapBytePad (gi[i].width, + glyphSet->format->depth); + if (size & 3) + size += 4 - (size & 3); + + glyph = FindGlyph (glyphSet, gids[i]); + if (glyph) + { + data = xalloc (size); + if (data) + { + memcpy (data, bits, size); + *((PrivateRec **) + dixLookupPrivateAddr (&(glyph)->devPrivates, + dmxGlyphPrivateKey)) = data; + } + } + + bits += size; + } + + bits = (CARD8 *)(gi + nglyphs); /* FIXME: Will this ever fail? */ for (i = 0; i < dmxNumScreens; i++) { DMXScreenInfo *dmxScreen = &dmxScreens[i]; if (dmxScreen->beDisplay) { + + XLIB_PROLOGUE (dmxScreen); XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[i], gidsCopy, @@ -383,6 +741,7 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) nglyphs, (char *)bits, nbytes); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } } @@ -418,8 +777,10 @@ static int dmxProcRenderFreeGlyphs(ClientPtr client) DMXScreenInfo *dmxScreen = &dmxScreens[i]; if (dmxScreen->beDisplay) { + XLIB_PROLOGUE (dmxScreen); XRenderFreeGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[i], gids, nglyphs); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } } @@ -471,11 +832,7 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) GlyphSetPtr glyphSet; dmxGlyphPrivPtr glyphPriv; - pSrc = SecurityLookupIDByType(client, stuff->src, PictureType, - DixReadAccess); - pSrcPriv = DMX_GET_PICT_PRIV(pSrc); - if (!pSrcPriv->pict) - return ret; + Picture src = None; pDst = SecurityLookupIDByType(client, stuff->dst, PictureType, DixWriteAccess); @@ -486,6 +843,18 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) scrnNum = pDst->pDrawable->pScreen->myNum; dmxScreen = &dmxScreens[scrnNum]; + pSrc = SecurityLookupIDByType(client, stuff->src, PictureType, + DixReadAccess); + pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + + if (pSrc->pDrawable) + src = pSrcPriv->pict; + else + src = pSrcPriv->sourcePict[scrnNum]; + + if (!src) + return ret; + /* Note: If the back-end display has been detached, then it * should not be possible to reach here since the pSrcPriv->pict * and pDstPriv->pict will have already been set to 0. @@ -578,30 +947,34 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) } } + XLIB_PROLOGUE (dmxScreen); + switch (stuff->renderReqType) { case X_RenderCompositeGlyphs8: XRenderCompositeText8(dmxScreen->beDisplay, stuff->op, - pSrcPriv->pict, pDstPriv->pict, + src, pDstPriv->pict, pFormat, stuff->xSrc, stuff->ySrc, 0, 0, elts, nelt); break; case X_RenderCompositeGlyphs16: XRenderCompositeText16(dmxScreen->beDisplay, stuff->op, - pSrcPriv->pict, pDstPriv->pict, + src, pDstPriv->pict, pFormat, stuff->xSrc, stuff->ySrc, 0, 0, (XGlyphElt16 *)elts, nelt); break; case X_RenderCompositeGlyphs32: XRenderCompositeText32(dmxScreen->beDisplay, stuff->op, - pSrcPriv->pict, pDstPriv->pict, + src, pDstPriv->pict, pFormat, stuff->xSrc, stuff->ySrc, 0, 0, (XGlyphElt32 *)elts, nelt); break; } + XLIB_EPILOGUE (dmxScreen); + dmxSync(dmxScreen, FALSE); xfree(elts); @@ -624,27 +997,49 @@ static int dmxProcRenderSetPictureTransform(ClientPtr client) VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess, RenderErrBase + BadPicture); + pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + xform.matrix[0][0] = stuff->transform.matrix11; + xform.matrix[0][1] = stuff->transform.matrix12; + xform.matrix[0][2] = stuff->transform.matrix13; + xform.matrix[1][0] = stuff->transform.matrix21; + xform.matrix[1][1] = stuff->transform.matrix22; + xform.matrix[1][2] = stuff->transform.matrix23; + xform.matrix[2][0] = stuff->transform.matrix31; + xform.matrix[2][1] = stuff->transform.matrix32; + xform.matrix[2][2] = stuff->transform.matrix33; + /* For the following to work with PanoramiX, it assumes that Render * wraps the ProcRenderVector after dmxRenderInit has been called. */ - dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; - pPictPriv = DMX_GET_PICT_PRIV(pPicture); + if (pPicture->pDrawable) + { + dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; + + if (pPictPriv->pict) { + XLIB_PROLOGUE (dmxScreen); + XRenderSetPictureTransform(dmxScreen->beDisplay, + pPictPriv->pict, + &xform); + XLIB_EPILOGUE (dmxScreen); + } + } + else if (pPictPriv->sourcePict) + { + int i; - if (pPictPriv->pict) { - xform.matrix[0][0] = stuff->transform.matrix11; - xform.matrix[0][1] = stuff->transform.matrix12; - xform.matrix[0][2] = stuff->transform.matrix13; - xform.matrix[1][0] = stuff->transform.matrix21; - xform.matrix[1][1] = stuff->transform.matrix22; - xform.matrix[1][2] = stuff->transform.matrix23; - xform.matrix[2][0] = stuff->transform.matrix31; - xform.matrix[2][1] = stuff->transform.matrix32; - xform.matrix[2][2] = stuff->transform.matrix33; - - XRenderSetPictureTransform(dmxScreen->beDisplay, - pPictPriv->pict, - &xform); - dmxSync(dmxScreen, FALSE); + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (pPictPriv->sourcePict[i]) + { + XLIB_PROLOGUE (dmxScreen); + XRenderSetPictureTransform(dmxScreen->beDisplay, + pPictPriv->sourcePict[i], + &xform); + XLIB_EPILOGUE (dmxScreen); + } + } } return dmxSaveRenderVector[stuff->renderReqType](client); @@ -668,25 +1063,267 @@ static int dmxProcRenderSetPictureFilter(ClientPtr client) /* For the following to work with PanoramiX, it assumes that Render * wraps the ProcRenderVector after dmxRenderInit has been called. */ - dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; + if (pPicture->pDrawable) + { + dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; + pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + if (pPictPriv->pict) + { + char name[256]; + + filter = (char *)(stuff + 1); + params = (XFixed *)(filter + ((stuff->nbytes + 3) & ~3)); + nparams = ((XFixed *)stuff + client->req_len) - params; + + strncpy (name, filter, stuff->nbytes); + name[stuff->nbytes] = '\0'; + + XLIB_PROLOGUE (dmxScreen); + XRenderSetPictureFilter(dmxScreen->beDisplay, + pPictPriv->pict, + name, + params, + nparams); + XLIB_EPILOGUE (dmxScreen); + } + } + + return dmxSaveRenderVector[stuff->renderReqType](client); +} + +static int dmxProcRenderChangePicture(ClientPtr client) +{ + int ret; + REQUEST(xRenderChangePictureReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + + if (ret == Success && (stuff->mask & CPRepeat)) { + PicturePtr pPicture; + dmxPictPrivPtr pPictPriv; + int i; + + pPicture = SecurityLookupIDByType(client, stuff->picture, PictureType, + DixDestroyAccess); + pPictPriv = DMX_GET_PICT_PRIV(pPicture); + if (pPictPriv->sourcePict) + { + XRenderPictureAttributes attribs; + + attribs.repeat = pPicture->repeatType; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (pPictPriv->sourcePict[i]) + { + XLIB_PROLOGUE (dmxScreen); + XRenderChangePicture(dmxScreen->beDisplay, + pPictPriv->sourcePict[i], + CPRepeat, &attribs); + XLIB_EPILOGUE (dmxScreen); + } + } + } + } + + return ret; +} + +static int +dmxGetSourceStops (SourcePictPtr pSourcePict, + XFixed **stops, + XRenderColor **colors) +{ + if (pSourcePict->gradient.nstops) + { + int i; + + *stops = xalloc (pSourcePict->gradient.nstops * sizeof (XFixed)); + *colors = xalloc (pSourcePict->gradient.nstops * + sizeof (XRenderColor)); + + for (i = 0; i < pSourcePict->gradient.nstops; i++) + { + (*stops)[i] = pSourcePict->gradient.stops[i].x; + (*colors)[i].red = pSourcePict->gradient.stops[i].color.red; + (*colors)[i].green = pSourcePict->gradient.stops[i].color.green; + (*colors)[i].blue = pSourcePict->gradient.stops[i].color.blue; + (*colors)[i].alpha = pSourcePict->gradient.stops[i].color.alpha; + } + } + else + { + *stops = NULL; + *colors = NULL; + } + + return pSourcePict->gradient.nstops; +} + +static Picture +dmxDoCreateSourcePicture (int idx, PicturePtr pPicture) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + Picture pict = None; + + if (pPicture->pSourcePict) + { + SourcePictPtr pSourcePict = pPicture->pSourcePict; + XFixed *stops = NULL; + XRenderColor *colors = NULL; + int nstops = 0; + + if (!dmxScreen->beDisplay) + return 0; + + switch (pSourcePict->type) { + case SourcePictTypeSolidFill: { + XRenderColor c; + + c.alpha = (pSourcePict->solidFill.color & 0xff000000) >> 16; + c.red = (pSourcePict->solidFill.color & 0x00ff0000) >> 8; + c.green = (pSourcePict->solidFill.color & 0x0000ff00) >> 0; + c.blue = (pSourcePict->solidFill.color & 0x000000ff) << 8; + + XLIB_PROLOGUE (dmxScreen); + pict = XRenderCreateSolidFill (dmxScreen->beDisplay, &c); + XLIB_EPILOGUE (dmxScreen); + } break; + case SourcePictTypeLinear: { + XLinearGradient l; + + l.p1.x = pSourcePict->linear.p1.x; + l.p1.y = pSourcePict->linear.p1.y; + l.p2.x = pSourcePict->linear.p2.x; + l.p2.y = pSourcePict->linear.p2.y; + + nstops = dmxGetSourceStops (pSourcePict, &stops, &colors); + + XLIB_PROLOGUE (dmxScreen); + pict = XRenderCreateLinearGradient (dmxScreen->beDisplay, &l, + stops, colors, nstops); + XLIB_EPILOGUE (dmxScreen); + } break; + case SourcePictTypeRadial: { + XRadialGradient r; + + r.inner.x = pSourcePict->radial.c1.x; + r.inner.y = pSourcePict->radial.c1.y; + r.inner.radius = pSourcePict->radial.c1.radius; + r.outer.x = pSourcePict->radial.c2.x; + r.outer.y = pSourcePict->radial.c2.y; + r.outer.radius = pSourcePict->radial.c2.radius; + + nstops = dmxGetSourceStops (pSourcePict, &stops, &colors); + + XLIB_PROLOGUE (dmxScreen); + pict = XRenderCreateRadialGradient (dmxScreen->beDisplay, &r, + stops, colors, nstops); + XLIB_EPILOGUE (dmxScreen); + } break; + case SourcePictTypeConical: { + XConicalGradient c; + + c.center.x = pSourcePict->conical.center.x; + c.center.y = pSourcePict->conical.center.y; + c.angle = pSourcePict->conical.angle; + + nstops = dmxGetSourceStops (pSourcePict, &stops, &colors); + + XLIB_PROLOGUE (dmxScreen); + pict = XRenderCreateConicalGradient (dmxScreen->beDisplay, &c, + stops, colors, nstops); + XLIB_EPILOGUE (dmxScreen); + } break; + } + + if (nstops) + { + xfree (stops); + xfree (colors); + } + } + + return pict; +} + +static int dmxCreateSourcePicture(ClientPtr client, XID pid) +{ + PicturePtr pPicture; + dmxPictPrivPtr pPictPriv; + int i; + + pPicture = SecurityLookupIDByType(client, pid, PictureType, + DixDestroyAccess); pPictPriv = DMX_GET_PICT_PRIV(pPicture); + MAXSCREENSALLOC_RETURN(pPictPriv->sourcePict, BadAlloc); + memset (pPictPriv->sourcePict, 0, + sizeof (*pPictPriv->sourcePict) * MAXSCREENS); + pPictPriv->pict = (Picture) 0; + AddResource (pid, DMX_SOURCEPICT, pPicture); + pPicture->refcnt++; - if (pPictPriv->pict) { - filter = (char *)(stuff + 1); - params = (XFixed *)(filter + ((stuff->nbytes + 3) & ~3)); - nparams = ((XFixed *)stuff + client->req_len) - params; - - XRenderSetPictureFilter(dmxScreen->beDisplay, - pPictPriv->pict, - filter, - params, - nparams); - dmxSync(dmxScreen, FALSE); + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + + pPictPriv->sourcePict[i] = dmxDoCreateSourcePicture (i, pPicture); } - return dmxSaveRenderVector[stuff->renderReqType](client); + return Success; +} + +static int dmxProcRenderCreateSolidFill (ClientPtr client) +{ + int ret; + REQUEST(xRenderCreateSolidFillReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + if (ret != Success) + return ret; + + return dmxCreateSourcePicture (client, stuff->pid); +} + +static int dmxProcRenderCreateLinearGradient (ClientPtr client) +{ + int ret; + REQUEST(xRenderCreateLinearGradientReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + if (ret != Success) + return ret; + + return dmxCreateSourcePicture (client, stuff->pid); } +static int dmxProcRenderCreateRadialGradient (ClientPtr client) +{ + int ret; + REQUEST(xRenderCreateRadialGradientReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + if (ret != Success) + return ret; + + return dmxCreateSourcePicture (client, stuff->pid); +} + +static int dmxProcRenderCreateConicalGradient (ClientPtr client) +{ + int ret; + REQUEST(xRenderCreateConicalGradientReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + if (ret != Success) + return ret; + + return dmxCreateSourcePicture (client, stuff->pid); +} /** Create a picture on the appropriate screen. This is the actual * function that creates the picture. However, if the associated @@ -698,9 +1335,10 @@ static Picture dmxDoCreatePicture(PicturePtr pPicture) ScreenPtr pScreen = pDraw->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; XRenderPictFormat *pFormat; - Drawable draw; + Drawable draw; + Picture pict = 0; - if (pPicture->pDrawable->type == DRAWABLE_WINDOW) { + if (pDraw->type == DRAWABLE_WINDOW) { dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV((WindowPtr)(pDraw)); if (!(draw = pWinPriv->window)) { @@ -729,7 +1367,11 @@ static Picture dmxDoCreatePicture(PicturePtr pPicture) pFormat = dmxFindFormat(dmxScreen, pPicture->pFormat); - return XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0); + XLIB_PROLOGUE (dmxScreen); + pict = XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0); + XLIB_EPILOGUE (dmxScreen); + + return pict; } /** Create a list of pictures. This function is called by @@ -753,15 +1395,47 @@ void dmxCreatePictureList(WindowPtr pWindow) } /** Create \a pPicture on the backend. */ -int dmxBECreatePicture(PicturePtr pPicture) +int dmxBECreatePicture(int idx, PicturePtr pPicture) { dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); - /* Create picutre on BE */ - pPictPriv->pict = dmxDoCreatePicture(pPicture); + /* Create picture on BE */ + if (pPicture->pDrawable) + { + pPictPriv->pict = dmxDoCreatePicture(pPicture); - /* Flush changes to the backend server */ - dmxValidatePicture(pPicture, (1 << (CPLastBit+1)) - 1); + /* Flush changes to the backend server */ + dmxValidatePicture(pPicture, (1 << (CPLastBit+1)) - 1); + } + else + { + pPictPriv->sourcePict[idx] = dmxDoCreateSourcePicture(idx, pPicture); + if (pPictPriv->sourcePict[idx]) + { + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + XRenderPictureAttributes attribs; + XTransform xform; + int i, j; + + attribs.repeat = pPicture->repeatType; + + XLIB_PROLOGUE (dmxScreen); + XRenderChangePicture(dmxScreen->beDisplay, + pPictPriv->sourcePict[idx], + CPRepeat, &attribs); + XLIB_EPILOGUE (dmxScreen); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + xform.matrix[i][j] = pPicture->transform->matrix[i][j]; + + XLIB_PROLOGUE (dmxScreen); + XRenderSetPictureTransform(dmxScreen->beDisplay, + pPictPriv->sourcePict[idx], + &xform); + XLIB_EPILOGUE (dmxScreen); + } + } return Success; } @@ -784,7 +1458,8 @@ int dmxCreatePicture(PicturePtr pPicture) #endif /* Create picture on back-end server */ - pPictPriv->pict = dmxDoCreatePicture(pPicture); + pPictPriv->pict = dmxDoCreatePicture(pPicture); + pPictPriv->sourcePict = NULL; pPictPriv->savedMask = 0; DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps); @@ -793,17 +1468,27 @@ int dmxCreatePicture(PicturePtr pPicture) } /** Destroy \a pPicture on the back-end server. */ -Bool dmxBEFreePicture(PicturePtr pPicture) +Bool dmxBEFreePicture(ScreenPtr pScreen, PicturePtr pPicture) { - ScreenPtr pScreen = pPicture->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); if (pPictPriv->pict) { + XLIB_PROLOGUE (dmxScreen); XRenderFreePicture(dmxScreen->beDisplay, pPictPriv->pict); + XLIB_EPILOGUE (dmxScreen); pPictPriv->pict = (Picture)0; return TRUE; } + if (pPictPriv->sourcePict) { + if (pPictPriv->sourcePict[pScreen->myNum]) { + XLIB_PROLOGUE (dmxScreen); + XRenderFreePicture(dmxScreen->beDisplay, + pPictPriv->sourcePict[pScreen->myNum]); + XLIB_EPILOGUE (dmxScreen); + pPictPriv->sourcePict[pScreen->myNum] = (Picture) 0; + } + } return FALSE; } @@ -817,7 +1502,7 @@ Bool dmxDestroyPictureList(WindowPtr pWindow) Bool ret = FALSE; while (pPicture) { - ret |= dmxBEFreePicture(pPicture); + ret |= dmxBEFreePicture(pWindow->drawable.pScreen, pPicture); pPicture = pPicture->pNext; } @@ -836,7 +1521,7 @@ void dmxDestroyPicture(PicturePtr pPicture) DMX_UNWRAP(DestroyPicture, dmxScreen, ps); /* Destroy picture on back-end server */ - if (dmxBEFreePicture(pPicture)) + if (dmxBEFreePicture(pScreen, pPicture)) dmxSync(dmxScreen, FALSE); #if 1 @@ -868,8 +1553,10 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, */ if (clipType == CT_NONE) { /* Disable clipping, show all */ + XLIB_PROLOGUE (dmxScreen); XFixesSetPictureClipRegion(dmxScreen->beDisplay, pPictPriv->pict, 0, 0, None); + XLIB_EPILOGUE (dmxScreen); } else if (pPicture->clientClip) { RegionPtr pClip = pPicture->clientClip; BoxPtr pBox = REGION_RECTS(pClip); @@ -890,16 +1577,20 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, pRect++; } + XLIB_PROLOGUE (dmxScreen); XRenderSetPictureClipRectangles(dmxScreen->beDisplay, pPictPriv->pict, 0, 0, pRects, nRects); + XLIB_EPILOGUE (dmxScreen); xfree(pRects); } else { + XLIB_PROLOGUE (dmxScreen); XRenderSetPictureClipRectangles(dmxScreen->beDisplay, pPictPriv->pict, 0, 0, NULL, 0); + XLIB_EPILOGUE (dmxScreen); } dmxSync(dmxScreen, FALSE); } else { @@ -927,9 +1618,11 @@ void dmxDestroyPictureClip(PicturePtr pPicture) /* Destroy picture clip rects on back-end server */ if (pPictPriv->pict) { + XLIB_PROLOGUE (dmxScreen); XRenderSetPictureClipRectangles(dmxScreen->beDisplay, pPictPriv->pict, 0, 0, NULL, 0); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } else { /* FIXME: Handle destroying clip region when offscreen */ @@ -1017,9 +1710,10 @@ void dmxValidatePicture(PicturePtr pPicture, Mask mask) if (mask & CPComponentAlpha) attribs.component_alpha = pPicture->componentAlpha; + XLIB_PROLOGUE (dmxScreen); XRenderChangePicture(dmxScreen->beDisplay, pPictPriv->pict, mask, &attribs); - dmxSync(dmxScreen, FALSE); + XLIB_EPILOGUE (dmxScreen); } else { pPictPriv->savedMask |= mask; } @@ -1047,11 +1741,22 @@ void dmxComposite(CARD8 op, ScreenPtr pScreen = pDst->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps = GetPictureScreen(pScreen); - dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); - dmxPictPrivPtr pMaskPriv = NULL; dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); - - if (pMask) pMaskPriv = DMX_GET_PICT_PRIV(pMask); + Picture src = None; + Picture mask = None; + + if (pSrc->pDrawable) + src = (DMX_GET_PICT_PRIV (pSrc))->pict; + else + src = (DMX_GET_PICT_PRIV (pSrc))->sourcePict[pScreen->myNum]; + + if (pMask) + { + if (pMask->pDrawable) + mask = (DMX_GET_PICT_PRIV (pMask))->pict; + else + mask = (DMX_GET_PICT_PRIV (pMask))->sourcePict[pScreen->myNum]; + } DMX_UNWRAP(Composite, dmxScreen, ps); #if 0 @@ -1062,21 +1767,22 @@ void dmxComposite(CARD8 op, #endif /* Composite on back-end server */ - if (pSrcPriv->pict && pDstPriv->pict && - ((pMaskPriv && pMaskPriv->pict) || !pMaskPriv)) { + if (src && pDstPriv->pict) + { + XLIB_PROLOGUE (dmxScreen); XRenderComposite(dmxScreen->beDisplay, op, - pSrcPriv->pict, - pMaskPriv ? pMaskPriv->pict : None, + src, + mask, pDstPriv->pict, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } - DMX_WRAP(Composite, dmxComposite, dmxScreen, ps); } @@ -1114,12 +1820,14 @@ void dmxCompositeRects(CARD8 op, /* CompositeRects on back-end server */ if (pPictPriv->pict) { + XLIB_PROLOGUE (dmxScreen); XRenderFillRectangles(dmxScreen->beDisplay, op, pPictPriv->pict, (XRenderColor *)color, (XRectangle *)rects, nRect); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -1154,8 +1862,8 @@ void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps = GetPictureScreen(pScreen); - dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + Picture src = None; DMX_UNWRAP(Trapezoids, dmxScreen, ps); #if 0 @@ -1163,6 +1871,11 @@ void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, *traps); #endif + if (pSrc->pDrawable) + src = (DMX_GET_PICT_PRIV (pSrc))->pict; + else + src = (DMX_GET_PICT_PRIV (pSrc))->sourcePict[pScreen->myNum]; + /* Draw trapezoids on back-end server */ if (pDstPriv->pict) { XRenderPictFormat *pFormat; @@ -1172,14 +1885,16 @@ void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, /* FIXME: Error! */ } + XLIB_PROLOGUE (dmxScreen); XRenderCompositeTrapezoids(dmxScreen->beDisplay, op, - pSrcPriv->pict, + src, pDstPriv->pict, pFormat, xSrc, ySrc, (XTrapezoid *)traps, ntrap); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -1197,8 +1912,8 @@ void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps = GetPictureScreen(pScreen); - dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + Picture src = None; DMX_UNWRAP(Triangles, dmxScreen, ps); #if 0 @@ -1206,6 +1921,11 @@ void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, *tris); #endif + if (pSrc->pDrawable) + src = (DMX_GET_PICT_PRIV (pSrc))->pict; + else + src = (DMX_GET_PICT_PRIV (pSrc))->sourcePict[pScreen->myNum]; + /* Draw trapezoids on back-end server */ if (pDstPriv->pict) { XRenderPictFormat *pFormat; @@ -1215,14 +1935,16 @@ void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, /* FIXME: Error! */ } + XLIB_PROLOGUE (dmxScreen); XRenderCompositeTriangles(dmxScreen->beDisplay, op, - pSrcPriv->pict, + src, pDstPriv->pict, pFormat, xSrc, ySrc, (XTriangle *)tris, ntri); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -1240,8 +1962,8 @@ void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps = GetPictureScreen(pScreen); - dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + Picture src = None; DMX_UNWRAP(TriStrip, dmxScreen, ps); #if 0 @@ -1249,6 +1971,11 @@ void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ps->TriStrip(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points); #endif + if (pSrc->pDrawable) + src = (DMX_GET_PICT_PRIV (pSrc))->pict; + else + src = (DMX_GET_PICT_PRIV (pSrc))->sourcePict[pScreen->myNum]; + /* Draw trapezoids on back-end server */ if (pDstPriv->pict) { XRenderPictFormat *pFormat; @@ -1258,14 +1985,16 @@ void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, /* FIXME: Error! */ } + XLIB_PROLOGUE (dmxScreen); XRenderCompositeTriStrip(dmxScreen->beDisplay, op, - pSrcPriv->pict, + src, pDstPriv->pict, pFormat, xSrc, ySrc, (XPointFixed *)points, npoint); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } @@ -1282,8 +2011,8 @@ void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ScreenPtr pScreen = pDst->pDrawable->pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; PictureScreenPtr ps = GetPictureScreen(pScreen); - dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + Picture src = None; DMX_UNWRAP(TriFan, dmxScreen, ps); #if 0 @@ -1291,6 +2020,11 @@ void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ps->TriFan(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points); #endif + if (pSrc->pDrawable) + src = (DMX_GET_PICT_PRIV (pSrc))->pict; + else + src = (DMX_GET_PICT_PRIV (pSrc))->sourcePict[pScreen->myNum]; + /* Draw trapezoids on back-end server */ if (pDstPriv->pict) { XRenderPictFormat *pFormat; @@ -1300,14 +2034,16 @@ void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, /* FIXME: Error! */ } + XLIB_PROLOGUE (dmxScreen); XRenderCompositeTriFan(dmxScreen->beDisplay, op, - pSrcPriv->pict, + src, pDstPriv->pict, pFormat, xSrc, ySrc, (XPointFixed *)points, npoint); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } diff --git a/hw/dmx/dmxpict.h b/hw/dmx/dmxpict.h index a81eb7d..7c968d6 100644 --- a/hw/dmx/dmxpict.h +++ b/hw/dmx/dmxpict.h @@ -46,6 +46,7 @@ typedef struct _dmxPictPriv { Picture pict; /**< Picture ID from back-end server */ Mask savedMask; /**< Mask of picture attributes saved for * lazy window creation. */ + Picture *sourcePict; } dmxPictPrivRec, *dmxPictPrivPtr; @@ -113,20 +114,17 @@ extern void dmxTriFan(CARD8 op, extern int dmxBECreateGlyphSet(int idx, GlyphSetPtr glyphSet); extern Bool dmxBEFreeGlyphSet(ScreenPtr pScreen, GlyphSetPtr glyphSet); -extern int dmxBECreatePicture(PicturePtr pPicture); -extern Bool dmxBEFreePicture(PicturePtr pPicture); +extern int dmxBECreatePicture(int idx, PicturePtr pPicture); +extern Bool dmxBEFreePicture(ScreenPtr pScreen, PicturePtr pPicture); extern DevPrivateKey dmxPictPrivateKey; /**< Index for picture private data */ extern DevPrivateKey dmxGlyphSetPrivateKey; /**< Index for glyphset private data */ - +extern DevPrivateKey dmxGlyphPrivateKey; /**< Index for glyph private data */ /** Get the picture private data given a picture pointer */ #define DMX_GET_PICT_PRIV(_pPict) \ (dmxPictPrivPtr)dixLookupPrivate(&(_pPict)->devPrivates, dmxPictPrivateKey) -/** Set the glyphset private data given a glyphset pointer */ -#define DMX_SET_GLYPH_PRIV(_pGlyph, _pPriv) \ - GlyphSetSetPrivate((_pGlyph), dmxGlyphSetPrivateKey, (_pPriv)) /** Get the glyphset private data given a glyphset pointer */ #define DMX_GET_GLYPH_PRIV(_pGlyph) \ (dmxGlyphPrivPtr)GlyphSetGetPrivate((_pGlyph), dmxGlyphSetPrivateKey) diff --git a/hw/dmx/dmxpixmap.c b/hw/dmx/dmxpixmap.c index 6622403..40b4834 100644 --- a/hw/dmx/dmxpixmap.c +++ b/hw/dmx/dmxpixmap.c @@ -70,11 +70,13 @@ void dmxBECreatePixmap(PixmapPtr pPixmap) return; if (pPixmap->drawable.width && pPixmap->drawable.height) { + XLIB_PROLOGUE (dmxScreen); pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, pPixmap->drawable.width, pPixmap->drawable.height, pPixmap->drawable.depth); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); } } @@ -122,9 +124,13 @@ PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, pPixPriv->pixmap = (Pixmap)0; pPixPriv->detachedImage = NULL; - /* Create the pixmap on the back-end server */ - if (dmxScreen->beDisplay) { - dmxBECreatePixmap(pPixmap); + if (usage_hint != CREATE_PIXMAP_USAGE_GLYPH_PICTURE && + usage_hint != CREATE_PIXMAP_USAGE_BACKING_PIXMAP) + { + /* Create the pixmap on the back-end server */ + if (dmxScreen->beDisplay) { + dmxBECreatePixmap(pPixmap); + } } #if 0 @@ -142,7 +148,9 @@ Bool dmxBEFreePixmap(PixmapPtr pPixmap) dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); if (pPixPriv->pixmap) { + XLIB_PROLOGUE (dmxScreen); XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); + XLIB_EPILOGUE (dmxScreen); pPixPriv->pixmap = (Pixmap)0; return TRUE; } @@ -150,6 +158,15 @@ Bool dmxBEFreePixmap(PixmapPtr pPixmap) return FALSE; } +static Bool FoundPix = False; + +static void findPixmap (pointer value, XID id, RESTYPE type, pointer p) +{ + if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) + if ((PixmapPtr) p == (PixmapPtr) value) + FoundPix = True; +} + /** Destroy the pixmap pointed to by \a pPixmap. */ Bool dmxDestroyPixmap(PixmapPtr pPixmap) { @@ -162,8 +179,45 @@ Bool dmxDestroyPixmap(PixmapPtr pPixmap) #endif if (--pPixmap->refcnt) + { + int i; + return TRUE; + FoundPix = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources (clients[i], findPixmap, + (pointer) pPixmap); + + if (!FoundPix) + { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV (pPixmap); + + if (!pPixPriv->detachedImage) + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + pPixPriv->detachedImage = NULL; + + XLIB_PROLOGUE (dmxScreen); + pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + 0, 0, + pPixmap->drawable.width, + pPixmap->drawable.height, + -1, + ZPixmap); + XLIB_EPILOGUE (dmxScreen); + if (!pPixPriv->detachedImage) + ErrorF ("Cannot save pixmap image\n"); + } + } + + return TRUE; + } + /* Destroy pixmap on back-end server */ if (dmxScreen->beDisplay) { if (dmxBEFreePixmap(pPixmap)) { @@ -193,7 +247,7 @@ RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) ScreenPtr pScreen = pPixmap->drawable.pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - XImage *ximage; + XImage *ximage = NULL; RegionPtr pReg, pTmpReg; int x, y; unsigned long previousPixel, currentPixel; @@ -205,9 +259,13 @@ RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) return pReg; } + XLIB_PROLOGUE (dmxScreen); ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height, 1, XYPixmap); + XLIB_EPILOGUE (dmxScreen); + if (!ximage) + return NullRegion; pReg = REGION_CREATE(pScreen, NullBox, 1); pTmpReg = REGION_CREATE(pScreen, NullBox, 1); @@ -219,6 +277,7 @@ RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) for (y = 0; y < pPixmap->drawable.height; y++) { Box.y1 = y; Box.y2 = y + 1; + Box.x1 = 0; previousPixel = 0L; for (x = 0; x < pPixmap->drawable.width; x++) { currentPixel = XGetPixel(ximage, x, y); @@ -251,3 +310,94 @@ RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) dmxSync(dmxScreen, FALSE); return(pReg); } + +Bool +dmxModifyPixmapHeader (PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int oldWidth, oldHeight, oldDepth; + Bool status; + + oldWidth = pPixmap->drawable.width; + oldHeight = pPixmap->drawable.height; + oldDepth = pPixmap->drawable.depth; + + DMX_UNWRAP (ModifyPixmapHeader, dmxScreen, pScreen); + status = (*pScreen->ModifyPixmapHeader) (pPixmap, + width, + height, + depth, + bitsPerPixel, + devKind, + pPixData); + DMX_WRAP (ModifyPixmapHeader, dmxModifyPixmapHeader, dmxScreen, pScreen); + + if (!status) + return FALSE; + + if (pPixmap->drawable.width != oldWidth || + pPixmap->drawable.height != oldHeight || + pPixmap->drawable.depth != oldDepth) + { + dmxBEFreePixmap (pPixmap); + } + + if (pPixData && dmxScreen->beDisplay) + { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV (pPixmap); + XlibGC gc = NULL; + unsigned long m; + XGCValues v; + XImage ximage; + + ximage.width = pPixmap->drawable.width; + ximage.height = pPixmap->drawable.height; + ximage.format = ZPixmap; + ximage.byte_order = IMAGE_BYTE_ORDER; + ximage.bitmap_unit = 32; + ximage.bitmap_bit_order = BITMAP_BIT_ORDER; + ximage.bitmap_pad = 32; + ximage.depth = pPixmap->drawable.depth; + ximage.red_mask = 0; + ximage.green_mask = 0; + ximage.blue_mask = 0; + ximage.xoffset = 0; + ximage.bits_per_pixel = pPixmap->drawable.bitsPerPixel; + ximage.bytes_per_line = pPixmap->devKind; + ximage.data = (char *) pPixData; + + XInitImage (&ximage); + + dmxBECreatePixmap (pPixmap); + + m = GCFunction | GCPlaneMask | GCClipMask; + + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + XLIB_PROLOGUE (dmxScreen); + gc = XCreateGC (dmxScreen->beDisplay, pPixPriv->pixmap, m, &v); + XLIB_EPILOGUE (dmxScreen); + + if (gc) + { + XLIB_PROLOGUE (dmxScreen); + XPutImage (dmxScreen->beDisplay, + pPixPriv->pixmap, + gc, &ximage, 0, 0, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height); + XFreeGC (dmxScreen->beDisplay, gc); + XLIB_EPILOGUE (dmxScreen); + } + } + + return TRUE; +} diff --git a/hw/dmx/dmxpixmap.h b/hw/dmx/dmxpixmap.h index 6441834..4fcb710 100644 --- a/hw/dmx/dmxpixmap.h +++ b/hw/dmx/dmxpixmap.h @@ -53,6 +53,13 @@ extern PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, unsigned usage_hint); extern Bool dmxDestroyPixmap(PixmapPtr pPixmap); extern RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap); +extern Bool dmxModifyPixmapHeader (PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData); extern void dmxBECreatePixmap(PixmapPtr pPixmap); extern Bool dmxBEFreePixmap(PixmapPtr pPixmap); diff --git a/hw/dmx/dmxprop.c b/hw/dmx/dmxprop.c index 376313d..2dc5bf4 100644 --- a/hw/dmx/dmxprop.c +++ b/hw/dmx/dmxprop.c @@ -61,287 +61,327 @@ #include "dmx.h" #include "dmxprop.h" +#include "dmxwindow.h" #include "dmxlog.h" +#include "dmxatom.h" +#include "dmxselection.h" -/** Holds the window id of all DMX windows on the backend X server. */ -#define DMX_ATOMNAME "DMX_NAME" - -/** The identification string of this DMX server */ -#define DMX_IDENT "Xdmx" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif -extern char *display; +static int (*dmxSaveProcVector[256]) (ClientPtr); -static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev) +static int +dmxProcChangeProperty (ClientPtr client) { - return 0; + WindowPtr pWin; + PropertyPtr pProp; + int err; + REQUEST(xChangePropertyReq); + + err = (*dmxSaveProcVector[X_ChangeProperty]) (client); + if (err != Success) + return err; + + if (dixLookupWindow (&pWin, + stuff->window, + serverClient, + DixReadAccess) != Success || + dixLookupProperty (&pProp, + pWin, + stuff->property, + serverClient, + DixReadAccess) != Success) + return Success; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int j; + + if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->window, + XRT_WINDOW, + DixReadAccess))) + { + FOR_NSCREENS_BACKWARD(j) { + WindowPtr pScrWin; + + if (dixLookupWindow (&pScrWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + dmxBESetWindowProperty (pScrWin, pProp); + } + } + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + stuff->nUnits); + + return Success; + } +#endif + + dmxBESetWindowProperty (pWin, pProp); + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + stuff->nUnits); + + return Success; } -static const unsigned char *dmxPropertyIdentifier(void) +static void +dmxDeleteProperty (WindowPtr pWin, + Atom property) { - /* RATS: These buffers are only used in - * length-limited calls. */ - char hostname[256]; - static char buf[128]; - static int initialized = 0; - - if (initialized++) return (unsigned char *)buf; - - XmuGetHostname(hostname, sizeof(hostname)); - XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display); - return (unsigned char *)buf; + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window window; + + window = dmxBEGetSelectionAdjustedPropertyWindow (pWin); + if (!window) + return; + + XLIB_PROLOGUE (dmxScreen); + XDeleteProperty (dmxScreen->beDisplay, + window, + dmxBEAtom (dmxScreen, property)); + XLIB_EPILOGUE (dmxScreen); } -/** Starting with the \a start screen, iterate over all of the screens - * on the same physical X server as \a start, calling \a f with the - * screen and the \a closure. (The common case is that \a start is the - * only DMX window on the backend X server.) */ -void *dmxPropertyIterate(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) +static int +dmxProcDeleteProperty (ClientPtr client) { - DMXScreenInfo *pt; - - if (!start->next) { - if (!start->beDisplay) return NULL; - return f(start, closure); + WindowPtr pWin; + int err; + REQUEST(xDeletePropertyReq); + + err = (*dmxSaveProcVector[X_DeleteProperty]) (client); + if (err != Success) + return err; + + if (dixLookupWindow (&pWin, + stuff->window, + serverClient, + DixReadAccess) != Success) + return err; + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int j; + + if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->window, + XRT_WINDOW, + DixReadAccess))) + { + FOR_NSCREENS_BACKWARD(j) { + WindowPtr pScrWin; + + if (dixLookupWindow (&pScrWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + dmxDeleteProperty (pScrWin, stuff->property); + } + } + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + -1); + + return Success; } +#endif - for (pt = start->next; /* condition at end of loop */; pt = pt->next) { - void *retval; - /* beDisplay ban be NULL if a screen was detached */ - dmxLog(dmxDebug, "pt = %p\n", pt); - dmxLog(dmxDebug, "pt->beDisplay = %p\n", pt->beDisplay); - if (pt->beDisplay && (retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; + dmxDeleteProperty (pWin, stuff->property); + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + -1); + + return Success; } -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom) +static int +dmxProcGetProperty (ClientPtr client) { - Display *dpy = dmxScreen->beDisplay; - XTextProperty tp; - XTextProperty tproot; - const char *pt; - int retcode = 0; - char **list = NULL; - int count = 0; - int i; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return 0; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - if (!strncmp((char *)tp.value, DMX_IDENT, strlen(DMX_IDENT))) { - int flag = 0; - for (i = 0; i < count; i++) - if (!strcmp(list[i], (char *)tp.value)) { - ++flag; - break; - } - if (flag) continue; - ++retcode; - dmxLogOutputWarning(dmxScreen, - "%s also running on %s\n", - tp.value, dmxScreen->name); - list = xrealloc(list, ++count * sizeof(*list)); - list[count-1] = xalloc(tp.nitems + 2); - strncpy(list[count-1], (char *)tp.value, tp.nitems + 1); - } - XFree(tp.value); - } - } + WindowPtr pWin; + PropertyPtr pProp; + int err; + REQUEST(xGetPropertyReq); + + err = (*dmxSaveProcVector[X_GetProperty]) (client); + if (err != Success || !stuff->delete) + return err; + + if (dixLookupWindow (&pWin, + stuff->window, + serverClient, + DixReadAccess) != Success || + dixLookupProperty (&pProp, + pWin, + stuff->property, + serverClient, + DixReadAccess) != BadMatch) + return Success; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int j; + + if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->window, + XRT_WINDOW, + DixReadAccess))) + { + FOR_NSCREENS_BACKWARD(j) { + WindowPtr pScrWin; + + if (dixLookupWindow (&pScrWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + { + dmxDeleteProperty (pScrWin, stuff->property); + } + } + } + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + -1); + + return Success; } - XSetErrorHandler(dmxOldHandler); - - for (i = 0; i < count; i++) xfree(list[i]); - xfree(list); - XFree(tproot.value); - if (!retcode) - dmxLogOutput(dmxScreen, "No Xdmx server running on backend\n"); - return retcode; +#endif + + dmxDeleteProperty (pWin, stuff->property); + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + -1); + + return Success; } -/** Returns NULL if this is the only Xdmx window on the display. - * Otherwise, returns a pointer to the dmxScreen of the other windows on - * the display. */ -static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen, - Atom atom) +static void +dmxRotateProperties (WindowPtr pWin, + Atom *atoms, + Atom *buf, + int nAtoms, + int nPositions) { - Display *dpy = dmxScreen->beDisplay; - const unsigned char *id = dmxPropertyIdentifier(); - XTextProperty tproot; - XTextProperty tp; - const char *pt; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return NULL; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - dmxLog(dmxDebug,"On %s/%lu: %s\n", - dmxScreen->name, win, tp.value); - if (!strncmp((char *)tp.value, (char *)id, - strlen((char *)id))) { - int idx; - - if (!(pt = strchr((char *)tp.value, ','))) continue; - idx = strtol(pt+1, NULL, 10); - if (idx < 0 || idx >= dmxNumScreens) continue; - if (dmxScreens[idx].scrnWin != win) continue; - XSetErrorHandler(dmxOldHandler); - return &dmxScreens[idx]; - } - XFree(tp.value); - } - } - } - XSetErrorHandler(dmxOldHandler); - XFree(tproot.value); - return 0; + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window window; + int i; + + window = dmxBEGetSelectionAdjustedPropertyWindow (pWin); + if (!window) + return; + + for (i = 0; i < nAtoms; i++) + buf[i] = dmxBEAtom (dmxScreen, atoms[i]); + + XLIB_PROLOGUE (dmxScreen); + XRotateWindowProperties (dmxScreen->beDisplay, + window, + buf, + nAtoms, + nPositions); + XLIB_EPILOGUE (dmxScreen); } -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -int dmxPropertyDisplay(DMXScreenInfo *dmxScreen) +static int +dmxProcRotateProperties (ClientPtr client) { - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; + WindowPtr pWin; + int err; + Atom *buf, *atoms; + REQUEST(xRotatePropertiesReq); + + err = (*dmxSaveProcVector[X_RotateProperties]) (client); + if (err != Success) + return err; + + atoms = (Atom *) & stuff[1]; + buf = (Atom *) xalloc (stuff->nAtoms * sizeof (Atom)); + if (!buf) + return Success; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int j; + + if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->window, + XRT_WINDOW, + DixReadAccess))) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + dmxRotateProperties (pWin, atoms, buf, stuff->nAtoms, + stuff->nPositions); + } + } + + xfree (buf); + + return Success; + } +#endif - if (!dpy) - return 0; + if (dixLookupWindow (&pWin, + stuff->window, + serverClient, + DixReadAccess) == Success) + dmxRotateProperties (pWin, atoms, buf, stuff->nAtoms, + stuff->nPositions); - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if (dmxPropertyCheckOtherServers(dmxScreen, atom)) { - dmxScreen->shared = 1; - return 1; - } - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeReplace, id, strlen((char *)id)); - return 0; + xfree (buf); + + return Success; } -/** Returns 1 if the dmxScreen and the display in \a name are on the - * same display, or 0 otherwise. We can't just compare the display - * names because there can be multiple synonyms for the same display, - * some of which cannot be determined without accessing the display - * itself (e.g., domain aliases or machines with multiple NICs). */ -int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name) +/** Initialize property support. In addition to the screen function call + * pointers, DMX also hooks in at the ProcVector[] level. Here the old + * ProcVector function pointers are saved and the new ProcVector + * function pointers are initialized. */ +void dmxInitProps (void) { - Display *dpy0 = dmxScreen->beDisplay; - Atom atom0; - XTextProperty tp0; - Display *dpy1 = NULL; - Atom atom1; - XTextProperty tp1; - int retval = 0; - - if (!dpy0) - return 0; - - tp0.nitems = 0; - tp1.nitems = 0; - - if ((atom0 = XInternAtom(dpy0, DMX_ATOMNAME, True)) == None) { - dmxLog(dmxWarning, "No atom on %s\n", dmxScreen->name); - return 0; - } - if (!XGetTextProperty(dpy0, RootWindow(dpy0,0), &tp0, atom0) - || !tp0.nitems) { - dmxLog(dmxWarning, "No text property on %s\n", dmxScreen->name); - return 0; - } + int i; - if (!(dpy1 = XOpenDisplay(name))) { - dmxLog(dmxWarning, "Cannot open %s\n", name); - goto cleanup; - } - atom1 = XInternAtom(dpy1, DMX_ATOMNAME, True); - if (atom1 == None) { - dmxLog(dmxDebug, "No atom on %s\n", name); - goto cleanup; - } - if (!XGetTextProperty(dpy1, RootWindow(dpy1,0), &tp1, atom1) - || !tp1.nitems) { - dmxLog(dmxDebug, "No text property on %s\n", name); - goto cleanup; - } - if (!strcmp((char *)tp0.value, (char *)tp1.value)) retval = 1; + for (i = 0; i < 256; i++) + dmxSaveProcVector[i] = ProcVector[i]; - cleanup: - if (tp0.nitems) XFree(tp0.value); - if (tp1.nitems) XFree(tp1.value); - if (dpy1) XCloseDisplay(dpy1); - return retval; + ProcVector[X_ChangeProperty] = dmxProcChangeProperty; + ProcVector[X_DeleteProperty] = dmxProcDeleteProperty; + ProcVector[X_GetProperty] = dmxProcGetProperty; + ProcVector[X_RotateProperties] = dmxProcRotateProperties; } -/** Prints a log message if \a dmxScreen is on the same backend X server - * as some other DMX backend (output) screen. Modifies the property - * (#DMX_ATOMNAME) on the backend X server to reflect the creation of \a - * dmxScreen. - * - * The root window of the backend X server holds a list of window ids - * for all DMX windows (on this DMX server or some other DMX server). - * - * This list can then be iterated, and the property for each window can - * be examined. This property contains the following tuple (no quotes): - * - * "#DMX_IDENT:<hostname running DMX>:<display name of DMX>,<screen number>" - */ -void dmxPropertyWindow(DMXScreenInfo *dmxScreen) +/** Reset property support by restoring the original ProcVector function + * pointers. */ +void dmxResetProps (void) { - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; - Window win = dmxScreen->scrnWin; - DMXScreenInfo *other; - char buf[128]; /* RATS: only used with XmuSnprintf */ - - if (!dpy) - return; /* FIXME: What should be done here if Xdmx is started - * with this screen initially detached? - */ - - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) { - DMXScreenInfo *tmp = dmxScreen->next; - dmxScreen->next = (other->next ? other->next : other); - other->next = (tmp ? tmp : dmxScreen); - dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n", - dmxScreen->index, dmxScreen->name, dmxScreen->scrnWin, - other->index, other->name, other->scrnWin); - } - - XmuSnprintf(buf, sizeof(buf), ".%d,%lu", dmxScreen->index, - (long unsigned)win); - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); + int i; - XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index); - XChangeProperty(dpy, win, atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); + for (i = 0; i < 256; i++) + ProcVector[i] = dmxSaveProcVector[i]; } diff --git a/hw/dmx/dmxprop.h b/hw/dmx/dmxprop.h index 50135cd..5f800f4 100644 --- a/hw/dmx/dmxprop.h +++ b/hw/dmx/dmxprop.h @@ -36,11 +36,6 @@ #ifndef _DMXPROP_H_ #define _DMXPROP_H_ -extern int dmxPropertyDisplay(DMXScreenInfo *dmxScreen); -extern void dmxPropertyWindow(DMXScreenInfo *dmxScreen); -extern void *dmxPropertyIterate(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, - void *closure), - void *closure); -extern int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name); +extern void dmxInitProps (void); +extern void dmxResetProps (void); #endif diff --git a/hw/dmx/dmxrandr.c b/hw/dmx/dmxrandr.c new file mode 100644 index 0000000..18ba733 --- /dev/null +++ b/hw/dmx/dmxrandr.c @@ -0,0 +1,1353 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#ifdef RANDR +#include "dmx.h" +#include "dmxlog.h" +#include "dmxextension.h" +#include "dmxcb.h" +#include "dmxrandr.h" +#include "dmxclient.h" +#include "dmxatom.h" +#include "dmxwindow.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include <xcb/randr.h> + +static int xRROutputsForFirstScreen = 1; +static int xRRCrtcsForFirstScreen = 1; + +static DMXScreenInfo * +dmxRRGetScreenForCrtc (ScreenPtr pScreen, + RRCrtcPtr crtc) +{ + int i; + + rrScrPriv (pScreen); + + for (i = 0; i < pScrPriv->numCrtcs; i++) + if (pScrPriv->crtcs[i] == crtc) + break; + + if (i == pScrPriv->numCrtcs) + return NULL; + + if (i < xRRCrtcsForFirstScreen) + return dmxScreens; + + return &dmxScreens[((i - xRRCrtcsForFirstScreen) / xRRCrtcsPerScreen) + 1]; +} + +static DMXScreenInfo * +dmxRRGetScreenForOutput (ScreenPtr pScreen, + RROutputPtr output) +{ + int i; + + rrScrPriv (pScreen); + + for (i = 0; i < pScrPriv->numOutputs; i++) + if (pScrPriv->outputs[i] == output) + break; + + if (i == pScrPriv->numOutputs) + return NULL; + + if (i < xRROutputsForFirstScreen) + return dmxScreens; + + return &dmxScreens[((i - xRROutputsForFirstScreen) / xRROutputsPerScreen) + + 1]; +} + +static RRModePtr +dmxRRGetMode (XRRScreenResources *r, + unsigned long mode) +{ + xRRModeInfo modeInfo; + int i; + + for (i = 0; i < r->nmode; i++) + { + if (r->modes[i].id == mode) + { + memset (&modeInfo, '\0', sizeof (modeInfo)); + + modeInfo.width = r->modes[i].width; + modeInfo.height = r->modes[i].height; + modeInfo.dotClock = r->modes[i].dotClock; + modeInfo.hSyncStart = r->modes[i].hSyncStart; + modeInfo.hSyncEnd = r->modes[i].hSyncEnd; + modeInfo.hTotal = r->modes[i].hTotal; + modeInfo.hSkew = r->modes[i].hSkew; + modeInfo.vSyncStart = r->modes[i].vSyncStart; + modeInfo.vSyncEnd = r->modes[i].vSyncEnd; + modeInfo.vTotal = r->modes[i].vTotal; + modeInfo.nameLength = strlen (r->modes[i].name); + modeInfo.modeFlags = r->modes[i].modeFlags; + + return RRModeGet (&modeInfo, r->modes[i].name); + } + } + + return NULL; +} + +static RRCrtcPtr +dmxRRGetCrtc (ScreenPtr pScreen, + DMXScreenInfo *dmxScreen, + unsigned long crtc) +{ + int baseCrtc = 0; + int numCrtc = xRRCrtcsForFirstScreen; + int i; + + rrScrPriv (pScreen); + + if (!crtc) + return NULL; + + if (dmxScreen != dmxScreens) + { + baseCrtc = xRRCrtcsForFirstScreen + + ((dmxScreen - dmxScreens) - 1) * xRRCrtcsPerScreen; + numCrtc = xRRCrtcsPerScreen; + } + + for (i = 0; i < numCrtc; i++) + if (pScrPriv->crtcs[baseCrtc + i]->devPrivate == (void *) crtc) + return pScrPriv->crtcs[baseCrtc + i]; + + return NULL; +} + +static RROutputPtr +dmxRRGetOutput (ScreenPtr pScreen, + DMXScreenInfo *dmxScreen, + unsigned long output) +{ + int baseOutput = 0; + int numOutput = xRROutputsForFirstScreen; + int i; + + rrScrPriv (pScreen); + + if (!output) + return NULL; + + if (dmxScreen != dmxScreens) + { + baseOutput = xRROutputsForFirstScreen + + ((dmxScreen - dmxScreens) - 1) * xRROutputsPerScreen; + numOutput = xRROutputsPerScreen; + } + + for (i = 0; i < numOutput; i++) + if (pScrPriv->outputs[baseOutput + i]->devPrivate == (void *) output) + return pScrPriv->outputs[baseOutput + i]; + + return NULL; +} + +static Bool +dmxRRUpdateCrtc (ScreenPtr pScreen, + DMXScreenInfo *dmxScreen, + XRRScreenResources *r, + unsigned long xcrtc) +{ + XRRCrtcInfo *c = NULL; + RRCrtcPtr crtc; + RRModePtr mode = NULL; + RROutputPtr *outputs = NULL; + XRRCrtcGamma *gamma = NULL; + int i, noutput = 0; + + crtc = dmxRRGetCrtc (pScreen, dmxScreen, xcrtc); + if (!crtc) + return TRUE; /* do nothing if the crtc doesn't exist */ + + XLIB_PROLOGUE (dmxScreen); + c = XRRGetCrtcInfo (dmxScreen->beDisplay, r, xcrtc); + XLIB_EPILOGUE (dmxScreen); + + if (!c) + return FALSE; + + if (c->noutput) + { + outputs = xalloc (sizeof (RROutputPtr) * c->noutput); + if (!outputs) + return FALSE; + } + + if (c->mode) + mode = dmxRRGetMode (r, c->mode); + + for (i = 0; i < c->noutput; i++) + { + outputs[noutput] = dmxRRGetOutput (pScreen, dmxScreen, c->outputs[i]); + if (outputs[noutput]) + noutput++; + } + + XLIB_PROLOGUE (dmxScreen); + gamma = XRRGetCrtcGamma (dmxScreen->beDisplay, xcrtc); + XLIB_EPILOGUE (dmxScreen); + + if (!gamma) + { + if (mode) + RRModeDestroy (mode); + + return FALSE; + } + + RRCrtcGammaSet (crtc, gamma->red, gamma->green, gamma->blue); + + XRRFreeGamma (gamma); + + RRCrtcNotify (crtc, mode, c->x, c->y, c->rotation, noutput, outputs); + + if (outputs) + xfree (outputs); + + if (mode) + RRModeDestroy (mode); + + XRRFreeCrtcInfo (c); + + return TRUE; +} + +static Bool +dmxRRUpdateOutput (ScreenPtr pScreen, + DMXScreenInfo *dmxScreen, + XRRScreenResources *r, + unsigned long xoutput) +{ + XRROutputInfo *o = NULL; + RROutputPtr output, *clones = NULL; + RRModePtr *modes = NULL; + RRCrtcPtr *crtcs = NULL; + int i, nclone = 0, ncrtc = 0; + + output = dmxRRGetOutput (pScreen, dmxScreen, xoutput); + if (!output) + return TRUE; /* do nothing if the output doesn't exist */ + + XLIB_PROLOGUE (dmxScreen); + o = XRRGetOutputInfo (dmxScreen->beDisplay, r, xoutput); + XLIB_EPILOGUE (dmxScreen); + + if (!o) + return FALSE; + + if (o->nclone) + { + clones = xalloc (sizeof (RROutputPtr) * o->nclone); + if (!clones) + return FALSE; + } + + if (o->nmode) + { + modes = xalloc (sizeof (RRModePtr) * o->nmode); + if (!modes) + return FALSE; + } + + if (o->ncrtc) + { + crtcs = xalloc (sizeof (RRCrtcPtr) * o->ncrtc); + if (!crtcs) + return FALSE; + } + + for (i = 0; i < o->nclone; i++) + { + clones[nclone] = dmxRRGetOutput (pScreen, dmxScreen, o->clones[i]); + if (clones[nclone]) + nclone++; + } + + for (i = 0; i < o->ncrtc; i++) + { + crtcs[ncrtc] = dmxRRGetCrtc (pScreen, dmxScreen, o->crtcs[i]); + if (crtcs[ncrtc]) + ncrtc++; + } + + for (i = 0; i < o->nmode; i++) + { + modes[i] = dmxRRGetMode (r, o->modes[i]); + if (!modes[i]) + return FALSE; + } + + if (!RROutputSetClones (output, clones, nclone)) + return FALSE; + + if (!RROutputSetModes (output, modes, o->nmode, o->npreferred)) + return FALSE; + + if (!RROutputSetCrtcs (output, crtcs, ncrtc)) + return FALSE; + + if (!RROutputSetConnection (output, o->connection)) + return FALSE; + + if (!RROutputSetSubpixelOrder (output, o->subpixel_order)) + return FALSE; + + if (!RROutputSetPhysicalSize (output, o->mm_width, o->mm_height)) + return FALSE; + + if (clones) + xfree (clones); + + if (modes) + xfree (modes); + + if (crtcs) + xfree (crtcs); + + XRRFreeOutputInfo (o); + + return TRUE; +} + +static Bool +dmxRRUpdateOutputProperty (ScreenPtr pScreen, + DMXScreenInfo *dmxScreen, + XRRScreenResources *r, + unsigned long xoutput, + unsigned long xproperty) +{ + RROutputPtr output; + XRRPropertyInfo *info = NULL; + unsigned char *prop; + int format, status = !Success; + unsigned long nElements, bytesAfter; + Atom type, atom; + INT32 *values = NULL; + + output = dmxRRGetOutput (pScreen, dmxScreen, xoutput); + if (!output) + return TRUE; /* do nothing if the output doesn't exist */ + + atom = dmxAtom (dmxScreen, xproperty); + + XLIB_PROLOGUE (dmxScreen); + status = XRRGetOutputProperty (dmxScreen->beDisplay, xoutput, xproperty, + 0, 8192, FALSE, FALSE, + AnyPropertyType, &type, &format, + &nElements, &bytesAfter, &prop); + XLIB_EPILOGUE (dmxScreen); + + if (status != Success) + return FALSE; + + XLIB_PROLOGUE (dmxScreen); + info = XRRQueryOutputProperty (dmxScreen->beDisplay, xoutput, xproperty); + XLIB_EPILOGUE (dmxScreen); + + if (!info) + return FALSE; + + if (info->num_values) + { + int i; + + values = xalloc (info->num_values * sizeof (INT32)); + if (!values) + return FALSE; + + for (i = 0; i < info->num_values; i++) + values[i] = info->values[i]; + } + + if (type == XA_ATOM && format == 32) + { + INT32 *atoms = (INT32 *) prop; + int i; + + for (i = 0; i < nElements; i++) + atoms[i] = dmxAtom (dmxScreen, atoms[i]); + + if (!info->range && info->num_values > 0) + { + for (i = 0; i < info->num_values; i++) + values[i] = dmxAtom (dmxScreen, values[i]); + } + } + + RRConfigureOutputProperty (output, atom, FALSE, + info->range, info->immutable, info->num_values, + values); + + RRChangeOutputProperty (output, atom, type, format, PropModeReplace, + nElements, prop, FALSE, TRUE); + + if (values) + xfree (values); + + XFree (info); + XFree (prop); + + return TRUE; +} + +static Bool +dmxRRGetInfo (ScreenPtr pScreen, + Rotation *rotations) +{ + int i; + + rrScrPriv (pScreen); + + if (pScreen->myNum) + { + *rotations = RR_Rotate_0; + return TRUE; + } + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + XRRScreenResources *r = NULL; + int outputsPerScreen = xRROutputsForFirstScreen; + int baseOutput = 0; + int crtcsPerScreen = xRRCrtcsForFirstScreen; + int baseCrtc = 0; + int j; + + if (i) + { + outputsPerScreen = xRROutputsPerScreen; + baseOutput = xRROutputsForFirstScreen + + (i - 1) * xRROutputsPerScreen; + crtcsPerScreen = xRRCrtcsPerScreen; + baseCrtc = xRRCrtcsForFirstScreen + + (i - 1) * xRRCrtcsPerScreen; + } + + assert (baseOutput + outputsPerScreen <= pScrPriv->numOutputs); + assert (baseCrtc + crtcsPerScreen <= pScrPriv->numCrtcs); + + dmxScreen->beRandrPending = TRUE; + + if (dmxScreen->beRandr && dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); + r = XRRGetScreenResources (dmxScreen->beDisplay, + dmxScreen->scrnWin); + XLIB_EPILOGUE (dmxScreen); + + if (r) + { + if (r->noutput > outputsPerScreen) + dmxLog (dmxWarning, + "dmxRRGetInfo: ignoring %d BE server outputs\n", + r->noutput - outputsPerScreen); + + if (r->ncrtc > crtcsPerScreen) + dmxLog (dmxWarning, + "dmxRRGetInfo: ignoring %d BE server crtcs\n", + r->ncrtc - crtcsPerScreen); + } + } + + for (j = 0; j < outputsPerScreen; j++) + { + RROutputPtr output = pScrPriv->outputs[baseOutput + j]; + + if (r && j < r->noutput) + output->devPrivate = (void *) r->outputs[j]; + else + output->devPrivate = NULL; + } + + for (j = 0; j < crtcsPerScreen; j++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[baseCrtc + j]; + + crtc->devPrivate = NULL; + + if (r && j < r->ncrtc) + crtc->devPrivate = (void *) r->crtcs[j]; + else + crtc->devPrivate = NULL; + } + + for (j = 0; j < outputsPerScreen; j++) + { + RROutputPtr output = pScrPriv->outputs[baseOutput + j]; + + if (r) + { + if (j < r->noutput) + { +#ifdef _XSERVER64 + Atom64 *props = NULL; +#else + Atom *props = NULL; +#endif + + int nProp = 0, k; + + if (!dmxRRUpdateOutput (pScreen, + dmxScreen, + r, + r->outputs[j])) + return (dmxScreen->beRandrPending = FALSE); + + XLIB_PROLOGUE (dmxScreen); + props = XRRListOutputProperties (dmxScreen->beDisplay, + r->outputs[j], + &nProp); + XLIB_EPILOGUE (dmxScreen); + + if (nProp) + { + for (k = 0; k < nProp; k++) + if (!dmxRRUpdateOutputProperty (pScreen, + dmxScreen, + r, + r->outputs[j], + props[k])) + return (dmxScreen->beRandrPending = FALSE); + + XFree (props); + } + } + else + { + if (!RROutputSetModes (output, NULL, 0, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetClones (output, NULL, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetCrtcs (output, NULL, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetConnection (output, RR_Disconnected)) + return (dmxScreen->beRandrPending = FALSE); + } + } + else if (dmxScreen->beDisplay && j == 0) + { + RRModePtr mode; + xRRModeInfo modeInfo; + char name[64]; + + sprintf (name, + "%dx%d", + dmxScreen->scrnWidth, dmxScreen->scrnHeight); + + memset (&modeInfo, '\0', sizeof (modeInfo)); + modeInfo.width = dmxScreen->scrnWidth; + modeInfo.height = dmxScreen->scrnHeight; + modeInfo.nameLength = strlen (name); + + mode = RRModeGet (&modeInfo, name); + if (!mode) + return (dmxScreen->beRandrPending = FALSE); + + if (!RROutputSetModes (output, &mode, 1, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetClones (output, NULL, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetCrtcs (output, &pScrPriv->crtcs[baseCrtc], 1)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetConnection (output, RR_Connected)) + return (dmxScreen->beRandrPending = FALSE); + } + else + { + if (!RROutputSetModes (output, NULL, 0, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetClones (output, NULL, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetCrtcs (output, NULL, 0)) + return (dmxScreen->beRandrPending = FALSE); + if (!RROutputSetConnection (output, RR_Disconnected)) + return FALSE; + } + } + + for (j = 0; j < crtcsPerScreen; j++) + { + RRCrtcPtr crtc = pScrPriv->crtcs[baseCrtc + j]; + + if (r) + { + if (j < r->ncrtc) + { + if (!dmxRRUpdateCrtc (pScreen, dmxScreen, r, r->crtcs[j])) + return (dmxScreen->beRandrPending = FALSE); + } + else + { + RRCrtcNotify (crtc, NULL, 0, 0, RR_Rotate_0, 0, NULL); + } + } + else if (dmxScreen->beDisplay && j == 0) + { + RRModePtr mode; + xRRModeInfo modeInfo; + char name[64]; + + sprintf (name, + "%dx%d", + dmxScreen->scrnWidth, dmxScreen->scrnHeight); + + memset (&modeInfo, '\0', sizeof (modeInfo)); + modeInfo.width = dmxScreen->scrnWidth; + modeInfo.height = dmxScreen->scrnHeight; + modeInfo.nameLength = strlen (name); + + mode = RRModeGet (&modeInfo, name); + if (!mode) + return (dmxScreen->beRandrPending = FALSE); + + RRCrtcNotify (crtc, mode, + dmxScreen->rootX, dmxScreen->rootY, + RR_Rotate_0, 1, + &pScrPriv->outputs[baseOutput]); + + if (mode) + RRModeDestroy (mode); + } + else + { + RRCrtcNotify (crtc, NULL, 0, 0, RR_Rotate_0, 0, NULL); + } + } + + if (r) + XRRFreeScreenResources (r); + + dmxScreen->beRandrPending = FALSE; + } + + *rotations = RR_Rotate_0; + + for (i = 0; i < pScrPriv->numCrtcs; i++) + *rotations |= pScrPriv->crtcs[i]->rotations; + + return TRUE; +} + +static unsigned long +dmxRRGetXMode (XRRScreenResources *r, + RRModePtr mode) +{ + xRRModeInfo modeInfo = mode->mode; + int i; + + for (i = 0; i < r->nmode; i++) + { + if (modeInfo.width == r->modes[i].width && + modeInfo.height == r->modes[i].height && + modeInfo.dotClock == r->modes[i].dotClock && + modeInfo.hSyncStart == r->modes[i].hSyncStart && + modeInfo.hSyncEnd == r->modes[i].hSyncEnd && + modeInfo.hTotal == r->modes[i].hTotal && + modeInfo.hSkew == r->modes[i].hSkew && + modeInfo.vSyncStart == r->modes[i].vSyncStart && + modeInfo.vSyncEnd == r->modes[i].vSyncEnd && + modeInfo.vTotal == r->modes[i].vTotal && + modeInfo.nameLength == r->modes[i].nameLength && + modeInfo.modeFlags == r->modes[i].modeFlags) + { + if (!memcmp (r->modes[i].name, mode->name, modeInfo.nameLength)) + return r->modes[i].id; + } + } + + return None; +} + +static Bool +dmxRRScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int i; + + for (i = 0; i < dmxNumScreens; i++) + dmxResizeRootWindow (WindowTable[i], 0, 0, width, height); + + for (i = 0; i < dmxNumScreens; i++) + dmxUpdateScreenResources (screenInfo.screens[i], + 0, 0, width, height); + + dmxSetWidthHeight (width, height); + XineramaReinitData (pScreen); + dmxConnectionBlockCallback (); + } + else +#endif + { + dmxResizeRootWindow (WindowTable[pScreen->myNum], 0, 0, width, height); + dmxUpdateScreenResources (pScreen, 0, 0, width, height); + } + + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + + RRScreenSizeNotify (pScreen); + + return TRUE; +} + +static Bool +dmxRRCrtcSet (ScreenPtr pScreen, + RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + int numOutputs, + RROutputPtr *outputs) +{ + XRRScreenResources *r = NULL; + +#ifdef _XSERVER64 + RROutput64 *o = NULL; +#else + RROutput *o = NULL; +#endif + + RRMode m = None; + Status status = !RRSetConfigSuccess; + int i; + DMXScreenInfo *dmxScreen; + + dmxScreen = dmxRRGetScreenForCrtc (pScreen, crtc); + if (!dmxScreen) + return FALSE; + + if (dmxScreen->beRandrPending) + return RRCrtcNotify (crtc, mode, x, y, rotation, numOutputs, outputs); + + for (i = 0; i < numOutputs; i++) + if (!dmxRRGetOutput (pScreen, + dmxScreen, + (unsigned long) outputs[i]->devPrivate)) + return FALSE; + + if (numOutputs) + { + o = xalloc (sizeof (*o) * numOutputs); + if (!o) + return FALSE; + } + + XLIB_PROLOGUE (dmxScreen); + r = XRRGetScreenResources (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay)); + XLIB_EPILOGUE (dmxScreen); + + if (!r) + return FALSE; + + if (mode) + { + m = dmxRRGetXMode (r, mode); + if (!m) + { + XRRFreeScreenResources (r); + if (o) + xfree (o); + + return FALSE; + } + } + + for (i = 0; i < numOutputs; i++) + o[i] = (unsigned long) outputs[i]->devPrivate; + + XLIB_PROLOGUE (dmxScreen); + status = XRRSetCrtcConfig (dmxScreen->beDisplay, r, + (unsigned long) crtc->devPrivate, + CurrentTime, + x, y, + m, + rotation, + o, numOutputs); + XLIB_EPILOGUE (dmxScreen); + + XRRFreeScreenResources (r); + + if (o) + xfree (o); + + if (status != RRSetConfigSuccess) + return FALSE; + + return RRCrtcNotify (crtc, mode, x, y, rotation, numOutputs, outputs); +} + +static Bool +dmxRRCrtcSetGamma (ScreenPtr pScreen, + RRCrtcPtr crtc) +{ + XRRCrtcGamma *gamma; + DMXScreenInfo *dmxScreen; + + dmxScreen = dmxRRGetScreenForCrtc (pScreen, crtc); + if (!dmxScreen) + return FALSE; + + if (dmxScreen->beRandrPending) + return TRUE; + + gamma = XRRAllocGamma (crtc->gammaSize); + if (!gamma) + return FALSE; + + memcpy (gamma->red, crtc->gammaRed, gamma->size * sizeof (CARD16)); + memcpy (gamma->green, crtc->gammaGreen, gamma->size * sizeof (CARD16)); + memcpy (gamma->blue, crtc->gammaBlue, gamma->size * sizeof (CARD16)); + + XLIB_PROLOGUE (dmxScreen); + XRRSetCrtcGamma (dmxScreen->beDisplay, (unsigned long) crtc->devPrivate, + gamma); + XLIB_EPILOGUE (dmxScreen); + + XRRFreeGamma (gamma); + + return TRUE; +} + +static Bool +dmxRROutputSetProperty (ScreenPtr pScreen, + RROutputPtr output, + Atom property, + RRPropertyValuePtr value) +{ + RRPropertyPtr p; + +#ifdef _XSERVER64 + Atom64 atom = 0, type = 0; +#else + Atom atom = 0, type = 0; +#endif + + long *values = value->data; + long *validValues; + int i; + DMXScreenInfo *dmxScreen; + + dmxScreen = dmxRRGetScreenForOutput (pScreen, output); + if (!dmxScreen) + return FALSE; + + if (dmxScreen->beRandrPending) + return TRUE; + + p = RRQueryOutputProperty (output, property); + if (!p) + return FALSE; + + validValues = p->valid_values; + + atom = dmxBEAtom (dmxScreen, property); + type = dmxBEAtom (dmxScreen, value->type); + + if (type == XA_ATOM && value->format == 32) + { + INT32 *atoms = (INT32 *) value->data; + + for (i = 0; i < value->size; i++) + if (!ValidAtom (atoms[i])) + return FALSE; + + if (p->num_valid > 0) + { + for (i = 0; i < p->num_valid; i++) + if (!ValidAtom (p->valid_values[i])) + return FALSE; + + for (i = 0; i < value->size; i++) + { + int j; + + for (j = 0; j < p->num_valid; j++) + if (p->valid_values[j] == atoms[i]) + break; + + if (j == p->num_valid) + return FALSE; + } + + validValues = xalloc (p->num_valid * sizeof (long)); + if (!validValues) + return FALSE; + + for (i = 0; i < p->num_valid; i++) + validValues[i] = dmxBEAtom (dmxScreen, p->valid_values[i]); + } + + if (value->size) + { + int size = value->size * (value->format / 8); + + values = xalloc (size); + if (!values) + return FALSE; + + for (i = 0; i < value->size; i++) + values[i] = dmxBEAtom (dmxScreen, atoms[i]); + } + } + else + { + if (p->num_valid > 0) + { + validValues = xalloc (p->num_valid * sizeof (long)); + if (!validValues) + return FALSE; + + for (i = 0; i < p->num_valid; i++) + validValues[i] = p->valid_values[i]; + } + } + + XLIB_PROLOGUE (dmxScreen); + XRRConfigureOutputProperty (dmxScreen->beDisplay, + (unsigned long) output->devPrivate, + atom, p->is_pending, p->range, p->num_valid, + validValues); + XRRChangeOutputProperty (dmxScreen->beDisplay, + (unsigned long) output->devPrivate, + atom, type, value->format, PropModeReplace, + (unsigned char *) values, value->size); + XLIB_EPILOGUE (dmxScreen); + + if (validValues != p->valid_values) + xfree (validValues); + + if (values != value->data) + xfree (values); + + return TRUE; +} + +static Bool +dmxRROutputValidateMode (ScreenPtr pScreen, + RROutputPtr output, + RRModePtr mode) +{ + XRRModeInfo *modeInfo; + +#ifdef _XSERVER64 + RRMode64 m = 0; +#else + RRMode m = 0; +#endif + + DMXScreenInfo *dmxScreen; + + dmxScreen = dmxRRGetScreenForOutput (pScreen, output); + if (!dmxScreen) + return FALSE; + + if (dmxScreen->beRandrPending) + return TRUE; + + modeInfo = XRRAllocModeInfo (mode->name, mode->mode.nameLength); + if (!modeInfo) + return FALSE; + + modeInfo->width = mode->mode.width; + modeInfo->height = mode->mode.height; + modeInfo->dotClock = mode->mode.dotClock; + modeInfo->hSyncStart = mode->mode.hSyncStart; + modeInfo->hSyncEnd = mode->mode.hSyncEnd; + modeInfo->hTotal = mode->mode.hTotal; + modeInfo->hSkew = mode->mode.hSkew; + modeInfo->vSyncStart = mode->mode.vSyncStart; + modeInfo->vSyncEnd = mode->mode.vSyncEnd; + modeInfo->vTotal = mode->mode.vTotal; + modeInfo->modeFlags = mode->mode.modeFlags; + + XLIB_PROLOGUE (dmxScreen); + m = XRRCreateMode (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay), + modeInfo); + XLIB_EPILOGUE (dmxScreen); + + if (!m) + return FALSE; + + XRRFreeModeInfo (modeInfo); + + XLIB_PROLOGUE (dmxScreen); + XRRAddOutputMode (dmxScreen->beDisplay, + (unsigned long) output->devPrivate, m); + XLIB_EPILOGUE (dmxScreen); + + return TRUE; +} + +static void +dmxRRModeDestroy (ScreenPtr pScreen, + RRModePtr mode) +{ + XRRScreenResources *r; + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beRandr) + continue; + + if (dmxScreen->beRandrPending) + continue; + + r = NULL; + + XLIB_PROLOGUE (dmxScreen); + r = XRRGetScreenResources (dmxScreen->beDisplay, dmxScreen->scrnWin); + XLIB_EPILOGUE (dmxScreen); + + if (r) + { + +#ifdef _XSERVER64 + RRMode64 m; +#else + RRMode m; +#endif + + m = dmxRRGetXMode (r, mode); + if (m) + { + XLIB_PROLOGUE (dmxScreen); + XRRDestroyMode (dmxScreen->beDisplay, m); + XLIB_EPILOGUE (dmxScreen); + } + + XRRFreeScreenResources (r); + } + } +} + +Bool +dmxScreenEventCheckRR (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + switch (event->response_type & ~0x80) { + case XCB_MAP_NOTIFY: + if (((xcb_map_notify_event_t *) event)->window == dmxScreen->rootWin) + return TRUE; + + return FALSE; + case XCB_CONFIGURE_NOTIFY: { + xcb_configure_notify_event_t *xconfigure = + (xcb_configure_notify_event_t *) event; + XEvent X; + + if (xconfigure->window == dmxScreen->scrnWin) + { + if (dmxScreen->scrnWidth == xconfigure->width && + dmxScreen->scrnHeight == xconfigure->height) + return TRUE; + + dmxScreen->scrnWidth = xconfigure->width; + dmxScreen->scrnHeight = xconfigure->height; + } + else if (xconfigure->window == dmxScreen->rootWin) + { + if (dmxScreen->rootX == xconfigure->x && + dmxScreen->rootY == xconfigure->y) + return TRUE; + + dmxScreen->rootX = xconfigure->x; + dmxScreen->rootY = xconfigure->y; + } + else + { + return FALSE; + } + + X.xconfigure.type = XCB_CONFIGURE_NOTIFY; + X.xconfigure.display = dmxScreen->beDisplay; + X.xconfigure.window = xconfigure->window; + X.xconfigure.width = xconfigure->width; + X.xconfigure.height = xconfigure->height; + + XRRUpdateConfiguration (&X); + } break; + default: + if (!dmxScreen->beRandr) + return FALSE; + + switch ((event->response_type & ~0x80) - dmxScreen->beRandrEventBase) { + case XCB_RANDR_SCREEN_CHANGE_NOTIFY: { + xcb_randr_screen_change_notify_event_t *scevent = + (xcb_randr_screen_change_notify_event_t *) event; + XRRScreenChangeNotifyEvent X; + + X.type = event->response_type; + X.display = dmxScreen->beDisplay; + X.root = scevent->root; + X.width = scevent->width; + X.mwidth = scevent->mwidth; + X.height = scevent->height; + X.mheight = scevent->mheight; + X.rotation = scevent->rotation; + X.subpixel_order = scevent->subpixel_order; + + XRRUpdateConfiguration ((XEvent *) &X); + } break; + case XCB_RANDR_NOTIFY: + break; + default: + return FALSE; + } + } + + dmxScreen->beWidth = + DisplayWidth (dmxScreen->beDisplay, + DefaultScreen (dmxScreen->beDisplay)); + dmxScreen->beHeight = + DisplayHeight (dmxScreen->beDisplay, + DefaultScreen (dmxScreen->beDisplay)); + + /* only call RRGetInfo when server is fully initialized */ + if (dmxScreens[0].inputOverlayWid) + RRGetInfo (screenInfo.screens[0]); + + return TRUE; +} + +Bool +dmxRRScreenInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv (pScreen); + pScrPriv->rrGetInfo = dmxRRGetInfo; + pScrPriv->rrScreenSetSize = dmxRRScreenSetSize; + pScrPriv->rrCrtcSet = dmxRRCrtcSet; + pScrPriv->rrCrtcSetGamma = dmxRRCrtcSetGamma; + pScrPriv->rrOutputSetProperty = dmxRROutputSetProperty; + pScrPriv->rrOutputValidateMode = dmxRROutputValidateMode; + pScrPriv->rrModeDestroy = dmxRRModeDestroy; + + RRScreenSetSizeRange (pScreen, 1, 1, SHRT_MAX, SHRT_MAX); + + if (pScreen->myNum) + { + char name[64]; + int i; + + for (i = 0; i < xRROutputsPerScreen; i++) + { + sprintf (name, + "dmx%d", + (pScreen->myNum - 1) * xRROutputsPerScreen + i); + + if (!RROutputCreate (screenInfo.screens[0], + name, + strlen (name), + NULL)) + return FALSE; + } + + for (i = 0; i < xRRCrtcsPerScreen; i++) + if (!RRCrtcCreate (screenInfo.screens[0], NULL)) + return FALSE; + } + else + { + XRRScreenResources *r = NULL; + DMXScreenInfo *dmxScreen = dmxScreens; + Display *display = dmxScreen->beDisplay; + Bool beRandr = FALSE; + + if (display && dmxScreen->scrnWin == DefaultRootWindow (display)) + { + int major, minor, status = 0; + + XLIB_PROLOGUE (dmxScreen); + status = XRRQueryVersion (display, &major, &minor); + XLIB_EPILOGUE (dmxScreen); + + if (status) + { + if (major > 1 || (major == 1 && minor >= 2)) + { + int ignore; + + XLIB_PROLOGUE (dmxScreen); + beRandr = XRRQueryExtension (display, &ignore, &ignore); + XLIB_EPILOGUE (dmxScreen); + } + } + } + + if (display && beRandr) + { + XLIB_PROLOGUE (dmxScreen); + r = XRRGetScreenResources (display, DefaultRootWindow (display)); + XLIB_EPILOGUE (dmxScreen); + } + + if (r) + { + int i; + + xRROutputsForFirstScreen = r->noutput; + xRRCrtcsForFirstScreen = r->ncrtc; + + for (i = 0; i < r->noutput; i++) + { + XRROutputInfo *o; + + o = XRRGetOutputInfo (display, r, r->outputs[i]); + if (!o) + return FALSE; + + if (!RROutputCreate (screenInfo.screens[0], + o->name, strlen (o->name), + NULL)) + return FALSE; + } + + for (i = 0; i < r->ncrtc; i++) + if (!RRCrtcCreate (screenInfo.screens[0], NULL)) + return FALSE; + + XRRFreeScreenResources (r); + } + else + { + if (!RROutputCreate (screenInfo.screens[0], "default", 7, NULL)) + return FALSE; + + if (!RRCrtcCreate (screenInfo.screens[0], NULL)) + return FALSE; + } + } + + return TRUE; +} + +Bool +dmxBERRScreenInit (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxScreen->beRandr = FALSE; + + if (dmxScreen->scrnWin == DefaultRootWindow (dmxScreen->beDisplay)) + { + int major, minor, status = 0; + + XLIB_PROLOGUE (dmxScreen); + status = XRRQueryVersion (dmxScreen->beDisplay, &major, &minor); + XLIB_EPILOGUE (dmxScreen); + + if (status) + { + if (major > 1 || (major == 1 && minor >= 2)) + { + int ignore; + + XLIB_PROLOGUE (dmxScreen); + dmxScreen->beRandr = + XRRQueryExtension (dmxScreen->beDisplay, + &dmxScreen->beRandrEventBase, + &ignore); + XLIB_EPILOGUE (dmxScreen); + + dmxLog (dmxInfo, "RandR 1.2 is present\n"); + } + else + { + dmxLog (dmxInfo, "RandR 1.2 is not present\n"); + } + } + else + { + dmxLog (dmxInfo, "RandR extension missing\n"); + } + } + + if (!dmxScreen->beRandr) + return FALSE; + + XLIB_PROLOGUE (dmxScreen); + XRRSelectInput (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay), + RRScreenChangeNotifyMask | + RRCrtcChangeNotifyMask | + RROutputChangeNotifyMask | + RROutputPropertyNotifyMask); + XLIB_EPILOGUE (dmxScreen); + + return TRUE; +} + +void +dmxBERRScreenFini (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->beRandr) + { + XLIB_PROLOGUE (dmxScreen); + XRRSelectInput (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay), + 0); + XLIB_EPILOGUE (dmxScreen); + } +} + + +#endif diff --git a/hw/dmx/dmxrandr.h b/hw/dmx/dmxrandr.h new file mode 100644 index 0000000..0f6822b --- /dev/null +++ b/hw/dmx/dmxrandr.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXRANDR_H +#define DMXRANDR_H + +#include "dmxscrinit.h" +#include "randrstr.h" + +extern Bool dmxRRScreenInit (ScreenPtr pScreen); +extern Bool dmxScreenEventCheckRR (ScreenPtr pScreen, + xcb_generic_event_t *event); +extern Bool dmxBERRScreenInit (ScreenPtr pScreen); +extern void dmxBERRScreenFini (ScreenPtr pScreen); + +#endif /* DMXRANDR_H */ diff --git a/hw/dmx/dmxscrinit.c b/hw/dmx/dmxscrinit.c index 0e49e96..53ae6ab 100644 --- a/hw/dmx/dmxscrinit.c +++ b/hw/dmx/dmxscrinit.c @@ -40,8 +40,8 @@ #endif #include "dmx.h" +#include "dmxextension.h" #include "dmxsync.h" -#include "dmxshadow.h" #include "dmxscrinit.h" #include "dmxcursor.h" #include "dmxgc.h" @@ -52,14 +52,41 @@ #include "dmxcmap.h" #include "dmxprop.h" #include "dmxdpms.h" +#include "dmxlog.h" +#include "dmxcb.h" +#include "dmxinit.h" +#include "dmxgrab.h" +#include "dmxselection.h" +#include "dmxatom.h" +#include "dmxshm.h" +#include "dmxdnd.h" +#include "dmxlaunch.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif #ifdef RENDER #include "dmxpict.h" #endif +#ifdef COMPOSITE +#include "dmxcomp.h" +#endif + +#ifdef RANDR +#include "dmxrandr.h" +#endif + +#ifdef XV +#include "dmxxv.h" +#endif + #include "fb.h" #include "mipointer.h" #include "micmap.h" +#include "mivalidate.h" extern Bool dmxCloseScreen(int idx, ScreenPtr pScreen); static Bool dmxSaveScreen(ScreenPtr pScreen, int what); @@ -73,20 +100,20 @@ DevPrivateKey dmxPixPrivateKey = &dmxPixPrivateKey; /**< Private index for Pixma int dmxFontPrivateIndex; /**< Private index for Fonts */ DevPrivateKey dmxScreenPrivateKey = &dmxScreenPrivateKey; /**< Private index for Screens */ DevPrivateKey dmxColormapPrivateKey = &dmxColormapPrivateKey; /**< Private index for Colormaps */ +DevPrivateKey dmxDevicePrivateKey = &dmxDevicePrivateKey; /**< Private index for Devices */ #ifdef RENDER DevPrivateKey dmxPictPrivateKey = &dmxPictPrivateKey; /**< Private index for Picts */ DevPrivateKey dmxGlyphSetPrivateKey = &dmxGlyphSetPrivateKey; /**< Private index for GlyphSets */ +DevPrivateKey dmxGlyphPrivateKey = &dmxGlyphPrivateKey; /**< Private index for Glyphs */ #endif /** Initialize the parts of screen \a idx that require access to the * back-end server. */ -void dmxBEScreenInit(int idx, ScreenPtr pScreen) +void dmxBEScreenInit(ScreenPtr pScreen) { - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - XSetWindowAttributes attribs; - XGCValues gcvals; - unsigned long mask; - int i, j; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + char buf[256]; + int i, j; /* FIXME: The dmxScreenInit() code currently assumes that it will * not be called if the Xdmx server is started with this screen @@ -105,99 +132,873 @@ void dmxBEScreenInit(int idx, ScreenPtr pScreen) pScreen->whitePixel = dmxScreen->beWhitePixel; pScreen->blackPixel = dmxScreen->beBlackPixel; - /* Handle screen savers and DPMS on the backend */ - dmxDPMSInit(dmxScreen); - - /* Create root window for screen */ - mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; - attribs.background_pixel = dmxScreen->beBlackPixel; - attribs.event_mask = (KeyPressMask - | KeyReleaseMask - | ButtonPressMask - | ButtonReleaseMask - | EnterWindowMask - | LeaveWindowMask - | PointerMotionMask - | KeymapStateMask - | FocusChangeMask); - attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex]; - attribs.override_redirect = True; + dmxScreen->selectionOwner = None; + + sprintf(buf, "DMX_%s", dmxDigest); + + /* prefetch all valid atoms */ + for (i = 1; ValidAtom ((Atom) i); i++); + while (--i) + dmxBEPrefetchAtom (dmxScreen, (Atom) i); - dmxScreen->scrnWin = - XCreateWindow(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - dmxScreen->scrnX, - dmxScreen->scrnY, - dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - 0, - pScreen->rootDepth, - InputOutput, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - mask, - &attribs); - dmxPropertyWindow(dmxScreen); + XLIB_PROLOGUE (dmxScreen); + dmxScreen->beSelectionAtom = XInternAtom (dmxScreen->beDisplay, buf, 0); + XLIB_EPILOGUE (dmxScreen); - /* - * This turns off the cursor by defining a cursor with no visible - * components. - */ + /* Handle screen savers and DPMS on the backend */ + dmxBEDPMSScreenInit (pScreen); + +#ifdef MITSHM + dmxBEShmScreenInit (pScreen); +#endif + +#ifdef RANDR + dmxBERRScreenInit (pScreen); +#endif + +#ifdef XV + dmxBEXvScreenInit (pScreen); +#endif + + /* Create default drawables (used during GC creation) */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) + for (j = 0; j < dmxScreen->beNumDepths; j++) + if ((dmxScreen->bePixmapFormats[i].depth == 1) || + (dmxScreen->bePixmapFormats[i].depth == + dmxScreen->beDepths[j])) { + XLIB_PROLOGUE (dmxScreen); + dmxScreen->scrnDefDrawables[i] = (Drawable) + XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + 1, 1, dmxScreen->bePixmapFormats[i].depth); + XLIB_EPILOGUE (dmxScreen); + break; + } +} + +static void +dmxSetWindowPixmap (WindowPtr pWin, PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); + + if (pPixmap != pOld) { - char noCursorData[] = {0, 0, 0, 0, - 0, 0, 0, 0}; - Pixmap pixmap; - XColor color, tmp; - - pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin, - noCursorData, 8, 8); - XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0], - "black", &color, &tmp); - dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay, - pixmap, pixmap, - &color, &color, 0, 0); - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - - XFreePixmap(dmxScreen->beDisplay, pixmap); + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + + if (pPixmap && (*pScreen->GetWindowPixmap) (pWin->parent) != pPixmap) + pWinPriv->redirected = TRUE; + else + pWinPriv->redirected = FALSE; } - XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - - if (dmxShadowFB) { - mask = (GCFunction - | GCPlaneMask - | GCClipMask); - gcvals.function = GXcopy; - gcvals.plane_mask = AllPlanes; - gcvals.clip_mask = None; - - dmxScreen->shadowGC = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnWin, - mask, &gcvals); - - dmxScreen->shadowFBImage = - XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - dmxScreen->beDepth, - ZPixmap, - 0, - (char *)dmxScreen->shadow, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->beBPP, - PixmapBytePad(dmxScreen->scrnWidth, - dmxScreen->beBPP)); - } else { - /* Create default drawables (used during GC creation) */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) - for (j = 0; j < dmxScreen->beNumDepths; j++) - if ((dmxScreen->bePixmapFormats[i].depth == 1) || - (dmxScreen->bePixmapFormats[i].depth == - dmxScreen->beDepths[j])) { - dmxScreen->scrnDefDrawables[i] = (Drawable) - XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - 1, 1, dmxScreen->bePixmapFormats[i].depth); - break; + DMX_UNWRAP(SetWindowPixmap, dmxScreen, pScreen); + if (pScreen->SetWindowPixmap) + (*pScreen->SetWindowPixmap) (pWin, pPixmap); + DMX_WRAP(SetWindowPixmap, dmxSetWindowPixmap, dmxScreen, pScreen); +} + +static Bool +dmxScreenEventCheckInput (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + return dmxInputEventCheck (&dmxScreen->input, event); +} + +static void +dmxScreenGetSelectionOwner (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxScreen->selectionOwner = None; + while (dmxScreen->selectionOwner == None) + { + xcb_connection_t *c = dmxScreen->connection; + xcb_atom_t a = dmxScreen->beSelectionAtom; + xcb_get_selection_owner_reply_t *reply; + + reply = xcb_get_selection_owner_reply (c, + xcb_get_selection_owner (c, a), + NULL); + if (!reply) + break; + + if (reply->owner) + { + if (reply->owner != dmxScreen->rootWin) + { + const uint32_t value = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + xcb_void_cookie_t r; + xcb_generic_error_t *error; + + r = xcb_change_window_attributes_checked (c, + reply->owner, + XCB_CW_EVENT_MASK, + &value); + error = xcb_request_check (c, r); + if (error) + { + if (error->error_code != BadWindow) + dmxScreen->selectionOwner = reply->owner; + + free (error); + } + else + { + dmxScreen->selectionOwner = reply->owner; } + } + else + { + dmxScreen->selectionOwner = dmxScreen->rootWin; + } + } + else + { + xcb_set_selection_owner (dmxScreen->connection, + dmxScreen->rootWin, + dmxScreen->beSelectionAtom, + 0); + } + + free (reply); + } +} + +static Bool +dmxScreenEventCheckSelection (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + switch (event->response_type & ~0x80) { + case XCB_DESTROY_NOTIFY: { + xcb_destroy_notify_event_t *xdestroy = + (xcb_destroy_notify_event_t *) event; + + if (dmxSelectionDestroyNotify (pScreen, xdestroy->window)) + return TRUE; + + if (xdestroy->window != dmxScreen->selectionOwner) + return FALSE; + + if (dmxScreen->selectionOwner == dmxScreen->rootWin) + return FALSE; + + dmxScreenGetSelectionOwner (pScreen); + } break; + case XCB_PROPERTY_NOTIFY: { + xcb_property_notify_event_t *xproperty = + (xcb_property_notify_event_t *) event; + + if (!dmxSelectionPropertyNotify (pScreen, + xproperty->window, + xproperty->state, + xproperty->atom, + xproperty->time)) + return FALSE; + } break; + case XCB_SELECTION_CLEAR: { + xcb_selection_clear_event_t *xclear = + (xcb_selection_clear_event_t *) event; + + if (xclear->selection == dmxScreen->beSelectionAtom) + { + dmxScreenGetSelectionOwner (pScreen); + } + else + { + dmxSelectionClear (pScreen, + xclear->owner, + xclear->selection); + } + } break; + case XCB_SELECTION_NOTIFY: { + xcb_selection_notify_event_t *xnotify = + (xcb_selection_notify_event_t *) event; + + dmxSelectionNotify (pScreen, + xnotify->requestor, + xnotify->selection, + xnotify->target, + xnotify->property, + xnotify->time); + } break; + case XCB_SELECTION_REQUEST: { + xcb_selection_request_event_t *xrequest = + (xcb_selection_request_event_t *) event; + + dmxSelectionRequest (pScreen, + xrequest->owner, + xrequest->requestor, + xrequest->selection, + xrequest->target, + xrequest->property, + xrequest->time); + } break; + default: + return FALSE; + } + + return TRUE; +} + +static void +dmxDiscardIgnore (DMXScreenInfo *dmxScreen, + unsigned long sequence) +{ + while (dmxScreen->ignore.head) + { + if ((long) (sequence - dmxScreen->ignore.head->sequence) > 0) + { + DMXSequence *next = dmxScreen->ignore.head->next; + + free (dmxScreen->ignore.head); + + dmxScreen->ignore.head = next; + if (!dmxScreen->ignore.head) + dmxScreen->ignore.tail = &dmxScreen->ignore.head; + } + else + break; + } +} + +static Bool +dmxShouldIgnore (DMXScreenInfo *dmxScreen, + unsigned long sequence) +{ + dmxDiscardIgnore (dmxScreen, sequence); + + if (!dmxScreen->ignore.head) + return FALSE; + + return dmxScreen->ignore.head->sequence == sequence; +} + +static Bool +dmxScreenEventCheckExpose (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_expose_event_t *xexpose = (xcb_expose_event_t *) event; + WindowPtr pChild0, pChildN; + + if ((event->response_type & ~0x80) != XCB_EXPOSE) + return FALSE; + + if (dmxShouldIgnore (dmxScreen, xexpose->sequence)) + return TRUE; + + pChild0 = WindowTable[0]; + pChildN = WindowTable[pScreen->myNum]; + + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pChildN); + + if (pWinPriv->window == xexpose->window) + break; + + if (pChild0->firstChild) + { + assert (pChildN->firstChild); + pChild0 = pChild0->firstChild; + pChildN = pChildN->firstChild; + continue; + } + + while (!pChild0->nextSib && (pChild0 != WindowTable[0])) + { + assert (!pChildN->nextSib && + (pChildN != WindowTable[pScreen->myNum])); + pChild0 = pChild0->parent; + pChildN = pChildN->parent; + } + + if (pChild0 == WindowTable[0]) + { + assert (pChildN == WindowTable[pScreen->myNum]); + break; + } + + pChild0 = pChild0->nextSib; + pChildN = pChildN->nextSib; + } + + if (pChild0) + { + RegionRec region; + BoxRec box; + + box.x1 = pChild0->drawable.x + xexpose->x; + box.y1 = pChild0->drawable.y + xexpose->y; + box.x2 = box.x1 + xexpose->width; + box.y2 = box.y1 + xexpose->height; + + REGION_INIT (screenInfo.screens[0], ®ion, &box, 1); + (*pScreen->WindowExposures) (pChild0, ®ion, NullRegion); + REGION_UNINIT (screenInfo.screens[0], ®ion); + } + + return TRUE; +} + +static Bool +dmxScreenEventCheckOutputWindow (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + switch (event->response_type & ~0x80) { + case XCB_DESTROY_NOTIFY: { + xcb_destroy_notify_event_t *xdestroy = + (xcb_destroy_notify_event_t *) event; + + if (xdestroy->window != dmxScreen->scrnWin) + return FALSE; + + /* output window has been destroyed, detach screen when we reach + the block handler */ + dmxScreen->scrnWin = None; + return TRUE; + } break; + case XCB_MAP_NOTIFY: { + xcb_map_notify_event_t *xmap = (xcb_map_notify_event_t *) event; + + if (xmap->window == dmxScreen->scrnWin) + return TRUE; + } break; + default: + break; + } + + return FALSE; +} + +static Bool +dmxScreenEventCheckManageRoot (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pChild = WindowTable[pScreen->myNum]; + Window xWindow; + +#ifdef PANORAMIX + PanoramiXRes *win = NULL; + WindowPtr pWin; +#endif + + xcb_circulate_request_event_t *xcirculaterequest = + (xcb_circulate_request_event_t *) event; + xcb_configure_request_event_t *xconfigurerequest = + (xcb_configure_request_event_t *) event; + xcb_map_request_event_t *xmaprequest = + (xcb_map_request_event_t *) event; + xcb_client_message_event_t *xclient = + (xcb_client_message_event_t *) event; + xcb_map_notify_event_t *xmap = + (xcb_map_notify_event_t *) event; + + switch (event->response_type & ~0x80) { + case XCB_CIRCULATE_REQUEST: + xWindow = xcirculaterequest->window; + break; + case XCB_CONFIGURE_REQUEST: + xWindow = xconfigurerequest->window; + break; + case XCB_MAP_REQUEST: + xWindow = xmaprequest->window; + break; + case XCB_CLIENT_MESSAGE: + xWindow = xclient->window; + break; + case XCB_MAP_NOTIFY: + if (xmap->window == dmxScreen->rootWin) + { + dmxScreenGetSelectionOwner (pScreen); + return TRUE; + } + + /* fall-through */ + default: + return FALSE; + } + + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pChild); + + if (pWinPriv->window == xWindow) + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + win = PanoramiXFindIDByScrnum (XRT_WINDOW, + pChild->drawable.id, + pScreen->myNum); +#endif + + break; + } + + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + + while (!pChild->nextSib && + (pChild != WindowTable[pScreen->myNum])) + pChild = pChild->parent; + + if (pChild == WindowTable[pScreen->myNum]) + break; + + pChild = pChild->nextSib; + } + + if (pChild + +#ifdef PANORAMIX + && win +#endif + + ) + { + XID vlist[8]; + Atom type; + int mask, i = 0; + int status = Success; + xEvent x; + + switch (event->response_type & ~0x80) { + case XCB_CIRCULATE_REQUEST: + vlist[0] = None; + + if (xcirculaterequest->place == XCB_PLACE_ON_TOP) + vlist[1] = Above; + else + vlist[1] = Below; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int j; + + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + status |= ConfigureWindow (pWin, + CWSibling | + CWStackMode, + vlist, + serverClient); + } + } + else +#endif + status = ConfigureWindow (pChild, + CWSibling | CWStackMode, + vlist, + serverClient); + break; + case XCB_CONFIGURE_REQUEST: + mask = xconfigurerequest->value_mask; + + if (mask & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y)) + { + vlist[i++] = xconfigurerequest->x; + vlist[i++] = xconfigurerequest->y; + } + + if (mask & (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT)) + { + vlist[i++] = xconfigurerequest->width; + vlist[i++] = xconfigurerequest->height; + } + + if (mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) + vlist[i++] = xconfigurerequest->border_width; + + if (mask & XCB_CONFIG_WINDOW_SIBLING) + { + /* ignore stacking requests with sibling */ + if (xconfigurerequest->sibling == None) + vlist[i++] = None; + else + mask &= ~(XCB_CONFIG_WINDOW_SIBLING | + XCB_CONFIG_WINDOW_STACK_MODE); + } + + if (mask & XCB_CONFIG_WINDOW_STACK_MODE) + vlist[i++] = xconfigurerequest->stack_mode; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int j; + + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + status |= ConfigureWindow (pWin, + mask, + vlist, + serverClient); + } + } + else +#endif + + status = ConfigureWindow (pChild, + mask, + vlist, + serverClient); + break; + case XCB_MAP_REQUEST: + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + int j; + + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + status |= MapWindow (pWin, serverClient); + } + } + else +#endif + + status = MapWindow (pChild, serverClient); + break; + case XCB_CLIENT_MESSAGE: + x.u.u.type = ClientMessage | 0x80; + x.u.u.detail = xclient->format; + x.u.clientMessage.window = pChild->drawable.id; + + type = dmxAtom (dmxScreen, xclient->type); + + switch (xclient->format) { + case 8: + x.u.clientMessage.u.b.type = type; + + for (i = 0; i < 20; i++) + x.u.clientMessage.u.b.bytes[i] = xclient->data.data8[i]; + break; + case 16: + x.u.clientMessage.u.s.type = type; + + x.u.clientMessage.u.s.shorts0 = xclient->data.data16[0]; + x.u.clientMessage.u.s.shorts1 = xclient->data.data16[1]; + x.u.clientMessage.u.s.shorts2 = xclient->data.data16[2]; + x.u.clientMessage.u.s.shorts3 = xclient->data.data16[3]; + x.u.clientMessage.u.s.shorts4 = xclient->data.data16[4]; + x.u.clientMessage.u.s.shorts5 = xclient->data.data16[5]; + x.u.clientMessage.u.s.shorts6 = xclient->data.data16[6]; + x.u.clientMessage.u.s.shorts7 = xclient->data.data16[7]; + x.u.clientMessage.u.s.shorts8 = xclient->data.data16[8]; + x.u.clientMessage.u.s.shorts9 = xclient->data.data16[9]; + break; + case 32: + x.u.clientMessage.u.l.type = type; + + x.u.clientMessage.u.l.longs0 = xclient->data.data32[0]; + x.u.clientMessage.u.l.longs1 = xclient->data.data32[1]; + x.u.clientMessage.u.l.longs2 = xclient->data.data32[2]; + x.u.clientMessage.u.l.longs3 = xclient->data.data32[3]; + x.u.clientMessage.u.l.longs4 = xclient->data.data32[4]; + break; + } + + /* client messages are always forwarded to the root + window as there's no way for us to know which + windows they were originally intended for */ + pWin = WindowTable[pScreen->myNum]; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + x.u.clientMessage.window = win->info[0].id; + pWin = WindowTable[0]; + } +#endif + + DeliverEventsToWindow (PickPointer (serverClient), + pWin, + &x, + 1, + SubstructureRedirectMask | + SubstructureNotifyMask, + NullGrab, 0); + break; + } + + if (status != Success) + dmxLog (dmxWarning, + "dmxScreenManage: failed to handle " + "request type %d\n", + event->response_type & ~0x80); + } + else + { + XWindowChanges xwc; + + switch (event->response_type & ~0x80) { + case XCB_CIRCULATE_REQUEST: + XLIB_PROLOGUE (dmxScreen); + if (xcirculaterequest->place == XCB_PLACE_ON_TOP) + XRaiseWindow (dmxScreen->beDisplay, + xcirculaterequest->window); + else + XLowerWindow (dmxScreen->beDisplay, + xcirculaterequest->window); + XLIB_EPILOGUE (dmxScreen); + break; + case XCB_CONFIGURE_REQUEST: + xwc.x = xconfigurerequest->x; + xwc.y = xconfigurerequest->y; + xwc.width = xconfigurerequest->width; + xwc.height = xconfigurerequest->height; + xwc.border_width = xconfigurerequest->border_width; + xwc.sibling = xconfigurerequest->sibling; + xwc.stack_mode = xconfigurerequest->stack_mode; + + XLIB_PROLOGUE (dmxScreen); + XConfigureWindow (dmxScreen->beDisplay, + xconfigurerequest->window, + xconfigurerequest->value_mask, + &xwc); + XLIB_EPILOGUE (dmxScreen); + break; + case XCB_MAP_REQUEST: + XLIB_PROLOGUE (dmxScreen); + XMapWindow (dmxScreen->beDisplay, xmaprequest->window); + XLIB_EPILOGUE (dmxScreen); + break; + case XCB_CLIENT_MESSAGE: + break; + } + } + + return TRUE; +} + +static Bool +dmxScreenEventCheckIgnore (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + switch (event->response_type & ~0x80) { + case XCB_MAPPING_NOTIFY: + return TRUE; + default: + break; + } + + return FALSE; +} + +void +dmxBEDispatch (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_generic_event_t *event; + xcb_generic_error_t *error; + void *reply; + + assert (dmxScreen->inDispatch == FALSE); + dmxScreen->inDispatch = TRUE; + + while ((event = xcb_poll_for_event (dmxScreen->connection))) + { + if (!dmxScreenEventCheckInput (pScreen, event) && + !dmxScreenEventCheckSelection (pScreen, event) && + !dmxScreenEventCheckDnD (pScreen, event) && + !dmxScreenEventCheckOutputWindow (pScreen, event) && + !dmxScreenEventCheckManageRoot (pScreen, event) && + !dmxScreenEventCheckExpose (pScreen, event) && + +#ifdef MITSHM + !dmxScreenEventCheckShm (pScreen, event) && +#endif + +#ifdef RANDR + !dmxScreenEventCheckRR (pScreen, event) && +#endif + + !dmxScreenEventCheckIgnore (pScreen, event)) + { + if (event->response_type == 0) + { + xcb_generic_error_t *error = (xcb_generic_error_t *) event; + + dmxLogOutput (dmxScreen, "unhandled error type %d\n", + error->error_code); + } + else + { + dmxLogOutput (dmxScreen, "unhandled event type %d\n", + event->response_type); + } + } + + free (event); + } + + while (dmxScreen->request.head && + xcb_poll_for_reply (dmxScreen->connection, + dmxScreen->request.head->sequence, + (void **) &reply, + &error)) + { + DMXRequest *head = (DMXRequest *) dmxScreen->request.head; + + dmxScreen->request.head = head->base.next; + if (!dmxScreen->request.head) + dmxScreen->request.tail = &dmxScreen->request.head; + + (*head->reply) (pScreen, + head->base.sequence, + reply, + error, + head->data); + + if (reply) + free (reply); + if (error) + free (error); + + free (head); + } + + if (!dmxScreen->scrnWin || + xcb_connection_has_error (dmxScreen->connection)) + { + static xcb_generic_error_t detached_error = { 0, DMX_DETACHED }; + + while (dmxScreen->request.head) + { + DMXRequest *head = (DMXRequest *) dmxScreen->request.head; + + dmxScreen->request.head = head->base.next; + if (!dmxScreen->request.head) + dmxScreen->request.tail = &dmxScreen->request.head; + + (*head->reply) (pScreen, + head->base.sequence, + NULL, + &detached_error, + head->data); + + free (head); + } + + dmxScreen->broken = TRUE; + } + + dmxScreen->inDispatch = FALSE; +} + +static void +dmxScreenCheckForIOError (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (!dmxScreen->scrnWin || + xcb_connection_has_error (dmxScreen->connection)) + { + int i; + + if (dmxScreen->scrnWin) + { + dmxLogOutput (dmxScreen, "Detected broken connection\n"); + dmxScreen->alive = FALSE; + } + + if (!dmxScreen->broken) + dmxBEDispatch (pScreen); + + dmxDetachScreen (pScreen->myNum); + + for (i = 0; i < dmxNumScreens; i++) + if (i != pScreen->myNum && dmxScreens[i].beDisplay) + break; + + if (i == dmxNumScreens) + dmxLog (dmxFatal, "No back-end server connection, " + "giving up\n"); + } +} + +static void +dmxScreenBlockHandler (pointer blockData, + OSTimePtr pTimeout, + pointer pReadMask) +{ + ScreenPtr pScreen = (ScreenPtr) blockData; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->alive) + { + xcb_flush (dmxScreen->connection); + dmxScreenCheckForIOError (pScreen); + } +} + +static void +dmxScreenWakeupHandler (pointer blockData, + int result, + pointer pReadMask) +{ + ScreenPtr pScreen = (ScreenPtr) blockData; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->alive) + dmxBEDispatch (pScreen); +} + +static void +dmxHandleExposures (WindowPtr pWin) +{ + WindowPtr pChild; + ValidatePtr val; + ScreenPtr pScreen; + WindowExposuresProcPtr WindowExposures; + + pScreen = pWin->drawable.pScreen; + + pChild = pWin; + WindowExposures = pChild->drawable.pScreen->WindowExposures; + while (1) + { + if ( (val = pChild->valdata) ) + { + REGION_UNINIT(pScreen, &val->after.borderExposed); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + REGION_UNINIT(pScreen, &val->after.exposed); + xfree(val); + pChild->valdata = (ValidatePtr)NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; } } @@ -216,15 +1017,27 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) dmxGeneration = serverGeneration; } - if (dmxShadowFB) { - dmxScreen->shadow = shadowAlloc(dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - dmxScreen->beBPP); - } else { - if (!dmxInitGC(pScreen)) return FALSE; - if (!dmxInitWindow(pScreen)) return FALSE; - if (!dmxInitPixmap(pScreen)) return FALSE; - } + dmxInputInit (&dmxScreen->input); + + dmxScreen->ignore.head = NULL; + dmxScreen->ignore.tail = &dmxScreen->ignore.head; + + dmxScreen->request.head = NULL; + dmxScreen->request.tail = &dmxScreen->request.head; + + dmxScreen->scrnEventMask = 0; + + dmxScreen->rootEventMask = ExposureMask | StructureNotifyMask | + SubstructureRedirectMask; + + dmxScreen->multipleAtom = MakeAtom ("MULTIPLE", strlen ("MULTIPLE"), TRUE); + dmxScreen->atomPairAtom = MakeAtom ("ATOM_PAIR", strlen ("ATOM_PAIR"), TRUE); + dmxScreen->incrAtom = MakeAtom ("INCR", strlen ("INCR"), TRUE); + + if (!dmxInitGC(pScreen)) return FALSE; + if (!dmxInitWindow(pScreen)) return FALSE; + if (!dmxInitPixmap(pScreen)) return FALSE; + if (!dmxInitCursor(pScreen)) return FALSE; /* * Initalise the visual types. miSetVisualTypesAndMasks() requires @@ -233,120 +1046,213 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) * Maybe a miAddVisualTypeAndMask() function will be added to make * things easier here. */ - for (i = 0; i < dmxScreen->beNumDepths; i++) { - int depth; - int visuals = 0; - int bitsPerRgb = 0; - int preferredClass = -1; - Pixel redMask = 0; - Pixel greenMask = 0; - Pixel blueMask = 0; - - depth = dmxScreen->beDepths[i]; - for (j = 0; j < dmxScreen->beNumVisuals; j++) { - XVisualInfo *vi; - - vi = &dmxScreen->beVisuals[j]; - if (vi->depth == depth) { - /* Assume the masks are all the same. */ - visuals |= (1 << vi->class); - bitsPerRgb = vi->bits_per_rgb; - redMask = vi->red_mask; - greenMask = vi->green_mask; - blueMask = vi->blue_mask; - if (j == dmxScreen->beDefVisualIndex) { - preferredClass = vi->class; + if (dmxScreen->beAttachedDisplay) + { + for (i = 0; i < dmxScreen->beNumDepths; i++) { + int depth; + int visuals = 0; + int bitsPerRgb = 0; + int preferredClass = -1; + Pixel redMask = 0; + Pixel greenMask = 0; + Pixel blueMask = 0; + + depth = dmxScreen->beDepths[i]; + for (j = 0; j < dmxScreen->beNumVisuals; j++) { + XVisualInfo *vi; + + vi = &dmxScreen->beVisuals[j]; + if (vi->depth == depth) { + /* Assume the masks are all the same. */ + visuals |= (1 << vi->class); + bitsPerRgb = vi->bits_per_rgb; + redMask = vi->red_mask; + greenMask = vi->green_mask; + blueMask = vi->blue_mask; + if (j == dmxScreen->beDefVisualIndex) { + preferredClass = vi->class; + } } } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* avoid additional DirectColor visuals for better + back-end server support */ + if (preferredClass != DirectColor) + visuals &= ~(1 << DirectColor); + } +#endif + + miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, + preferredClass, + redMask, greenMask, blueMask); + } + } + else + { + for (i = 0; i < dmxScreens[0].beNumDepths; i++) { + int depth; + int visuals = 0; + int bitsPerRgb = 0; + int preferredClass = -1; + Pixel redMask = 0; + Pixel greenMask = 0; + Pixel blueMask = 0; + + depth = dmxScreens[0].beDepths[i]; + for (j = 0; j < dmxScreens[0].beNumVisuals; j++) { + XVisualInfo *vi; + + vi = &dmxScreens[0].beVisuals[j]; + if (vi->depth == depth) { + /* Assume the masks are all the same. */ + visuals |= (1 << vi->class); + bitsPerRgb = vi->bits_per_rgb; + redMask = vi->red_mask; + greenMask = vi->green_mask; + blueMask = vi->blue_mask; + if (j == dmxScreens[0].beDefVisualIndex) { + preferredClass = vi->class; + } + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* avoid additional DirectColor visuals for better + back-end server support */ + if (preferredClass != DirectColor) + visuals &= ~(1 << DirectColor); + } +#endif + + miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, + preferredClass, + redMask, greenMask, blueMask); } - miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass, - redMask, greenMask, blueMask); } fbScreenInit(pScreen, - dmxShadowFB ? dmxScreen->shadow : NULL, + NULL, dmxScreen->scrnWidth, dmxScreen->scrnHeight, dmxScreen->beXDPI, - dmxScreen->beXDPI, + dmxScreen->beYDPI, dmxScreen->scrnWidth, dmxScreen->beBPP); + + if (!dmxScreen->scrnWin && dmxScreen->beDisplay) + { + dmxScreen->scrnWin = DefaultRootWindow (dmxScreen->beDisplay); + dmxScreen->scrnEventMask |= StructureNotifyMask; + XSelectInput (dmxScreen->beDisplay, + dmxScreen->scrnWin, + dmxScreen->scrnEventMask); + } + +#ifdef MITSHM + ShmRegisterDmxFuncs (pScreen); +#endif + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].ColormapEntries > 256) + pScreen->visuals[i].ColormapEntries = 256; + } +#endif + #ifdef RENDER - (void)dmxPictureInit(pScreen, 0, 0); + if (!dmxPictureInit (pScreen, 0, 0)) + return FALSE; #endif - if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL)) +#ifdef RANDR + if (!dmxRRScreenInit (pScreen)) + return FALSE; +#endif + +#ifdef XV + if (!dmxXvScreenInit (pScreen)) + return FALSE; +#endif + + if (!dmxDnDScreenInit (pScreen)) return FALSE; miInitializeBackingStore(pScreen); - if (dmxShadowFB) { - miDCInitialize(pScreen, &dmxPointerCursorFuncs); - } else { - MAXSCREENSALLOC(dmxCursorGeneration); - if (dmxCursorGeneration[idx] != serverGeneration) { - if (!(miPointerInitialize(pScreen, - &dmxPointerSpriteFuncs, - &dmxPointerCursorFuncs, - FALSE))) - return FALSE; - - dmxCursorGeneration[idx] = serverGeneration; - } + MAXSCREENSALLOC(dmxCursorGeneration); + if (dmxCursorGeneration[idx] != serverGeneration) { + if (!(miPointerInitialize(pScreen, + &dmxPointerSpriteFuncs, + &dmxPointerCursorFuncs, + FALSE))) + return FALSE; + + dmxCursorGeneration[idx] = serverGeneration; } DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen); DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen); - dmxBEScreenInit(idx, pScreen); - - if (!dmxShadowFB) { - /* Wrap GC functions */ - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - /* Wrap Window functions */ - DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); - DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); - DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - - DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - - DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); - - /* Wrap Image functions */ - DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); - DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen); - - /* Wrap Pixmap functions */ - DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); - DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); - DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); - - /* Wrap Font functions */ - DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); - DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); - - /* Wrap Colormap functions */ - DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); - DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); - DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); - DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); - - /* Wrap Shape functions */ - DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); - } + /* Wrap GC functions */ + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + /* Wrap Window functions */ + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + DMX_WRAP(HandleExposures, dmxHandleExposures, dmxScreen, pScreen); + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); + + DMX_WRAP(ModifyPixmapHeader, dmxModifyPixmapHeader, dmxScreen, pScreen); + + DMX_WRAP(SetWindowPixmap, dmxSetWindowPixmap, dmxScreen, pScreen); + + /* Wrap Image functions */ + DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); + DMX_WRAP(GetSpans, NULL, dmxScreen, pScreen); + + /* Wrap Pixmap functions */ + DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); + DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); + DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); + + /* Wrap Font functions */ + DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); + DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); + + /* Wrap Colormap functions */ + DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); + DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); + DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); + DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); + + /* Wrap Shape functions */ + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); if (!dmxCreateDefColormap(pScreen)) return FALSE; + RegisterBlockAndWakeupHandlers (dmxScreenBlockHandler, + dmxScreenWakeupHandler, + pScreen); + return TRUE; } @@ -356,51 +1262,38 @@ void dmxBECloseScreen(ScreenPtr pScreen) DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; int i; - /* Restore the back-end screen-saver and DPMS state. */ - dmxDPMSTerm(dmxScreen); +#ifdef XV + dmxBEXvScreenFini (pScreen); +#endif - /* Free the screen resources */ +#ifdef RANDR + dmxBERRScreenFini (pScreen); +#endif - XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor); - dmxScreen->noCursor = (Cursor)0; + /* Restore the back-end screen-saver and DPMS state. */ + dmxBEDPMSScreenFini (pScreen); - XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + /* Free the screen resources */ dmxScreen->scrnWin = (Window)0; - if (dmxShadowFB) { - /* Free the shadow GC and image assocated with the back-end server */ - XFreeGC(dmxScreen->beDisplay, dmxScreen->shadowGC); - dmxScreen->shadowGC = NULL; - XFree(dmxScreen->shadowFBImage); - dmxScreen->shadowFBImage = NULL; - } else { - /* Free the default drawables */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - XFreePixmap(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i]); - dmxScreen->scrnDefDrawables[i] = (Drawable)0; - } + /* Free the default drawables */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + XLIB_PROLOGUE (dmxScreen); + XFreePixmap(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i]); + XLIB_EPILOGUE (dmxScreen); + dmxScreen->scrnDefDrawables[i] = (Drawable)0; } /* Free resources allocated during initialization (in dmxinit.c) */ for (i = 0; i < dmxScreen->beNumDefColormaps; i++) + { + XLIB_PROLOGUE (dmxScreen); XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]); + XLIB_EPILOGUE (dmxScreen); + } xfree(dmxScreen->beDefColormaps); dmxScreen->beDefColormaps = NULL; -#if 0 - /* Do not free visuals, depths and pixmap formats here. Free them - * in dmxCloseScreen() instead -- see comment below. */ - XFree(dmxScreen->beVisuals); - dmxScreen->beVisuals = NULL; - - XFree(dmxScreen->beDepths); - dmxScreen->beDepths = NULL; - - XFree(dmxScreen->bePixmapFormats); - dmxScreen->bePixmapFormats = NULL; -#endif - #ifdef GLXEXT if (dmxScreen->glxVisuals) { XFree(dmxScreen->glxVisuals); @@ -409,9 +1302,8 @@ void dmxBECloseScreen(ScreenPtr pScreen) } #endif - /* Close display */ - XCloseDisplay(dmxScreen->beDisplay); - dmxScreen->beDisplay = NULL; + dmxClearQueue (&dmxScreen->request); + dmxClearQueue (&dmxScreen->ignore); } /** Close screen number \a idx. */ @@ -419,62 +1311,77 @@ Bool dmxCloseScreen(int idx, ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + /* Free input overlay window tree */ + if (dmxScreen->inputOverlayWid) + FreeResource (dmxScreen->inputOverlayWid, RT_NONE); + /* Reset the proc vectors */ if (idx == 0) { +#ifdef COMPOSITE + if (!noCompositeExtension) + dmxResetComposite(); +#endif #ifdef RENDER - dmxResetRender(); + if (!noRenderExtension) + dmxResetRender(); +#endif +#ifdef MITSHM + dmxResetShm(); #endif - dmxResetFonts(); + dmxResetSelections(); + dmxResetGrabs(); + dmxResetProps(); } - if (dmxShadowFB) { - /* Free the shadow framebuffer */ - xfree(dmxScreen->shadow); - } else { + /* Unwrap Shape functions */ + DMX_UNWRAP(SetShape, dmxScreen, pScreen); - /* Unwrap Shape functions */ - DMX_UNWRAP(SetShape, dmxScreen, pScreen); + /* Unwrap the pScreen functions */ + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - /* Unwrap the pScreen functions */ - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); - DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); - DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); - DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); - DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(HandleExposures, dmxScreen, pScreen); + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); - DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); - DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); + DMX_UNWRAP(ModifyPixmapHeader, dmxScreen, pScreen); - DMX_UNWRAP(GetImage, dmxScreen, pScreen); - DMX_UNWRAP(GetSpans, dmxScreen, pScreen); + DMX_UNWRAP(SetWindowPixmap, dmxScreen, pScreen); - DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); - DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); + DMX_UNWRAP(GetImage, dmxScreen, pScreen); + DMX_UNWRAP(GetSpans, dmxScreen, pScreen); - DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); + DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); + DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); - DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); - DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); - DMX_UNWRAP(StoreColors, dmxScreen, pScreen); - } + DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); + + DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); + DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); + DMX_UNWRAP(StoreColors, dmxScreen, pScreen); DMX_UNWRAP(SaveScreen, dmxScreen, pScreen); if (dmxScreen->beDisplay) { dmxBECloseScreen(pScreen); -#if 1 + /* Close display */ + dmxCloseDisplay (dmxScreen); + dmxScreen->beDisplay = NULL; + /* Free visuals, depths and pixmap formats here so that they * won't be freed when a screen is detached, thereby allowing * the screen to be reattached to be compared to the one @@ -488,9 +1395,11 @@ Bool dmxCloseScreen(int idx, ScreenPtr pScreen) XFree(dmxScreen->bePixmapFormats); dmxScreen->bePixmapFormats = NULL; -#endif } + if (idx == 0) + dmxAbortDisplay (); + DMX_UNWRAP(CloseScreen, dmxScreen, pScreen); return pScreen->CloseScreen(idx, pScreen); } @@ -500,15 +1409,21 @@ static Bool dmxSaveScreen(ScreenPtr pScreen, int what) DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; if (dmxScreen->beDisplay) { + if (dmxScreen->scrnWin != DefaultRootWindow (dmxScreen->beDisplay)) + return TRUE; switch (what) { case SCREEN_SAVER_OFF: case SCREEN_SAVER_FORCER: + XLIB_PROLOGUE (dmxScreen); XResetScreenSaver(dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); break; case SCREEN_SAVER_ON: case SCREEN_SAVER_CYCLE: + XLIB_PROLOGUE (dmxScreen); XActivateScreenSaver(dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, FALSE); break; } @@ -516,3 +1431,60 @@ static Bool dmxSaveScreen(ScreenPtr pScreen, int what) return TRUE; } + +Bool +dmxAddSequence (DMXQueue *q, + unsigned long sequence) +{ + DMXSequence *s; + + s = malloc (sizeof (DMXSequence)); + if (!s) + return FALSE; + + s->sequence = sequence; + s->next = 0; + + *(q->tail) = s; + q->tail = &s->next; + + return TRUE; +} + +void +dmxClearQueue (DMXQueue *q) +{ + while (q->head) + { + DMXSequence *head = q->head; + + q->head = head->next; + free (head); + } + + q->tail = &q->head; +} + +Bool +dmxAddRequest (DMXQueue *q, + ReplyProcPtr reply, + unsigned long sequence, + void *data) +{ + DMXRequest *r; + + r = malloc (sizeof (DMXRequest)); + if (!r) + return FALSE; + + r->base.sequence = sequence; + r->base.next = 0; + r->reply = reply; + r->data = data; + + *(q->tail) = &r->base; + q->tail = &r->base.next; + + return TRUE; +} + diff --git a/hw/dmx/dmxscrinit.h b/hw/dmx/dmxscrinit.h index a464235..5ac4c36 100644 --- a/hw/dmx/dmxscrinit.h +++ b/hw/dmx/dmxscrinit.h @@ -45,7 +45,16 @@ extern DevPrivateKey dmxScreenPrivateKey; extern Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]); -extern void dmxBEScreenInit(int idx, ScreenPtr pScreen); +extern void dmxBEScreenInit(ScreenPtr pScreen); extern void dmxBECloseScreen(ScreenPtr pScreen); +extern void dmxBEDispatch (ScreenPtr pScreen); + +extern Bool dmxAddSequence (DMXQueue *q, unsigned long sequence); +extern void dmxClearQueue (DMXQueue *q); + +extern Bool dmxAddRequest (DMXQueue *q, + ReplyProcPtr reply, + unsigned long sequence, + void *data); #endif /* DMXSCRINIT_H */ diff --git a/hw/dmx/dmxselection.c b/hw/dmx/dmxselection.c new file mode 100644 index 0000000..76113f4 --- /dev/null +++ b/hw/dmx/dmxselection.c @@ -0,0 +1,1539 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxlog.h" +#include "dmxatom.h" +#include "dmxwindow.h" +#include "dmxscrinit.h" +#include "dmxsync.h" +#include "dmxdnd.h" +#include "dmxselection.h" + +#include "selection.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#define DMX_SELECTION_TIMEOUT (30 * 1000) /* 30 seconds */ + +typedef struct _DMXSelection { + struct _DMXSelection *next; + + XID wid; + XID requestor; + Atom selection; + Atom target; + Atom property; + Time time; + Bool incr; + + struct { + unsigned int in; + unsigned int out; + } value[MAXSCREENS]; + + OsTimerPtr timer; +} DMXSelection; + +static DMXSelection *convHead = NULL; +static DMXSelection *propHead = NULL; +static DMXSelection *reqHead = NULL; + +static DMXSelection * +dmxUnhookSelection (DMXSelection **head, + DMXSelection *s) +{ + DMXSelection *p, *prev = NULL; + + for (p = *head; p; p = p->next) + { + if (p == s) + break; + + prev = p; + } + + assert (p); + + if (prev) + prev->next = s->next; + else + *head = s->next; + + s->next = NULL; + + TimerCancel (s->timer); + + return s; +} + +static int +dmxSelectionDeleteConv (DMXSelection *s) +{ + WindowPtr pWin; + xEvent event; + + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = s->time; + event.u.selectionNotify.requestor = s->wid; + event.u.selectionNotify.selection = s->selection; + event.u.selectionNotify.target = s->target; + event.u.selectionNotify.property = None; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + DeliverEventsToWindow (inputInfo.pointer, pWin, &event, 1, + NoEventMask, NullGrab, 0); + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static int +dmxSelectionDeleteProp (DMXSelection *s) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (s->incr && s->value[i].out) + { + const uint32_t value = 0; + + xcb_change_window_attributes (dmxScreen->connection, + s->value[i].out, + XCB_CW_EVENT_MASK, + &value); + } + } + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static int +dmxSelectionDeleteReq (DMXSelection *s) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + if (s->value[i].out) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + const uint32_t value = 0; + + xcb_change_window_attributes (dmxScreen->connection, + s->value[i].out, + XCB_CW_EVENT_MASK, + &value); + } + } + + if (s->wid) + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + + win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + s->wid, + XRT_WINDOW, + DixDestroyAccess); + + if (win) + { + int j; + + FOR_NSCREENS_BACKWARD(j) { + FreeResource (win->info[j].id, RT_NONE); + } + } + } + else +#endif + + FreeResource (s->wid, RT_NONE); + } + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static CARD32 +dmxSelectionCallback (OsTimerPtr timer, + CARD32 time, + pointer arg) +{ + DMXSelection *r = (DMXSelection *) arg; + DMXSelection *s; + + if (time) + dmxLog (dmxWarning, + "selection conversion for %s timed out\n", + NameForAtom (r->selection)); + + for (s = convHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteConv (dmxUnhookSelection (&convHead, s)); + + for (s = propHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s)); + + for (s = reqHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s)); + + return 0; +} + +static void +dmxSelectionResetTimer (DMXSelection *s) +{ + s->timer = TimerSet (s->timer, + 0, + DMX_SELECTION_TIMEOUT, + dmxSelectionCallback, + s); +} + +static void +dmxAppendSelection (DMXSelection **head, + DMXSelection *s) +{ + DMXSelection *p, *last; + + do { + for (last = NULL, p = *head; p; p = p->next) + { + /* avoid duplicates */ + if (p->selection == s->selection && + p->requestor == s->requestor) + { + if (p->timer) + TimerCancel (p->timer); + + dmxSelectionCallback (s->timer, 0, p); + break; + } + + last = p; + } + } while (p); + + dmxSelectionResetTimer (s); + + if (last) + last->next = s; + else + *head = s; +} + +static Atom +dmxBESelectionAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + int i; + + for (i = 0; i < dmxSelectionMapNum; i++) + if (atom == dmxSelectionMap[i].atom) + return dmxBEAtom (dmxScreen, dmxSelectionMap[i].beAtom); + + return dmxBEAtom (dmxScreen, atom); +} + +static Atom +dmxSelectionAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + int i; + + for (i = 0; i < dmxSelectionMapNum; i++) + if (atom == dmxSelectionMap[i].beAtom) + return dmxAtom (dmxScreen, dmxSelectionMap[i].atom); + + return dmxAtom (dmxScreen, atom); +} + +static void +dmxBESetSelectionOwner (ScreenPtr pScreen, + WindowPtr pWin, + Atom selection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window window = None; + + if (!dmxScreen->beDisplay) + return; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return; + + if (pWin) + window = DMX_GET_WINDOW_PRIV(pWin)->window; + + xcb_set_selection_owner (dmxScreen->connection, + window, + dmxBESelectionAtom (dmxScreen, selection), + 0); +} + +static void +dmxSelectionOwnerReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (reply) + { + xcb_get_selection_owner_reply_t *xselection = + (xcb_get_selection_owner_reply_t *) reply; + + dmxScreen->getSelectionOwnerResult = xselection->owner; + } + + dmxScreen->getSelectionOwner.sequence = 0; +} + +static Bool +dmxBEGetSelectionOwner (ScreenPtr pScreen, + Atom selection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + /* reset getSelectionOwner fields */ + dmxScreen->getSelectionOwner.sequence = 0; + dmxScreen->getSelectionOwnerResult = 0; + + if (!dmxScreen->beDisplay) + return FALSE; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return FALSE; + + dmxScreen->getSelectionOwner = + xcb_get_selection_owner (dmxScreen->connection, + dmxBESelectionAtom (dmxScreen, selection)); + + dmxAddRequest (&dmxScreen->request, + dmxSelectionOwnerReply, + dmxScreen->getSelectionOwner.sequence, + 0); + + return TRUE; +} + +static Window +dmxBEConvertSelection (WindowPtr pWin, + Atom selection, + Atom target, + Atom property, + Time time) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + + if (!dmxScreen->beDisplay || !pWinPriv->window) + return 0; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return 0; + + xcb_convert_selection (dmxScreen->connection, + pWinPriv->window, + dmxBESelectionAtom (dmxScreen, selection), + dmxBEAtom (dmxScreen, target), + property ? dmxBEAtom (dmxScreen, property) : None, + 0); + + dmxSync (dmxScreen, FALSE); + + return pWinPriv->window; +} + +Window +dmxBEGetSelectionAdjustedPropertyWindow (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + DMXSelection *s; + + if (!pWinPriv->window) + return None; + + for (s = reqHead; s; s = s->next) + if (s->value[pScreen->myNum].in == pWinPriv->window) + return s->value[pScreen->myNum].out; + + return pWinPriv->window; +} + +void +dmxSelectionClear (ScreenPtr pScreen, + Window owner, + Atom xSelection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom selection = dmxSelectionAtom (dmxScreen, xSelection); + Selection *pSel; + + if (!ValidAtom (selection)) + return; + + if (dixLookupSelection (&pSel, + selection, + serverClient, + DixGetAttrAccess) == Success && + pSel->client != NullClient) + { + SelectionInfoRec info = { pSel, NullClient, SelectionSetOwner }; + xEvent event; + + event.u.u.type = SelectionClear; + event.u.selectionClear.time = currentTime.milliseconds; + event.u.selectionClear.window = pSel->window; + event.u.selectionClear.atom = pSel->selection; + + TryClientEvents (pSel->client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + + pSel->lastTimeChanged = currentTime; + pSel->window = dmxScreen->inputOverlayWid; + pSel->pWin = NULL; + pSel->client = NullClient; + + CallCallbacks (&SelectionCallback, &info); + + pSel->window = None; + } +} + +static void +dmxSelectionPropertyReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXSelection *s; + + for (s = propHead; s; s = s->next) + if (s->value[pScreen->myNum].in == sequence) + break; + + if (s) + { + WindowPtr pWin = NullWindow; + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + { + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xEvent event; + + event.u.selectionNotify.property = None; + + if (reply) + { + Atom type = dmxAtom (dmxScreen, xproperty->type); + uint32_t *data = xcb_get_property_value (xproperty); + int length = xcb_get_property_value_length (xproperty); + + /* only 32 bit data types can be translated */ + if (xproperty->format == 32) + { + int i; + + switch (type) { + case XA_ATOM: + for (i = 0; i < length; i++) + data[i] = dmxAtom (dmxScreen, data[i]); + break; + case XA_BITMAP: + case XA_PIXMAP: + case XA_COLORMAP: + case XA_CURSOR: + case XA_DRAWABLE: + case XA_FONT: + case XA_VISUALID: + case XA_WINDOW: + /* XXX: there's no guarantee that properties of these + types can be converted as all back-end resources + don't exist on this server. + */ + type = 0; + default: + if (type == dmxScreen->atomPairAtom) + for (i = 0; i < length; i++) + data[i] = dmxAtom (dmxScreen, data[i]); + break; + } + } + + if (ValidAtom (type) && + ChangeWindowProperty (pWin, + s->property, + type, + xproperty->format, + PropModeReplace, + length, + data, + TRUE) == Success) + event.u.selectionNotify.property = s->property; + } + + if (s->target) + { + event.u.u.type = SelectionNotify | 0x80; + event.u.selectionNotify.time = s->time; + event.u.selectionNotify.requestor = s->wid; + event.u.selectionNotify.selection = s->selection; + event.u.selectionNotify.target = s->target; + + TryClientEvents (wClient (pWin), NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + } + + if (s->incr) + { + /* end of incremental selection transfer when size is 0 */ + if (xproperty->value_len != 0) + { + /* don't send another selection notify event */ + s->target = None; + dmxSelectionResetTimer (s); + return; + } + } + } + + dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s)); + } +} + +void +dmxSelectionNotify (ScreenPtr pScreen, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom selection = dmxSelectionAtom (dmxScreen, xSelection); + DMXSelection *s; + + for (s = convHead; s; s = s->next) + if (s->value[pScreen->myNum].out == requestor && + s->selection == selection) + break; + + if (s) + { + xcb_get_property_cookie_t cookie = { 0 }; + Atom property = dmxAtom (dmxScreen, xProperty); + Atom target = dmxAtom (dmxScreen, xTarget); + + if (ValidAtom (property) && ValidAtom (target)) + cookie = xcb_get_property (dmxScreen->connection, + xFalse, + requestor, + xProperty, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + if (cookie.sequence) + { + const uint32_t value = + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_PROPERTY_CHANGE; + + dmxUnhookSelection (&convHead, s); + + memset (s->value, 0, sizeof (s->value)); + + s->value[pScreen->myNum].out = requestor; + s->value[pScreen->myNum].in = cookie.sequence; + + s->property = property; + s->target = target; + + if (target == dmxScreen->incrAtom) + s->incr = TRUE; + + if (s->incr) + xcb_change_window_attributes (dmxScreen->connection, + requestor, + XCB_CW_EVENT_MASK, + &value); + + dmxAppendSelection (&propHead, s); + + dmxAddRequest (&dmxScreen->request, + dmxSelectionPropertyReply, + cookie.sequence, + 0); + } + else + { + int i; + + s->value[pScreen->myNum].out = 0; + + for (i = 0; i < dmxNumScreens; i++) + if (s->value[i].out) + break; + + if (i == dmxNumScreens) + dmxSelectionDeleteConv (dmxUnhookSelection (&convHead, s)); + } + } +} + +Bool +dmxSelectionDestroyNotify (ScreenPtr pScreen, + Window window) +{ + DMXSelection *s; + + for (s = reqHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window) + break; + + if (s) + { + dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s)); + return TRUE; + } + + for (s = propHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window) + break; + + if (s) + { + s->value[pScreen->myNum].out = None; + return TRUE; + } + + return FALSE; +} + +Bool +dmxSelectionPropertyNotify (ScreenPtr pScreen, + Window window, + int state, + Atom xProperty, + Time xTime) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + DMXSelection *s; + + if (state == XCB_PROPERTY_NEW_VALUE) + { + for (s = propHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window) + break; + + if (s) + { + xcb_get_property_cookie_t cookie = { 0 }; + + cookie = xcb_get_property (dmxScreen->connection, + xFalse, + window, + xProperty, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + if (cookie.sequence) + { + s->value[pScreen->myNum].in = cookie.sequence; + dmxAddRequest (&dmxScreen->request, + dmxSelectionPropertyReply, + cookie.sequence, + 0); + dmxSelectionResetTimer (s); + } + else + { + dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s)); + } + } + } + else + { + for (s = reqHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window && + s->property == dmxAtom (dmxScreen, xProperty)) + break; + + if (s) + { + WindowPtr pWin; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + DeleteProperty (serverClient, pWin, s->property); + + if (s->incr) + TimerCancel (s->timer); + else + dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s)); + } + } + + return TRUE; +} + +static Bool +dmxConvertSelection (ScreenPtr pScreen, + DMXSelection *s, + Window owner, + int multipleLength, + uint32_t *multipleData) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pChild0, pChildN; + Selection *pSel = NULL; + + pChild0 = WindowTable[0]; + pChildN = WindowTable[pScreen->myNum]; + + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pChildN); + + if (pWinPriv->window == owner) + { + dixLookupSelection (&pSel, + s->selection, + serverClient, + DixReadAccess); + break; + } + + if (pChild0->firstChild) + { + pChild0 = pChild0->firstChild; + pChildN = pChildN->firstChild; + continue; + } + + while (!pChild0->nextSib && (pChild0 != WindowTable[0])) + { + pChild0 = pChild0->parent; + pChildN = pChildN->parent; + } + + if (pChild0 == WindowTable[0]) + break; + + pChild0 = pChild0->nextSib; + pChildN = pChildN->nextSib; + } + + if (pSel) + { + XID overrideRedirect = TRUE; + WindowPtr pProxy = NullWindow; + int result; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *newWin; + int j; + + if (!(newWin = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return FALSE; + + newWin->type = XRT_WINDOW; + newWin->u.win.visibility = VisibilityNotViewable; + newWin->u.win.class = InputOnly; + newWin->u.win.root = FALSE; + for (j = 0; j < PanoramiXNumScreens; j++) + newWin->info[j].id = FakeClientID (0); + + FOR_NSCREENS_BACKWARD(j) { + pProxy = CreateWindow (newWin->info[j].id, + dmxScreens[j].pInputOverlayWin, + 0, 0, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pProxy->drawable.id, RT_WINDOW, pProxy)) + return FALSE; + + s->value[j].in = DMX_GET_WINDOW_PRIV (pProxy)->window; + } + + AddResource (newWin->info[0].id, XRT_WINDOW, newWin); + } + else +#endif + + { + pProxy = CreateWindow (FakeClientID (0), + dmxScreens[0].pInputOverlayWin, + 0, 0, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pProxy->drawable.id, RT_WINDOW, pProxy)) + return FALSE; + + s->value[0].in = DMX_GET_WINDOW_PRIV (pProxy)->window; + } + + if (pProxy) + { + xEvent event; + + event.u.u.type = SelectionRequest; + event.u.selectionRequest.owner = pSel->window; + event.u.selectionRequest.time = currentTime.milliseconds; + event.u.selectionRequest.requestor = pProxy->drawable.id; + event.u.selectionRequest.selection = s->selection; + event.u.selectionRequest.target = s->target; + event.u.selectionRequest.property = s->property; + + s->wid = pProxy->drawable.id; + s->requestor = pProxy->drawable.id; + + if (TryClientEvents (pSel->client, NULL, &event, 1, + NoEventMask, + NoEventMask /* CantBeFiltered */, + NullGrab)) + { + if (multipleLength) + ChangeWindowProperty (pProxy, + s->property, + dmxScreen->atomPairAtom, + 32, + PropModeReplace, + multipleLength, + multipleData, + TRUE); + + dmxAppendSelection (&reqHead, s); + return TRUE; + } + } + + dmxSelectionDeleteReq (s); + } + + return FALSE; +} + +static void +dmxMultipleTargetPropertyReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + xcb_selection_notify_event_t xevent; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + DMXSelection *s = (DMXSelection *) data; + + if (reply) + { + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (xproperty->format == 32) + { + uint32_t *data = xcb_get_property_value (xproperty); + int length = xcb_get_property_value_length (xproperty); + int i; + + for (i = 0; i < length; i++) + { + data[i] = dmxAtom (dmxScreen, data[i]); + if ((i & 1) == 0 && data[i] == dmxScreen->incrAtom) + s->incr = TRUE; + } + + if (dmxConvertSelection (pScreen, s, s->wid, length, data)) + return; + } + } + + xevent.response_type = XCB_SELECTION_NOTIFY; + xevent.pad0 = 0; + xevent.sequence = 0; + xevent.time = s->time; + xevent.requestor = s->value[pScreen->myNum].out; + xevent.selection = dmxBESelectionAtom (dmxScreen, s->selection); + xevent.target = dmxBEAtom (dmxScreen, s->target); + xevent.property = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + s->value[pScreen->myNum].out, + 0, + (const char *) &xevent); + + dmxSync (dmxScreen, FALSE); + + free (s); +} + +void +dmxSelectionRequest (ScreenPtr pScreen, + Window owner, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime) +{ + xcb_selection_notify_event_t xevent; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom selection = + dmxSelectionAtom (dmxScreen, xSelection); + + if (ValidAtom (selection)) + { + Atom target = dmxAtom (dmxScreen, xTarget); + Atom property = (xProperty) ? dmxAtom (dmxScreen, xProperty) : None; + + if (ValidAtom (target) && ((property == None) || ValidAtom (property))) + { + DMXSelection *s; + + s = xalloc (sizeof (DMXSelection)); + if (s) + { + s->wid = 0; + s->requestor = 0; + s->selection = selection; + s->target = target; + s->property = property; + s->time = xTime; + s->incr = FALSE; + s->next = 0; + s->timer = 0; + + memset (s->value, 0, sizeof (s->value)); + + s->value[pScreen->myNum].out = requestor; + + if (target == dmxScreen->multipleAtom) + { + if (ValidAtom (property)) + { + xcb_get_property_cookie_t prop; + + prop = xcb_get_property (dmxScreen->connection, + xFalse, + requestor, + xProperty, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + s->wid = owner; + + dmxAddRequest (&dmxScreen->request, + dmxMultipleTargetPropertyReply, + prop.sequence, + (void *) s); + + return; + } + } + else + { + if (dmxConvertSelection (pScreen, s, owner, 0, 0)) + return; + } + } + + xfree (s); + } + } + + xevent.response_type = XCB_SELECTION_NOTIFY; + xevent.pad0 = 0; + xevent.sequence = 0; + xevent.time = xTime; + xevent.requestor = requestor; + xevent.selection = xSelection; + xevent.target = xTarget; + xevent.property = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + requestor, + 0, + (const char *) &xevent); + + dmxSync (dmxScreen, FALSE); +} + +void +dmxSelectionPropertyChangeCheck (WindowPtr pWin, + Atom property, + int nUnits) +{ + DMXSelection *s; + + if (nUnits == -1) + { + for (s = reqHead; s; s = s->next) + if (s->requestor == pWin->drawable.id && + s->property == property) + break; + + if (s) + { + if (s->incr) + TimerCancel (s->timer); + else + dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s)); + + return; + } + + for (s = propHead; s; s = s->next) + if (s->requestor == pWin->drawable.id && + s->property == property) + break; + + if (s && s->incr) + { + int i; + + TimerCancel (s->timer); + + for (i = 0; i < dmxNumScreens; i++) + if (s->value[i].out) + break; + + /* owner doesn't exist anymore */ + if (i == dmxNumScreens) + { + ChangeWindowProperty (pWin, + s->property, + XA_ATOM, + 32, + PropModeReplace, + 0, + NULL, + TRUE); + + dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s)); + } + } + } + else if (nUnits == 0) + { + for (s = reqHead; s; s = s->next) + if (s->requestor == pWin->drawable.id && + s->property == property) + break; + + /* end of incremental selection conversion */ + if (s && s->incr) + dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s)); + } +} + +static int (*dmxSaveProcVector[256]) (ClientPtr); + +static int +dmxProcSetSelectionOwner (ClientPtr client) +{ + WindowPtr pOld = NullWindow; + WindowPtr pWin; +#ifdef PANORAMIX + PanoramiXRes *win = NULL; +#endif + Selection *pSel; + int err; + int i; + + REQUEST(xSetSelectionOwnerReq); + + if (dixLookupSelection (&pSel, + stuff->selection, + serverClient, + DixReadAccess) == Success) + pOld = pSel->pWin; + + err = (*dmxSaveProcVector[X_SetSelectionOwner]) (client); + if (err != Success) + return err; + + if (!pSel && dixLookupSelection (&pSel, + stuff->selection, + serverClient, + DixReadAccess) != Success) + return Success; + + if (pSel->pWin) + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + pSel->window, + XRT_WINDOW, + DixReadAccess); + else +#endif + dixLookupWindow (&pWin, pSel->window, serverClient, DixReadAccess); + } + else if (!pOld) + { + /* avoid setting selection owner to none on back-end servers + when we're not the current owner */ + return Success; + } + + for (i = 0; i < dmxNumScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + pWin = NullWindow; + if (win) + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixReadAccess); + + dmxBESetSelectionOwner (pScreen, pWin, pSel->selection); + } + else +#endif + { + if (pWin && pWin->drawable.pScreen != pScreen) + continue; + + dmxBESetSelectionOwner (pScreen, pWin, pSel->selection); + } + } + + return Success; +} + +static int +dmxProcGetSelectionOwner (ClientPtr client) +{ + xGetSelectionOwnerReply reply; + Selection *pSel; + int rc; + + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + if (!ValidAtom (stuff->id)) + { + client->errorValue = stuff->id; + return BadAtom; + } + + rc = dixLookupSelection (&pSel, stuff->id, client, DixGetAttrAccess); + if (rc == Success) + { + if (pSel->window != None) + return (*dmxSaveProcVector[X_GetSelectionOwner]) (client); + } + else if (rc != BadMatch) + { + return rc; + } + + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.owner = None; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + unsigned int sequence; + int j; + + FOR_NSCREENS(j) { + dmxBEGetSelectionOwner (screenInfo.screens[j], stuff->id); + } + + do { + dmxDispatch (); + + sequence = 0; + + FOR_NSCREENS_BACKWARD(j) { + DMXScreenInfo *dmxScreen = &dmxScreens[j]; + + if (dmxScreen->getSelectionOwnerResult) + break; + + sequence |= dmxScreen->getSelectionOwner.sequence; + } + } while (sequence && j < 0 && dmxWaitForResponse ()); + + /* at least one back-end server has an owner for this selection */ + if (j >= 0) + reply.owner = dmxScreens[0].inputOverlayWid; + } +#endif + + WriteReplyToClient (client, sizeof (xGetSelectionOwnerReply), &reply); + return client->noClientException; +} + +static int +dmxProcConvertSelection (ClientPtr client) +{ + DMXSelection *s; + Bool paramsOkay; + xEvent event; + WindowPtr pWin; + Selection *pSel; + int rc; +#ifdef PANORAMIX + PanoramiXRes *win = NULL; + int j; +#endif + + REQUEST(xConvertSelectionReq); + REQUEST_SIZE_MATCH(xConvertSelectionReq); + + rc = dixLookupWindow (&pWin, stuff->requestor, client, DixSetAttrAccess); + if (rc != Success) + return rc; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->requestor, + XRT_WINDOW, + DixReadAccess))) + return BadImplementation; + } +#endif + + paramsOkay = ValidAtom (stuff->selection) && ValidAtom (stuff->target); + paramsOkay &= (stuff->property == None) || ValidAtom (stuff->property); + if (!paramsOkay) + { + client->errorValue = stuff->property; + return BadAtom; + } + + s = xalloc (sizeof (DMXSelection)); + if (!s) + return BadAlloc; + + s->wid = 0; + s->requestor = stuff->requestor; + s->selection = stuff->selection; + s->target = stuff->target; + s->property = stuff->property; + s->time = stuff->time; + s->incr = FALSE; + s->next = 0; + s->timer = 0; + + memset (s->value, 0, sizeof (s->value)); + + if (stuff->target == dmxScreens[0].multipleAtom) + { + PropertyPtr pProp; + + if (dixLookupProperty (&pProp, + pWin, + stuff->property, + serverClient, + DixReadAccess) == Success && + pProp->format == 32) + { + Atom *data = (Atom *) pProp->data; + int i; + + for (i = 0; i < pProp->size; i++) + if ((i & 1) == 0 && data[i] == dmxScreens[0].incrAtom) + s->incr = TRUE; + } + } + + rc = dixLookupSelection (&pSel, stuff->selection, client, DixReadAccess); + if (rc == Success) + { + if (pSel->window != None) + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + s->value[j].in = DMX_GET_WINDOW_PRIV (pWin)->window; + } + } + else +#endif + s->value[pWin->drawable.pScreen->myNum].in = + DMX_GET_WINDOW_PRIV (pWin)->window; + + dmxAppendSelection (&reqHead, s); + + return (*dmxSaveProcVector[X_ConvertSelection]) (client); + } + } + else if (rc != BadMatch) + { + xfree (s); + return rc; + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + s->value[j].out = dmxBEConvertSelection (pWin, + stuff->selection, + stuff->target, + stuff->property, + stuff->time); + } + } + else +#endif + s->value[pWin->drawable.pScreen->myNum].out = + dmxBEConvertSelection (pWin, + stuff->selection, + stuff->target, + stuff->property, + stuff->time); + + for (j = 0; j < dmxNumScreens; j++) + if (s->value[j].out) + break; + + if (j < dmxNumScreens) + { + s->wid = stuff->requestor; + + dmxAppendSelection (&convHead, s); + + return client->noClientException; + } + + xfree (s); + + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = stuff->time; + event.u.selectionNotify.requestor = stuff->requestor; + event.u.selectionNotify.selection = stuff->selection; + event.u.selectionNotify.target = stuff->target; + event.u.selectionNotify.property = None; + + TryClientEvents (client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + return client->noClientException; +} + +static int +dmxProcSendEvent (ClientPtr client) +{ + REQUEST(xSendEventReq); + REQUEST_SIZE_MATCH(xSendEventReq); + + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) + { + client->errorValue = stuff->propagate; + return BadValue; + } + + switch (stuff->event.u.u.type) { + case SelectionNotify: + if (stuff->eventMask == NoEventMask && + stuff->destination != PointerWindow && + stuff->destination != InputFocus) + { + Atom property = stuff->event.u.selectionNotify.property; + Atom target = stuff->event.u.selectionNotify.target; + DMXSelection *s; + + for (s = reqHead; s; s = s->next) + if (s->requestor == stuff->destination && + s->selection == stuff->event.u.selectionNotify.selection) + break; + + if (s) + { + int i; + + if (target == dmxScreens[0].incrAtom) + s->incr = TRUE; + + s->property = property; + + for (i = 0; i < dmxNumScreens; i++) + { + xcb_selection_notify_event_t xevent; + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + const uint32_t value = + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_PROPERTY_CHANGE; + + if (!s->value[i].out) + continue; + + xevent.response_type = XCB_SELECTION_NOTIFY; + xevent.pad0 = 0; + xevent.sequence = 0; + xevent.time = s->time; + xevent.requestor = s->value[i].out; + xevent.selection = dmxBESelectionAtom (dmxScreen, + s->selection); + if (target) + xevent.target = dmxBEAtom (dmxScreen, target); + else + xevent.target = None; + + if (property) + xevent.property = dmxBEAtom (dmxScreen, property); + else + xevent.property = None; + + xcb_change_window_attributes (dmxScreen->connection, + s->value[i].out, + XCB_CW_EVENT_MASK, + &value); + + xcb_send_event (dmxScreen->connection, + FALSE, + s->value[i].out, + 0, + (const char *) &xevent); + + dmxSync (dmxScreen, FALSE); + + dmxSelectionResetTimer (s); + return client->noClientException; + } + + dmxSelectionResetTimer (s); + } + } + break; + case ClientMessage: + if (stuff->event.u.u.detail != 8 && + stuff->event.u.u.detail != 16 && + stuff->event.u.u.detail != 32) + { + client->errorValue = stuff->event.u.u.detail; + return BadValue; + } + + if (stuff->destination == dmxScreens[0].inputOverlayWid) + dmxDnDClientMessageEvent (&stuff->event); + + break; + } + + return (*dmxSaveProcVector[X_SendEvent]) (client); +} + +void +dmxInitSelections (void) +{ + int i; + + for (i = 0; i < 256; i++) + dmxSaveProcVector[i] = ProcVector[i]; + + ProcVector[X_GetSelectionOwner] = dmxProcGetSelectionOwner; + ProcVector[X_SetSelectionOwner] = dmxProcSetSelectionOwner; + ProcVector[X_ConvertSelection] = dmxProcConvertSelection; + ProcVector[X_SendEvent] = dmxProcSendEvent; +} + +void +dmxResetSelections (void) +{ + int i; + + + for (i = 0; i < 256; i++) + ProcVector[i] = dmxSaveProcVector[i]; +} diff --git a/hw/dmx/dmxselection.h b/hw/dmx/dmxselection.h new file mode 100644 index 0000000..afa7762 --- /dev/null +++ b/hw/dmx/dmxselection.h @@ -0,0 +1,79 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXSELECTION_H +#define DMXSELECTION_H + +#include "dmx.h" +#include "propertyst.h" + +Window +dmxBEGetSelectionAdjustedPropertyWindow (WindowPtr pWin); + +void +dmxSelectionClear (ScreenPtr pScreen, + Window owner, + Atom xSelection); + +void +dmxSelectionNotify (ScreenPtr pScreen, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime); + +Bool +dmxSelectionPropertyNotify (ScreenPtr pScreen, + Window requestor, + int state, + Atom xProperty, + Time xTime); + +Bool +dmxSelectionDestroyNotify (ScreenPtr pScreen, + Window requestor); + +void +dmxSelectionRequest (ScreenPtr pScreen, + Window owner, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime); + +void +dmxSelectionPropertyChangeCheck (WindowPtr pWin, + Atom property, + int nUnits); + +void +dmxInitSelections (void); + +void +dmxResetSelections (void); + +#endif /* DMXSELECTION_H */ diff --git a/hw/dmx/dmxshm.c b/hw/dmx/dmxshm.c new file mode 100644 index 0000000..c7b2c25 --- /dev/null +++ b/hw/dmx/dmxshm.c @@ -0,0 +1,757 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxshm.h" +#include "dmxgc.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxsync.h" +#include "dmxlog.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "shmint.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#ifdef MITSHM + +#include <sys/ipc.h> +#include <sys/shm.h> + +unsigned long DMX_SHMSEG; + +static dmxShmSegInfoPtr shmSegs = NULL; + +extern int (*ProcShmVector[ShmNumberRequests])(ClientPtr); + +static int (*dmxSaveProcVector[ShmNumberRequests]) (ClientPtr); + +static void dmxShmPutImage (XSHM_PUT_IMAGE_ARGS); + +static ShmFuncs dmxFuncs = { NULL, dmxShmPutImage }; + +void +ShmRegisterDmxFuncs (ScreenPtr pScreen) +{ + ShmRegisterFuncs (pScreen, &dmxFuncs); +} + +static void +dmxShmPutImage (DrawablePtr pDraw, + GCPtr pGC, + int depth, + unsigned int format, + int w, + int h, + int sx, + int sy, + int sw, + int sh, + int dx, + int dy, + char *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pDraw->pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV (pGC); + int vIndex = dmxScreen->beDefVisualIndex; + XImage *image = NULL; + Drawable draw; + + if (pDraw->type == DRAWABLE_WINDOW) + draw = (DMX_GET_WINDOW_PRIV ((WindowPtr) (pDraw)))->window; + else + draw = (DMX_GET_PIXMAP_PRIV ((PixmapPtr) (pDraw)))->pixmap; + + if (!dmxScreen->beDisplay || !draw) + return; + + XLIB_PROLOGUE (dmxScreen); + image = XCreateImage (dmxScreen->beDisplay, + dmxScreen->beVisuals[vIndex].visual, + depth, format, 0, data, w, h, + BitmapPad (dmxScreen->beDisplay), + (format == ZPixmap) ? + PixmapBytePad (w, depth) : BitmapBytePad (w)); + XLIB_EPILOGUE (dmxScreen); + + if (image) + { + RegionRec reg; + BoxRec src, dst; + BoxPtr pBox; + int nBox; + + src.x1 = dx - sx; + src.y1 = dy - sy; + src.x2 = src.x1 + w; + src.y2 = src.y1 + h; + + dst.x1 = dx; + dst.y1 = dy; + dst.x2 = dst.x1 + sw; + dst.y2 = dst.y1 + sh; + + if (src.x1 > dst.x1) + dst.x1 = src.x1; + if (src.y1 > dst.y1) + dst.y1 = src.y1; + if (src.x2 < dst.x2) + dst.x2 = src.x2; + if (src.y2 < dst.y2) + dst.y2 = src.y2; + + REGION_INIT (pGC->pScreen, ®, &dst, 0); + + if (pGC->pCompositeClip) + { + REGION_TRANSLATE (pGC->pScreen, pGC->pCompositeClip, + -pDraw->x, -pDraw->y); + REGION_INTERSECT (pGC->pScreen, ®, ®, pGC->pCompositeClip); + REGION_TRANSLATE (pGC->pScreen, pGC->pCompositeClip, + pDraw->x, pDraw->y); + } + + nBox = REGION_NUM_RECTS (®); + pBox = REGION_RECTS (®); + + XLIB_PROLOGUE (dmxScreen); + while (nBox--) + { + XPutImage (dmxScreen->beDisplay, draw, pGCPriv->gc, image, + pBox->x1 - src.x1, + pBox->y1 - src.y1, + pBox->x1, + pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1); + pBox++; + } + XLIB_EPILOGUE (dmxScreen); + + REGION_UNINIT (pGC->pScreen, ®); + + XFree (image); + + dmxSync (dmxScreen, FALSE); + } +} + +void +dmxBEAttachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo) +{ + if (!dmxScreen->beShm) + return; + + if (!pShmInfo->shmseg[dmxScreen->index]) + { + pShmInfo->shmseg[dmxScreen->index] = + xcb_generate_id (dmxScreen->connection); + + xcb_shm_attach (dmxScreen->connection, + pShmInfo->shmseg[dmxScreen->index], + pShmInfo->shmid, + pShmInfo->readOnly); + } +} + +void +dmxBEDetachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo) +{ + if (!dmxScreen->beShm) + return; + + if (pShmInfo->shmseg[dmxScreen->index]) + { + xcb_shm_detach (dmxScreen->connection, + pShmInfo->shmseg[dmxScreen->index]); + + pShmInfo->shmseg[dmxScreen->index] = None; + pShmInfo->cookie[dmxScreen->index].sequence = 0; + } +} + +Bool +dmxScreenEventCheckShm (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxShmSegInfoPtr pShmInfo; + xcb_shm_seg_t shmseg = 0; + unsigned int sequence = 0; + + if (!dmxScreen->beShm) + return FALSE; + + if (event->response_type) + { + switch ((event->response_type & ~0x80) - dmxScreen->beShmEventBase) { + case XCB_SHM_COMPLETION: { + /* XCB protocol description for XCB_SHM_COMPLETION is wrong */ + xShmCompletionEvent *xcompletion = + (xShmCompletionEvent *) event; + + shmseg = xcompletion->shmseg; + } break; + default: + return FALSE; + } + } + else + { + sequence = ((xcb_generic_error_t *) event)->sequence; + } + + for (pShmInfo = shmSegs; pShmInfo; pShmInfo = pShmInfo->next) + { + if (shmseg && shmseg != pShmInfo->shmseg[pScreen->myNum]) + continue; + + if (!pShmInfo->cookie[pScreen->myNum].sequence) + continue; + + if (sequence && sequence != pShmInfo->cookie[pScreen->myNum].sequence) + continue; + + pShmInfo->pendingEvents--; + pShmInfo->cookie[pScreen->myNum].sequence = 0; + } + + return TRUE; +} + +static int +dmxFreeShmSeg (pointer value, + XID id) +{ + dmxShmSegInfoPtr *pPrev, pShmInfo = (dmxShmSegInfoPtr) value; + int i; + + if (--pShmInfo->refcnt) + return TRUE; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + + dmxBEDetachShmSeg (dmxScreen, pShmInfo); + } + + for (pPrev = &shmSegs; *pPrev != pShmInfo; pPrev = &(*pPrev)->next) + ; + *pPrev = pShmInfo->next; + + xfree (pShmInfo); + return Success; +} + +static int +dmxProcShmAttach (ClientPtr client) +{ + dmxShmSegInfoPtr pShmInfo; + int i, err; + REQUEST(xShmAttachReq); + + err = (*dmxSaveProcVector[X_ShmAttach]) (client); + if (err != Success) + return err; + + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != stuff->shmid); + pShmInfo = pShmInfo->next) + ; + if (pShmInfo) + { + pShmInfo->refcnt++; + } + else + { + pShmInfo = xalloc (sizeof (dmxShmSegInfoRec)); + if (!pShmInfo) + return Success; + + pShmInfo->refcnt = 1; + pShmInfo->shmid = stuff->shmid; + pShmInfo->readOnly = stuff->readOnly; + pShmInfo->pendingEvents = 0; + + memset (pShmInfo->shmseg, 0, sizeof (pShmInfo->shmseg)); + memset (pShmInfo->cookie, 0, sizeof (pShmInfo->cookie)); + + pShmInfo->next = shmSegs; + shmSegs = pShmInfo; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + + dmxBEAttachShmSeg (dmxScreen, pShmInfo); + } + } + + AddResource (stuff->shmseg, DMX_SHMSEG, (pointer) pShmInfo); + + return Success; +} + +static int +dmxProcShmGetImage (ClientPtr client) +{ + DrawablePtr pDraw; + long lenPer = 0, length; + Mask plane = 0; + xShmGetImageReply xgi; + ShmDescPtr shmdesc; + dmxShmSegInfoPtr pShmInfo; + Drawable draw; + int n, rc; + + REQUEST(xShmGetImageReq); + + REQUEST_SIZE_MATCH(xShmGetImageReq); + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) + { + client->errorValue = stuff->format; + return(BadValue); + } + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != shmdesc->shmid); + pShmInfo = pShmInfo->next) + ; + + if (!pShmInfo || !pShmInfo->shmseg[pDraw->pScreen->myNum]) + return (*dmxSaveProcVector[X_ShmGetImage]) (client); + + if (pDraw->type == DRAWABLE_WINDOW) + { + if( /* check for being viewable */ + !((WindowPtr) pDraw)->realized || + /* check for being on screen */ + pDraw->x + stuff->x < 0 || + pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || + pDraw->y + stuff->y < 0 || + pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || + /* check for being inside of border */ + stuff->x < - wBorderWidth((WindowPtr)pDraw) || + stuff->x + (int)stuff->width > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || + stuff->y < -wBorderWidth((WindowPtr)pDraw) || + stuff->y + (int)stuff->height > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height + ) + return(BadMatch); + xgi.visual = wVisual(((WindowPtr)pDraw)); + draw = (DMX_GET_WINDOW_PRIV ((WindowPtr) (pDraw)))->window; + } + else + { + if (stuff->x < 0 || + stuff->x+(int)stuff->width > pDraw->width || + stuff->y < 0 || + stuff->y+(int)stuff->height > pDraw->height + ) + return(BadMatch); + xgi.visual = None; + draw = (DMX_GET_PIXMAP_PRIV ((PixmapPtr) (pDraw)))->pixmap; + } + xgi.type = X_Reply; + xgi.length = 0; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if(stuff->format == ZPixmap) + { + length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; + } + else + { + lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); + } + + if (!draw) + return (*dmxSaveProcVector[X_ShmGetImage]) (client); + + VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); + xgi.size = length; + + if (length) + { + xcb_shm_get_image_cookie_t cookie; + xcb_shm_get_image_reply_t *reply; + DMXScreenInfo *dmxScreen = + &dmxScreens[pDraw->pScreen->myNum]; + + rc = BadValue; + cookie = xcb_shm_get_image (dmxScreen->connection, draw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->planeMask, stuff->format, + pShmInfo->shmseg[dmxScreen->index], + stuff->offset); + do { + dmxDispatch (); + + if (xcb_poll_for_reply (dmxScreen->connection, + cookie.sequence, + (void **) &reply, + NULL)) + { + if (reply) + { + rc = Success; + free (reply); + } + break; + } + } while (dmxWaitForResponse () && dmxScreen->alive); + + if (rc != Success) + return (*dmxSaveProcVector[X_ShmGetImage]) (client); + } + + if (client->swapped) { + swaps(&xgi.sequenceNumber, n); + swapl(&xgi.length, n); + swapl(&xgi.visual, n); + swapl(&xgi.size, n); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); + + return(client->noClientException); +} + +static int +dmxProcShmPutImage (ClientPtr client) +{ + GCPtr pGC; + DrawablePtr pDraw; + long length; + ShmDescPtr shmdesc; + dmxShmSegInfoPtr pShmInfo; + REQUEST(xShmPutImageReq); + + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); + if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) + return BadValue; + if (stuff->format == XYBitmap) + { + if (stuff->depth != 1) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + } + else if (stuff->format == XYPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, stuff->depth); + } + else + { + client->errorValue = stuff->format; + return BadValue; + } + + /* + * There's a potential integer overflow in this check: + * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, + * client); + * the version below ought to avoid it + */ + if (stuff->totalHeight != 0 && + length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { + client->errorValue = stuff->totalWidth; + return BadValue; + } + if (stuff->srcX > stuff->totalWidth) + { + client->errorValue = stuff->srcX; + return BadValue; + } + if (stuff->srcY > stuff->totalHeight) + { + client->errorValue = stuff->srcY; + return BadValue; + } + if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) + { + client->errorValue = stuff->srcWidth; + return BadValue; + } + if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) + { + client->errorValue = stuff->srcHeight; + return BadValue; + } + + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != shmdesc->shmid); + pShmInfo = pShmInfo->next) + ; + + if (pShmInfo && pShmInfo->shmseg[pDraw->pScreen->myNum]) + { + DMXScreenInfo *dmxScreen = &dmxScreens[pDraw->pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV (pGC); + xcb_drawable_t draw; + + if (pDraw->type == DRAWABLE_WINDOW) + draw = (DMX_GET_WINDOW_PRIV ((WindowPtr) (pDraw)))->window; + else + draw = (DMX_GET_PIXMAP_PRIV ((PixmapPtr) (pDraw)))->pixmap; + + if (dmxScreen->beDisplay && draw) + { + pShmInfo->cookie[dmxScreen->index] = + xcb_shm_put_image (dmxScreen->connection, + draw, + XGContextFromGC (pGCPriv->gc), + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, + stuff->depth, + stuff->format, + TRUE, + pShmInfo->shmseg[dmxScreen->index], + stuff->offset); + + pShmInfo->pendingEvents++; + } + } + else + { + dmxShmPutImage (pDraw, pGC, stuff->depth, stuff->format, + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, + shmdesc->addr + stuff->offset); + } + + if (!pDraw->pScreen->myNum) + { + /* we could handle this completely asynchrounsly and continue to + process client requests until all pending completion events + have been collected but some clients seem to assume that + the server is done using the shared memory segment once it + has processed the request */ + if (pShmInfo) + { + /* wait for all back-end servers to complete */ + do { + dmxDispatch (); + } while (pShmInfo->pendingEvents && dmxWaitForResponse ()); + } + } + + if (stuff->sendEvent) + { + xShmCompletionEvent ev; + + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = X_ShmPutImage; + ev.majorEvent = ShmReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + + return (client->noClientException); +} + +void +dmxBEShmScreenInit (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xcb_generic_error_t *error; + xcb_shm_seg_t shmseg; + xcb_pixmap_t pixmap = 0; + uint32_t shmid; + static char key[] = { 'x', 'd', 'm', 'x' }; + char *shmaddr; + xcb_shm_get_image_reply_t *reply; + XlibGC gc; + XGCValues gcvals; + unsigned long mask; + int i; + + dmxScreen->beShm = FALSE; + + shmid = shmget (IPC_PRIVATE, sizeof (key), IPC_CREAT | 0600); + if (shmid == -1) + return; + + shmaddr = shmat (shmid, NULL, 0); + if (shmaddr == (char *) -1) + { + shmctl (shmid, IPC_RMID, NULL); + return; + } + + memset (shmaddr, 0, sizeof (key)); + + shmseg = xcb_generate_id (dmxScreen->connection); + error = xcb_request_check (dmxScreen->connection, + xcb_shm_attach_checked (dmxScreen->connection, + shmseg, + shmid, + FALSE)); + if (error) + { + free (error); + shmdt (shmaddr); + shmctl (shmid, IPC_RMID, NULL); + return; + } + + mask = (GCFunction | GCPlaneMask | GCClipMask | GCGraphicsExposures); + + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + gcvals.foreground = 0; + gcvals.graphics_exposures = FALSE; + + pixmap = xcb_generate_id (dmxScreen->connection); + xcb_create_pixmap (dmxScreen->connection, + 8, + pixmap, + dmxScreen->scrnWin, + sizeof (key), + 1); + + XLIB_PROLOGUE (dmxScreen); + gc = XCreateGC (dmxScreen->beDisplay, pixmap, mask, &gcvals); + if (gc) + { + for (i = 0; i < sizeof (key); i++) + { + gcvals.foreground = key[i]; + XChangeGC (dmxScreen->beDisplay, gc, GCForeground, &gcvals); + XFillRectangle (dmxScreen->beDisplay, pixmap, gc, i, 0, 1, 1); + } + + XFreeGC (dmxScreen->beDisplay, gc); + } + XLIB_EPILOGUE (dmxScreen); + + reply = + xcb_shm_get_image_reply (dmxScreen->connection, + xcb_shm_get_image (dmxScreen->connection, + pixmap, + 0, 0, + sizeof (key), 1, + 0xff, + XCB_IMAGE_FORMAT_Z_PIXMAP, + shmseg, + 0), + NULL); + + xcb_free_pixmap (dmxScreen->connection, pixmap); + + if (!reply) + { + xcb_shm_detach (dmxScreen->connection, shmseg); + shmdt (shmaddr); + shmctl (shmid, IPC_RMID, NULL); + return; + } + + free (reply); + + for (i = 0; i < sizeof (key); i++) + if (shmaddr[i] != key[i]) + break; + + xcb_shm_detach (dmxScreen->connection, shmseg); + shmdt (shmaddr); + shmctl (shmid, IPC_RMID, NULL); + + if (i < sizeof (key)) + return; + + dmxScreen->beShm = TRUE; + dmxScreen->beShmEventBase = XShmGetEventBase (dmxScreen->beDisplay); + dmxLogOutput (dmxScreen, "Using MIT-SHM extension\n"); +} + +void dmxInitShm (void) +{ + int i; + + DMX_SHMSEG = CreateNewResourceType (dmxFreeShmSeg); + + for (i = 0; i < ShmNumberRequests; i++) + dmxSaveProcVector[i] = ProcShmVector[i]; + + ProcShmVector[X_ShmAttach] = dmxProcShmAttach; + ProcShmVector[X_ShmGetImage] = dmxProcShmGetImage; + ProcShmVector[X_ShmPutImage] = dmxProcShmPutImage; +} + +void dmxResetShm (void) +{ + int i; + + for (i = 0; i < ShmNumberRequests; i++) + ProcShmVector[i] = dmxSaveProcVector[i]; +} + +#endif diff --git a/hw/dmx/dmxshm.h b/hw/dmx/dmxshm.h new file mode 100644 index 0000000..69577f0 --- /dev/null +++ b/hw/dmx/dmxshm.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXSHM_H +#define DMXSHM_H + +#ifdef MITSHM + +#include <X11/extensions/XShm.h> +#include <xcb/shm.h> + +typedef struct _dmxShmSegInfo { + struct _dmxShmSegInfo *next; + uint32_t shmid; + int refcnt; + uint8_t readOnly; + uint32_t pendingEvents; + xcb_shm_seg_t shmseg[MAXSCREENS]; + xcb_void_cookie_t cookie[MAXSCREENS]; +} dmxShmSegInfoRec, *dmxShmSegInfoPtr; + +extern unsigned long DMX_SHMSEG; + +extern void ShmRegisterDmxFuncs (ScreenPtr pScreen); + +extern void dmxBEAttachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo); +extern void dmxBEDetachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo); + +extern Bool dmxScreenEventCheckShm (ScreenPtr pScreen, + xcb_generic_event_t *event); + +extern void dmxBEShmScreenInit (ScreenPtr pScreen); + +extern void dmxInitShm (void); +extern void dmxResetShm (void); +#endif + +#endif /* DMXSHM_H */ diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c index c1aa431..c413b9b 100644 --- a/hw/dmx/dmxsync.c +++ b/hw/dmx/dmxsync.c @@ -54,54 +54,119 @@ #include "dmxsync.h" #include "dmxstat.h" #include "dmxlog.h" +#include "dmxextension.h" +#include "dmxscrinit.h" #include <sys/time.h> static int dmxSyncInterval = 100; /* Default interval in milliseconds */ -static OsTimerPtr dmxSyncTimer; -static int dmxSyncPending; +static OsTimerPtr dmxSyncTimer = NULL; +static OsTimerPtr dmxActiveSyncTimer = NULL; +static int dmxSyncPending = 0; +static int dmxSyncRequest = 0; -static void dmxDoSync(DMXScreenInfo *dmxScreen) +/* dispatch all pending back-end server responses */ +void +dmxDispatch (void) { - dmxScreen->needsSync = FALSE; - - if (!dmxScreen->beDisplay) - return; /* FIXME: Is this correct behavior for sync stats? */ + int i; - if (!dmxStatInterval) { - XSync(dmxScreen->beDisplay, False); - } else { - struct timeval start, stop; - - gettimeofday(&start, 0); - XSync(dmxScreen->beDisplay, False); - gettimeofday(&stop, 0); - dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); - } + for (i = 0; i < dmxNumScreens; i++) + if (dmxScreens[i].alive) + dmxBEDispatch (screenInfo.screens[i]); } -static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) +/* non-blocking wait for back-end server response. returns 0 when no + more reponses can arrive */ +int +dmxWaitForResponse (void) { - int i; + fd_set rfds; + int nfd = 0; + int i, ret = 0; - if (dmxSyncPending) { - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->needsSync) dmxDoSync(dmxScreen); - } + FD_ZERO (&rfds); + + for (i = 0; i < dmxNumScreens; i++) + { + if (dmxScreens[i].alive) + { + xcb_flush (dmxScreens[i].connection); + + if (xcb_connection_has_error (dmxScreens[i].connection)) + { + dmxScreens[i].alive = FALSE; + ret = -1; + } + else + { + FD_SET (dmxScreens[i].fd, &rfds); + + if (dmxScreens[i].fd > nfd) + nfd = dmxScreens[i].fd; + } + } } - dmxSyncPending = 0; - return 0; /* Do not place on queue again */ + + if (ret == 0 && nfd) + { + do { + ret = select (nfd + 1, &rfds, 0, 0, 0); + } while (ret == -1 && errno == EINTR); + + /* screens with broken connections are detached in the + block handler */ + } + + return nfd; } -static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) +static void dmxDoSync(DMXScreenInfo *dmxScreen) { - TimerForce(dmxSyncTimer); + dmxScreen->needsSync = FALSE; + + if (!dmxScreen->alive) + return; /* FIXME: Is this correct behavior for sync stats? */ + + if (dmxScreen->sync.sequence) + return; + + dmxScreen->sync = xcb_get_input_focus (dmxScreen->connection); + dmxAddRequest (&dmxScreen->request, + dmxScreenSyncReply, + dmxScreen->sync.sequence, + 0); + dmxSyncRequest++; } -static void dmxSyncWakeupHandler(pointer blockData, int result, - pointer pReadMask) +static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) { + int i; + + /* make sure TimerFree is not called from while waiting for + pending replies */ + dmxActiveSyncTimer = NULL; + + /* wait for all pending sync replies */ + do { + dmxDispatch (); + } while (dmxSyncRequest && dmxWaitForResponse ()); + + if (dmxSyncPending) + { + for (i = 0; i < dmxNumScreens; i++) + if (dmxScreens[i].needsSync) + dmxDoSync (&dmxScreens[i]); + + dmxSyncPending = 0; + + if (dmxSyncRequest) + { + dmxActiveSyncTimer = timer; + return dmxSyncInterval; + } + } + + return 0; /* Do not place on queue again */ } /** Request the XSync() batching optimization with the specified \a @@ -124,9 +189,6 @@ void dmxSyncActivate(const char *interval) void dmxSyncInit(void) { if (dmxSyncInterval) { - RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler, - dmxSyncWakeupHandler, - NULL); dmxLog(dmxInfo, "XSync batching with %d ms interval\n", dmxSyncInterval); } else { @@ -159,35 +221,82 @@ void dmxSync(DMXScreenInfo *dmxScreen, Bool now) * 2) freed, if it was on a queue (dmxSyncPending != 0), or * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0) */ - if (dmxSyncTimer && !dmxSyncPending) xfree(dmxSyncTimer); + if (dmxSyncTimer && !dmxActiveSyncTimer) xfree(dmxSyncTimer); dmxSyncTimer = NULL; - now = TRUE; + now = FALSE; dmxGeneration = serverGeneration; } - /* Queue sync */ + + /* Queue sync */ if (dmxScreen) { + if (now && dmxScreen->inDispatch) + { + dmxLog (dmxWarning, + "Immediate sync from within back-end dispatch\n"); + free (xcb_get_input_focus_reply + (dmxScreen->connection, + xcb_get_input_focus (dmxScreen->connection), + NULL)); + return; + } dmxScreen->needsSync = TRUE; ++dmxSyncPending; } - /* Do sync or set time for later */ - if (now || !dmxScreen) { - if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); - /* At this point, dmxSyncPending == 0 because - * dmxSyncCallback must have been called. */ - if (dmxSyncPending) - dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", - dmxScreen ? dmxScreen->name : "", now, dmxSyncPending); - } else { - dmxScreen->needsSync = TRUE; - if (dmxSyncPending == 1) - dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, - dmxSyncCallback, NULL); + /* Do sync or set time for later */ + if (now || !dmxScreen) + { + if (dmxActiveSyncTimer) + { + TimerCancel (dmxActiveSyncTimer); + dmxActiveSyncTimer = NULL; + } + + while (dmxSyncRequest || dmxSyncPending) + dmxSyncCallback (NULL, 0, NULL); } - } else { - /* If dmxSyncInterval is not being used, - * then all the backends are already - * up-to-date. */ - if (dmxScreen) dmxDoSync(dmxScreen); + else if (!dmxActiveSyncTimer) + { + dmxActiveSyncTimer = TimerSet (dmxSyncTimer, + 0, + dmxSyncInterval, + dmxSyncCallback, + NULL); + } + } + else + { + /* If dmxSyncInterval is not being used, + * then all the backends are already + * up-to-date. */ + if (dmxScreen) + { + dmxDoSync (dmxScreen); + dmxSyncCallback (NULL, 0, NULL); + } + } +} + +/* error or reply doesn't matter, all we need is some response + from the back-end server */ +void +dmxScreenSyncReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->sync.sequence) + { + dmxScreen->sync.sequence = 0; + dmxSyncRequest--; + + if (dmxSyncRequest == 0 && dmxSyncPending == 0 && dmxActiveSyncTimer) + { + TimerCancel (dmxActiveSyncTimer); + dmxActiveSyncTimer = NULL; + } } } diff --git a/hw/dmx/dmxsync.h b/hw/dmx/dmxsync.h index b80f54a..0d48a43 100644 --- a/hw/dmx/dmxsync.h +++ b/hw/dmx/dmxsync.h @@ -37,7 +37,14 @@ #ifndef _DMXSYNC_H_ #define _DMXSYNC_H_ +extern void dmxDispatch (void); +extern int dmxWaitForResponse (void); extern void dmxSyncActivate(const char *interval); extern void dmxSyncInit(void); extern void dmxSync(DMXScreenInfo *dmxScreen, Bool now); +extern void dmxScreenSyncReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data); #endif diff --git a/hw/dmx/dmxvisual.c b/hw/dmx/dmxvisual.c index 7b8771f..0d90ae1 100644 --- a/hw/dmx/dmxvisual.c +++ b/hw/dmx/dmxvisual.c @@ -93,7 +93,7 @@ Visual *dmxLookupVisual(ScreenPtr pScreen, VisualPtr pVisual) for (i = 0; i < dmxScreen->beNumVisuals; i++) { if (pVisual->class == dmxScreen->beVisuals[i].class && pVisual->bitsPerRGBValue == dmxScreen->beVisuals[i].bits_per_rgb && - pVisual->ColormapEntries == dmxScreen->beVisuals[i].colormap_size && + pVisual->ColormapEntries <= dmxScreen->beVisuals[i].colormap_size && pVisual->nplanes == dmxScreen->beVisuals[i].depth && pVisual->redMask == dmxScreen->beVisuals[i].red_mask && pVisual->greenMask == dmxScreen->beVisuals[i].green_mask && diff --git a/hw/dmx/dmxwindow.c b/hw/dmx/dmxwindow.c index 24acc08..3a0ab16 100644 --- a/hw/dmx/dmxwindow.c +++ b/hw/dmx/dmxwindow.c @@ -46,11 +46,25 @@ #include "dmxvisual.h" #include "dmxinput.h" #include "dmxextension.h" +#include "dmxscrinit.h" +#include "dmxcursor.h" +#include "dmxfont.h" +#include "dmxatom.h" +#include "dmxprop.h" +#include "dmxselection.h" +#include "dmxdnd.h" #ifdef RENDER #include "dmxpict.h" #endif #include "windowstr.h" +#include "propertyst.h" +#include "dixfont.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif static void dmxDoRestackWindow(WindowPtr pWindow); static void dmxDoChangeWindowAttributes(WindowPtr pWindow, @@ -59,6 +73,12 @@ static void dmxDoChangeWindowAttributes(WindowPtr pWindow, static void dmxDoSetShape(WindowPtr pWindow); +static void +dmxDoRedirectWindow(WindowPtr pWindow); + +static void +dmxDoUpdateWindowPixmap(WindowPtr pWindow); + /** Initialize the private area for the window functions. */ Bool dmxInitWindow(ScreenPtr pScreen) { @@ -76,24 +96,20 @@ Window dmxCreateRootWindow(WindowPtr pWindow) dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); Window parent; Visual *visual; - unsigned long mask; + unsigned long mask = 0; XSetWindowAttributes attribs; ColormapPtr pCmap; dmxColormapPrivPtr pCmapPriv; + Window win = None; + int w = pWindow->drawable.width; + int h = pWindow->drawable.height; - /* Create root window */ - - parent = dmxScreen->scrnWin; /* This is our "Screen" window */ - visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + /* Avoid to create windows on back-end servers with virtual framebuffer */ + if (dmxScreen->virtualFb) + return None; - mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; - attribs.event_mask = ExposureMask; - attribs.backing_store = NotUseful; - attribs.colormap = pCmapPriv->cmap; - attribs.border_pixel = 0; + mask = CWEventMask; + attribs.event_mask = dmxScreen->rootEventMask; /* Incorporate new attributes, if needed */ if (pWinPriv->attribMask) { @@ -101,41 +117,56 @@ Window dmxCreateRootWindow(WindowPtr pWindow) mask |= pWinPriv->attribMask; } - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - visual, - mask, - &attribs); -} + /* Create root window */ + parent = dmxScreen->scrnWin; /* This is our "Screen" window */ + visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; -/** Change the location and size of the "screen" window. Called from - * #dmxReconfigureScreenWindow(). */ -void dmxResizeScreenWindow(ScreenPtr pScreen, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - unsigned int m; - XWindowChanges c; + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - if (!dmxScreen->beDisplay) - return; + mask |= CWBackingStore | CWColormap | CWBorderPixel | CWOverrideRedirect; + attribs.backing_store = NotUseful; + attribs.colormap = pCmapPriv->cmap; + attribs.border_pixel = 0; + attribs.override_redirect = TRUE; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif - /* Handle resizing on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = x; - c.y = y; - c.width = w; - c.height = h; + XLIB_PROLOGUE (dmxScreen); + win = XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + w, + h, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + visual, + mask, + &attribs); + XChangeProperty (dmxScreen->beDisplay, win, + XInternAtom (dmxScreen->beDisplay, "DMX_NAME", False), + XA_STRING, 8, + PropModeReplace, + (unsigned char *) dmxDigest, + strlen (dmxDigest)); + XLIB_EPILOGUE (dmxScreen); + + dmxBEDnDRootWindowUpdate (pWindow->drawable.pScreen, win); + + return win; +} - XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); - dmxSync(dmxScreen, False); +static void dmxSetIgnore (DMXScreenInfo *dmxScreen, unsigned int sequence) +{ + dmxAddSequence (&dmxScreen->ignore, sequence); } /** Change the location and size of the "root" window. Called from @@ -148,6 +179,9 @@ void dmxResizeRootWindow(WindowPtr pRoot, unsigned int m; XWindowChanges c; + if (!pWinPriv->window) + return; + /* Handle resizing on back-end server */ if (dmxScreen->beDisplay) { m = CWX | CWY | CWWidth | CWHeight; @@ -156,18 +190,31 @@ void dmxResizeRootWindow(WindowPtr pRoot, c.width = (w > 0) ? w : 1; c.height = (h > 0) ? h : 1; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); } if (w == 0 || h == 0) { if (pWinPriv->mapped) { if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + } pWinPriv->mapped = FALSE; } } else if (!pWinPriv->mapped) { if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + } pWinPriv->mapped = TRUE; } @@ -215,6 +262,12 @@ static Window dmxCreateNonRootWindow(WindowPtr pWindow) unsigned long mask = 0L; XSetWindowAttributes attribs; dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + Window win = None; + int x, y, w, h, bw; + + /* Avoid to create windows on back-end servers with virtual framebuffer */ + if (dmxScreen->virtualFb) + return None; /* Create window on back-end server */ @@ -228,6 +281,9 @@ static Window dmxCreateNonRootWindow(WindowPtr pWindow) parent = pParentPriv->window; } + mask |= CWEventMask; + attribs.event_mask = ExposureMask | SubstructureRedirectMask; + /* Incorporate new attributes, if needed */ if (pWinPriv->attribMask) { dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); @@ -254,18 +310,37 @@ static Window dmxCreateNonRootWindow(WindowPtr pWindow) be created on top of the stack, so we must restack the windows */ pWinPriv->restacked = (pWindow->prevSib != NullWindow); - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - pWinPriv->visual, - mask, - &attribs); + if (pWindow != dmxScreen->pInputOverlayWin) + { + x = pWindow->origin.x - wBorderWidth(pWindow); + y = pWindow->origin.y - wBorderWidth(pWindow); + w = pWindow->drawable.width; + h = pWindow->drawable.height; + bw = pWindow->borderWidth; + } + else + { + x = y = -1; + w = h = 1; + bw = 0; + } + + XLIB_PROLOGUE (dmxScreen); + win = XCreateWindow(dmxScreen->beDisplay, + parent, + x, + y, + w, + h, + bw, + pWindow->drawable.depth, + pWindow->drawable.class, + pWinPriv->visual, + mask, + &attribs); + XLIB_EPILOGUE (dmxScreen); + + return win; } /** This function handles lazy window creation and realization. Window @@ -285,15 +360,29 @@ void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) if (!dmxScreen->beDisplay) return; - pWinPriv->window = dmxCreateNonRootWindow(pWindow); - if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); - if (pWinPriv->isShaped) dmxDoSetShape(pWindow); + if (!pWindow->parent) + dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pWindow); + else + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + if (pWinPriv->window) + { + if (pWinPriv->redirected) dmxDoRedirectWindow(pWindow); + if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); + if (pWinPriv->isShaped) dmxDoSetShape(pWindow); #ifdef RENDER - if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); + if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); #endif - if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, - pWinPriv->window); - if (doSync) dmxSync(dmxScreen, False); + if (pWinPriv->mapped) + { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + + if (pWinPriv->beRedirected) dmxDoUpdateWindowPixmap (pWindow); + } + if (doSync) dmxSync(dmxScreen, False); + } } /** Create \a pWindow on the back-end server. If the lazy window @@ -308,16 +397,16 @@ Bool dmxCreateWindow(WindowPtr pWindow) Bool ret = TRUE; DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); -#if 0 + if (pScreen->CreateWindow) ret = pScreen->CreateWindow(pWindow); -#endif /* Set up the defaults */ pWinPriv->window = (Window)0; pWinPriv->offscreen = TRUE; pWinPriv->mapped = FALSE; pWinPriv->restacked = FALSE; + pWinPriv->redirected = FALSE; pWinPriv->attribMask = 0; pWinPriv->isShaped = FALSE; #ifdef RENDER @@ -328,29 +417,14 @@ Bool dmxCreateWindow(WindowPtr pWindow) pWinPriv->barrier = 0; #endif + pWinPriv->beRedirected = FALSE; + if (dmxScreen->beDisplay) { /* Only create the root window at this stage -- non-root windows are created when they are mapped and are on-screen */ if (!pWindow->parent) { - dmxScreen->rootWin = pWinPriv->window - = dmxCreateRootWindow(pWindow); - if (dmxScreen->scrnX != dmxScreen->rootX - || dmxScreen->scrnY != dmxScreen->rootY - || dmxScreen->scrnWidth != dmxScreen->rootWidth - || dmxScreen->scrnHeight != dmxScreen->rootHeight) { - dmxResizeRootWindow(pWindow, - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - pWindow->origin.x = dmxScreen->rootX; - pWindow->origin.y = dmxScreen->rootY; - } + dmxScreen->rootWin = pWinPriv->window = + dmxCreateRootWindow(pWindow); } else { dmxGetDefaultWindowAttributes(pWindow, &pWinPriv->cmap, @@ -382,8 +456,15 @@ Bool dmxBEDestroyWindow(WindowPtr pWindow) DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + pWinPriv->beRedirected = FALSE; + if (pWinPriv->window) { - XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); + if (dmxScreen->scrnWin) + { + XLIB_PROLOGUE (dmxScreen); + XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + } pWinPriv->window = (Window)0; return TRUE; } @@ -419,10 +500,9 @@ Bool dmxDestroyWindow(WindowPtr pWindow) pWinPriv->windowDestroyed(pWindow); #endif -#if 0 if (pScreen->DestroyWindow) ret = pScreen->DestroyWindow(pWindow); -#endif + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); return ret; @@ -439,10 +519,8 @@ Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) XWindowChanges c; DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); -#if 0 if (pScreen->PositionWindow) ret = pScreen->PositionWindow(pWindow, x, y); -#endif /* Determine if the window is completely off the visible portion of the screen */ @@ -452,7 +530,7 @@ Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) been created yet, create it and map it */ if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { + } else if (pWinPriv->window && pWindow != dmxScreen->pInputOverlayWin) { /* Position window on back-end server */ m = CWX | CWY | CWWidth | CWHeight; c.x = pWindow->origin.x - wBorderWidth(pWindow); @@ -464,7 +542,10 @@ Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) c.border_width = pWindow->borderWidth; } + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } @@ -539,7 +620,12 @@ static void dmxDoChangeWindowAttributes(WindowPtr pWindow, *mask &= ~CWBackingPixel; /* Backing store not supported */ if (*mask & CWOverrideRedirect) - attribs->override_redirect = pWindow->overrideRedirect; + { + if (pWindow->parent) + attribs->override_redirect = pWindow->overrideRedirect; + else + *mask &= ~CWOverrideRedirect; + } if (*mask & CWSaveUnder) *mask &= ~CWSaveUnder; /* Save unders not supported */ @@ -560,7 +646,21 @@ static void dmxDoChangeWindowAttributes(WindowPtr pWindow, } if (*mask & CWCursor) - *mask &= ~CWCursor; /* Handled by the cursor code */ + { + ScreenPtr pScreen = pWindow->drawable.pScreen; + + if (pWindow->cursorIsNone) + { + attribs->cursor = None; + } + else + { + dmxCursorPrivPtr pCursorPriv = + DMX_GET_CURSOR_PRIV (wCursor (pWindow), pScreen); + + attribs->cursor = pCursorPriv->cursor; + } + } } /** Change the window attributes of \a pWindow. */ @@ -568,16 +668,9 @@ Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) { ScreenPtr pScreen = pWindow->drawable.pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); XSetWindowAttributes attribs; - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); -#if 0 - if (pScreen->ChangeWindowAttributes) - ret = pScreen->ChangeWindowAttributes(pWindow, mask); -#endif - /* Change window attribs on back-end server */ dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); @@ -585,15 +678,14 @@ Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) pWinPriv->attribMask |= mask; if (mask && pWinPriv->window) { + XLIB_PROLOGUE (dmxScreen); XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, mask, &attribs); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - - return ret; + return TRUE; } /** Realize \a pWindow on the back-end server. If the lazy window @@ -607,10 +699,8 @@ Bool dmxRealizeWindow(WindowPtr pWindow) dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); -#if 0 if (pScreen->RealizeWindow) ret = pScreen->RealizeWindow(pWindow); -#endif /* Determine if the window is completely off the visible portion of the screen */ @@ -624,16 +714,27 @@ Bool dmxRealizeWindow(WindowPtr pWindow) if (pWinPriv->window) { /* Realize window on back-end server */ - XMapWindow(dmxScreen->beDisplay, pWinPriv->window); - dmxSync(dmxScreen, False); + + dmxDoRedirectWindow (pWindow); + + if (MapUnmapEventsEnabled (pWindow)) + { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); + XMapWindow (dmxScreen->beDisplay, pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + } + + dmxDoUpdateWindowPixmap (pWindow); } + dmxSync(dmxScreen, False); + /* Let the other functions know that the window is now mapped */ pWinPriv->mapped = TRUE; DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); return ret; } @@ -646,14 +747,27 @@ Bool dmxUnrealizeWindow(WindowPtr pWindow) dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); -#if 0 if (pScreen->UnrealizeWindow) ret = pScreen->UnrealizeWindow(pWindow); -#endif if (pWinPriv->window) { /* Unrealize window on back-end server */ - XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + + XLIB_PROLOGUE (dmxScreen); + if (MapUnmapEventsEnabled (pWindow)) + { + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + } + + if (pWinPriv->beRedirected) + { + XCompositeUnredirectWindow (dmxScreen->beDisplay, + pWinPriv->window, + CompositeRedirectAutomatic); + pWinPriv->beRedirected = FALSE; + } + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } @@ -669,7 +783,6 @@ Bool dmxUnrealizeWindow(WindowPtr pWindow) DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); return ret; } @@ -687,7 +800,10 @@ static void dmxDoRestackWindow(WindowPtr pWindow) m = CWStackMode; c.sibling = (Window)0; c.stack_mode = Below; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); } else { /* Window is not at the bottom of the stack */ dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); @@ -706,7 +822,10 @@ static void dmxDoRestackWindow(WindowPtr pWindow) m = CWStackMode; c.sibling = (Window)0; c.stack_mode = Below; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); return; } pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); @@ -715,7 +834,10 @@ static void dmxDoRestackWindow(WindowPtr pWindow) m = CWStackMode | CWSibling; c.sibling = pNextSibPriv->window; c.stack_mode = Above; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); } } @@ -728,10 +850,8 @@ void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); -#if 0 if (pScreen->RestackWindow) pScreen->RestackWindow(pWindow, pOldNextSib); -#endif if (pOldNextSib != pWindow->nextSib) { /* Track restacking for lazy window creation optimization */ @@ -745,48 +865,6 @@ void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) } DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); -} - -static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) -{ - return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); -} - -/** Handle exposures on \a pWindow. Since window exposures are handled - * in DMX, the events that are generated by the back-end server are - * redundant, so we eat them here. */ -void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, - RegionPtr other_exposed) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - XEvent ev; - - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - - dmxSync(dmxScreen, False); - - if (pWinPriv->window) { - while (XCheckIfEvent(dmxScreen->beDisplay, &ev, - dmxWindowExposurePredicate, - (XPointer)&pWinPriv->window)) { - /* Handle expose events -- this should not be necessary - since the base window in which the root window was - created is guaranteed to be on top (override_redirect), - so we should just swallow these events. If for some - reason the window is not on top, then we'd need to - collect these events and send them to the client later - (e.g., during the block handler as Xnest does). */ - } - } - -#if 1 - if (pScreen->WindowExposures) - pScreen->WindowExposures(pWindow, prgn, other_exposed); -#endif - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); } /** Move \a pWindow on the back-end server. Determine whether or not it @@ -794,17 +872,7 @@ void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, * lazy window creation optimization is enabled. */ void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) { - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->CopyWindow) - pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); -#endif + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); /* Determine if the window is completely off the visible portion of the screen */ @@ -814,20 +882,7 @@ void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) been created yet, create it and map it */ if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Move window on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); } - - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); } /** Resize \a pWindow on the back-end server. Determine whether or not @@ -847,10 +902,8 @@ void dmxResizeWindow(WindowPtr pWindow, int x, int y, pSibPriv = DMX_GET_WINDOW_PRIV(pSib); DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); -#if 1 if (pScreen->ResizeWindow) pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); -#endif /* Determine if the window is completely off the visible portion of the screen */ @@ -860,7 +913,7 @@ void dmxResizeWindow(WindowPtr pWindow, int x, int y, been created yet, create it and map it */ if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { + } else if (pWinPriv->window && pWindow != dmxScreen->pInputOverlayWin) { /* Handle resizing on back-end server */ m = CWX | CWY | CWWidth | CWHeight; c.x = pWindow->origin.x - wBorderWidth(pWindow); @@ -868,12 +921,14 @@ void dmxResizeWindow(WindowPtr pWindow, int x, int y, c.width = pWindow->drawable.width; c.height = pWindow->drawable.height; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); } /** Reparent \a pWindow on the back-end server. */ @@ -885,10 +940,8 @@ void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); -#if 0 if (pScreen->ReparentWindow) pScreen->ReparentWindow(pWindow, pPriorParent); -#endif if (pWinPriv->window) { if (!pParentPriv->window) { @@ -896,15 +949,16 @@ void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) } /* Handle reparenting on back-end server */ + XLIB_PROLOGUE (dmxScreen); XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, pParentPriv->window, pWindow->origin.x - wBorderWidth(pWindow), pWindow->origin.x - wBorderWidth(pWindow)); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); } /** Change border width for \a pWindow to \a width pixels. */ @@ -917,19 +971,20 @@ void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) XWindowChanges c; DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); -#if 1 if (pScreen->ChangeBorderWidth) pScreen->ChangeBorderWidth(pWindow, width); -#endif /* NOTE: Do we need to check for on/off screen here? */ - if (pWinPriv->window) { + if (pWinPriv->window && pWindow != dmxScreen->pInputOverlayWin) { /* Handle border width change on back-end server */ m = CWBorderWidth; c.border_width = width; + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + XLIB_EPILOGUE (dmxScreen); dmxSync(dmxScreen, False); } @@ -960,14 +1015,20 @@ static void dmxDoSetShape(WindowPtr pWindow) pBox++; pRect++; } + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, ShapeBounding, 0, 0, pRectFirst, nRect, ShapeSet, YXBanded); + XLIB_EPILOGUE (dmxScreen); xfree(pRectFirst); } else { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, ShapeBounding, 0, 0, None, ShapeSet); + XLIB_EPILOGUE (dmxScreen); } /* Next, set the clip shape */ @@ -983,19 +1044,48 @@ static void dmxDoSetShape(WindowPtr pWindow) pBox++; pRect++; } + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, ShapeClip, 0, 0, pRectFirst, nRect, ShapeSet, YXBanded); + XLIB_EPILOGUE (dmxScreen); xfree(pRectFirst); } else { + XLIB_PROLOGUE (dmxScreen); + dmxSetIgnore (dmxScreen, NextRequest (dmxScreen->beDisplay)); XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, ShapeClip, 0, 0, None, ShapeSet); + XLIB_EPILOGUE (dmxScreen); } - if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { - ErrorF("Input selected for window %x on Screen %d\n", - (unsigned int)pWinPriv->window, pScreen->myNum); + if (wInputShape (pWindow)) { + pBox = REGION_RECTS(wInputShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wInputShape(pWindow)); + pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XLIB_PROLOGUE (dmxScreen); + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeInput, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + XLIB_EPILOGUE (dmxScreen); + xfree(pRectFirst); + } + else + { + XLIB_PROLOGUE (dmxScreen); + XShapeCombineMask (dmxScreen->beDisplay, pWinPriv->window, + ShapeInput, 0, 0, None, ShapeSet); + XLIB_EPILOGUE (dmxScreen); } } @@ -1007,18 +1097,375 @@ void dmxSetShape(WindowPtr pWindow) dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); DMX_UNWRAP(SetShape, dmxScreen, pScreen); -#if 1 if (pScreen->SetShape) pScreen->SetShape(pWindow); -#endif if (pWinPriv->window) { /* Handle setting the current shape on the back-end server */ dmxDoSetShape(pWindow); dmxSync(dmxScreen, False); - } else { - pWinPriv->isShaped = TRUE; } + pWinPriv->isShaped = TRUE; + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); } + +static void +dmxDoRedirectWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (pWinPriv->window && pWinPriv->redirected && !pWinPriv->beRedirected) + { + XLIB_PROLOGUE (dmxScreen); + XCompositeRedirectWindow (dmxScreen->beDisplay, + pWinPriv->window, + CompositeRedirectAutomatic); + XLIB_EPILOGUE (dmxScreen); + pWinPriv->beRedirected = TRUE; + } +} + +static void +dmxDoUpdateWindowPixmap(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (pWinPriv->window && pWinPriv->beRedirected) + { + PixmapPtr pPixmap; + + pPixmap = (*pScreen->GetWindowPixmap) (pWindow); + if (pPixmap) + { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV (pPixmap); + + if (pPixPriv->pixmap) + { + XLIB_PROLOGUE (dmxScreen); + XFreePixmap (dmxScreen->beDisplay, pPixPriv->pixmap); + XLIB_EPILOGUE (dmxScreen); + pPixPriv->pixmap = None; + } + + XLIB_PROLOGUE (dmxScreen); + pPixPriv->pixmap = + XCompositeNameWindowPixmap (dmxScreen->beDisplay, + pWinPriv->window); + XLIB_EPILOGUE (dmxScreen); + } + } +} + +static void +dmxTranslateWindowProperty (WindowPtr pWindow, + char type, + unsigned char *data, + unsigned char *output) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + switch (type) { + case 'a': + case 'A': { + Atom *src = (Atom *) data; + Atom *dst = (Atom *) output; + + *dst = dmxBEAtom (dmxScreen, *src); + } break; + case 'p': + case 'P': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + PixmapPtr pPixmap; + XID id = *src; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *res; + + if (dixLookupResource ((pointer *) &res, + id, + XRT_PIXMAP, + serverClient, + DixReadAccess) == Success) + id = res->info[pScreen->myNum].id; + } +#endif + + if (dixLookupResource ((pointer *) &pPixmap, + id, + RT_PIXMAP, + serverClient, + DixReadAccess) == Success) + *dst = (DMX_GET_PIXMAP_PRIV (pPixmap))->pixmap; + else + *dst = 0; + } break; + case 'm': + case 'M': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + ColormapPtr pColormap; + XID id = *src; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *res; + + if (dixLookupResource ((pointer *) &res, + id, + XRT_COLORMAP, + serverClient, + DixReadAccess) == Success) + id = res->info[pScreen->myNum].id; + } +#endif + + if (dixLookupResource ((pointer *) &pColormap, + id, + RT_COLORMAP, + serverClient, + DixReadAccess) == Success) + *dst = (DMX_GET_COLORMAP_PRIV (pColormap))->cmap; + else + *dst = 0; + } break; + case 'c': + case 'C': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + CursorPtr pCursor; + + if (dixLookupResource ((pointer *) &pCursor, + *src, + RT_CURSOR, + serverClient, + DixReadAccess) == Success) + *dst = (DMX_GET_CURSOR_PRIV (pCursor, pScreen))->cursor; + else + *dst = 0; + } break; + case 'd': + case 'D': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + DrawablePtr pDrawable; + XID id = *src; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *res; + + if (dixLookupResource ((pointer *) &res, + id, + XRC_DRAWABLE, + serverClient, + DixReadAccess) == Success) + id = res->info[pScreen->myNum].id; + } +#endif + + if (dixLookupResource ((pointer *) &pDrawable, + id, + RC_DRAWABLE, + serverClient, + DixReadAccess) == Success) + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr) pDrawable; + + *dst = (DMX_GET_WINDOW_PRIV (pWin))->window; + } + else + { + PixmapPtr pPixmap = (PixmapPtr) pDrawable; + + *dst = (DMX_GET_PIXMAP_PRIV (pPixmap))->pixmap; + } + } + else + *dst = 0; + } break; + case 'f': + case 'F': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + FontPtr pFont; + + if (dixLookupResource ((pointer *) &pFont, + *src, + RT_FONT, + serverClient, + DixReadAccess) == Success) + { + dmxFontPrivPtr pFontPriv = + FontGetPrivate (pFont, dmxFontPrivateIndex); + + *dst = pFontPriv->font[pScreen->myNum]->fid; + } + else + *dst = 0; + } break; + case 'v': + case 'V': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + Visual *visual; + + visual = dmxLookupVisualFromID (pScreen, *src); + if (visual) + *dst = XVisualIDFromVisual (visual); + else + *dst = 0; + } break; + case 'w': + case 'W': { + XID *src = (XID *) data; + XID *dst = (XID *) output; + WindowPtr pWin; + XID id = *src; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *res; + + if (dixLookupResource ((pointer *) &res, + id, + XRT_WINDOW, + serverClient, + DixReadAccess) == Success) + id = res->info[pScreen->myNum].id; + } +#endif + + if (dixLookupResource ((pointer *) &pWin, + id, + RT_WINDOW, + serverClient, + DixReadAccess) == Success) + *dst = (DMX_GET_WINDOW_PRIV (pWin))->window; + else + *dst = 0; + } break; + default: + *((CARD32 *) output) = *((CARD32 *) data); + break; + } +} + +void +dmxBESetWindowProperty (WindowPtr pWindow, + PropertyPtr pProp) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + unsigned char *data = pProp->data; + const char *format = NULL; + Window window; + int i; + + window = dmxBEGetSelectionAdjustedPropertyWindow (pWindow); + if (!window) + return; + + /* only 32 bit data types can be translated */ + if (pProp->format == 32) + { + switch (pProp->type) { + case XA_ATOM: + format = "a.."; + break; + case XA_BITMAP: + case XA_PIXMAP: + format = "p.."; + break; + case XA_COLORMAP: + format = "m.."; + break; + case XA_CURSOR: + format = "c.."; + break; + case XA_DRAWABLE: + format = "d.."; + break; + case XA_FONT: + format = "f.."; + break; + case XA_VISUALID: + format = "v.."; + break; + case XA_WINDOW: + format = "w.."; + break; + default: + for (i = 0; i < dmxPropTransNum; i++) + { + if (pProp->type == dmxPropTrans[i].type) + { + format = dmxPropTrans[i].format; + break; + } + } + } + } + + if (format) + { + unsigned char *dst, *src = data; + + dst = xalloc (pProp->size * (pProp->format >> 3)); + if (dst) + { + int j; + + i = j = 0; + data = dst; + + while (format[j] != '\0') + { + if (i++ == pProp->size) + break; + + if (format[j] == '.') + j = 0; + + dmxTranslateWindowProperty (pWindow, format[j++], src, dst); + + src += (pProp->format >> 3); + dst += (pProp->format >> 3); + } + + if (i < pProp->size) + memcpy (dst, src, (pProp->size - i) * (pProp->format >> 3)); + } + } + + XLIB_PROLOGUE (dmxScreen); + XChangeProperty (dmxScreen->beDisplay, + window, + dmxBEAtom (dmxScreen, pProp->propertyName), + dmxBEAtom (dmxScreen, pProp->type), + pProp->format, + PropModeReplace, + data, + pProp->size); + XLIB_EPILOGUE (dmxScreen); + + if (data != pProp->data) + xfree (data); + + dmxSync (dmxScreen, FALSE); +} + diff --git a/hw/dmx/dmxwindow.h b/hw/dmx/dmxwindow.h index 353d0a3..5147cf2 100644 --- a/hw/dmx/dmxwindow.h +++ b/hw/dmx/dmxwindow.h @@ -38,6 +38,7 @@ #define DMXWINDOW_H #include "windowstr.h" +#include "property.h" /** Window private area. */ typedef struct _dmxWinPriv { @@ -45,6 +46,7 @@ typedef struct _dmxWinPriv { Bool offscreen; Bool mapped; Bool restacked; + Bool redirected; unsigned long attribMask; Colormap cmap; Visual *visual; @@ -58,6 +60,7 @@ typedef struct _dmxWinPriv { void (*windowDestroyed)(WindowPtr); void (*windowUnmapped)(WindowPtr); #endif + Bool beRedirected; } dmxWinPrivRec, *dmxWinPrivPtr; @@ -77,8 +80,6 @@ extern Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask); extern Bool dmxRealizeWindow(WindowPtr pWindow); extern Bool dmxUnrealizeWindow(WindowPtr pWindow); extern void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib); -extern void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, - RegionPtr other_exposed); extern void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc); @@ -95,6 +96,8 @@ extern void dmxResizeRootWindow(WindowPtr pRoot, extern Bool dmxBEDestroyWindow(WindowPtr pWindow); +extern void dmxBESetWindowProperty(WindowPtr pWindow, PropertyPtr pProp); + /* Support for shape extension */ extern void dmxSetShape(WindowPtr pWindow); diff --git a/hw/dmx/dmxxlibio.h b/hw/dmx/dmxxlibio.h new file mode 100644 index 0000000..6c5d188 --- /dev/null +++ b/hw/dmx/dmxxlibio.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2007 David Reveman + * + * 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 + * David Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * David Reveman makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DAVID REVEMAN 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMX_XLIBIO_H +#define DMX_XLIBIO_H + +#include <setjmp.h> + +extern jmp_buf _dmx_jumpbuf; +extern int _dmx_io_error; +extern int _dmx_jumpbuf_set; + +#define XLIB_PROLOGUE(_dmxScreen) \ + do { \ + _dmx_io_error = 0; \ + _dmx_jumpbuf_set = 1; \ + setjmp (_dmx_jumpbuf); \ + if (_dmx_io_error) \ + { \ + (_dmxScreen)->alive = FALSE; \ + } \ + else if ((_dmxScreen)->alive) \ + { + +#define XLIB_EPILOGUE(_dmxScreen) \ + } \ + _dmx_jumpbuf_set = 0; \ + } while (0) + +#endif diff --git a/hw/dmx/dmxxv.c b/hw/dmx/dmxxv.c new file mode 100644 index 0000000..03108b0 --- /dev/null +++ b/hw/dmx/dmxxv.c @@ -0,0 +1,734 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#ifdef XV +#include "dmx.h" +#include "dmxsync.h" +#include "dmxgc.h" +#include "dmxwindow.h" +#include "dmxvisual.h" +#include "dmxlog.h" +#include "dmxxv.h" + +#include "xvdix.h" +#include "gcstruct.h" +#include "dixstruct.h" +#include "servermd.h" +#include "pixmapstr.h" + +typedef struct _dmxXvAdaptor { + int base; + int n; +} dmxXvAdaptorRec, *dmxXvAdaptorPtr; + +typedef struct _dmxXvPort { + int id; + XvPortID port; + XvImage *image; +} dmxXvPortRec, *dmxXvPortPtr; + +#define DMX_GET_XV_SCREEN(pScreen) \ + ((XvScreenPtr) dixLookupPrivate (&pScreen->devPrivates, \ + XvGetScreenKey ())) + +#define DMX_XV_SCREEN(pScreen) \ + XvScreenPtr pXvScreen = DMX_GET_XV_SCREEN (pScreen) + +#define DMX_GET_XV_ADAPTOR_PRIV(pAdaptor) \ + ((dmxXvAdaptorPtr) ((pAdaptor)->devPriv.ptr)) + +#define DMX_XV_ADAPTOR_PRIV(pAdaptor) \ + dmxXvAdaptorPtr pAdaptorPriv = DMX_GET_XV_ADAPTOR_PRIV (pAdaptor) + +#define DMX_GET_XV_PORT_PRIV(pPort) \ + ((dmxXvPortPtr) ((pPort)->devPriv.ptr)) + +#define DMX_XV_PORT_PRIV(pPort) \ + dmxXvPortPtr pPortPriv = DMX_GET_XV_PORT_PRIV (pPort) + +#define DMX_XV_NUM_PORTS 32 + +#define DMX_XV_IMAGE_MAX_WIDTH 2046 +#define DMX_XV_IMAGE_MAX_HEIGHT 2046 + +#define DMX_FOURCC(a, b, c, d) \ + ((a) | (b) << 8 | (c) << 16 | ((unsigned int) (d)) << 24) + +#define DMX_FOURCC_YUY2 DMX_FOURCC ('Y', 'U', 'Y', '2') +#define DMX_FOURCC_YV12 DMX_FOURCC ('Y', 'V', '1', '2') + +static XvImageRec xvImages[] = { + { + DMX_FOURCC_YUY2, XvYUV, BITMAP_BIT_ORDER, + { + 'Y','U','Y','2', + 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, + 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 + }, + 16, XvPacked, 1, + 0, 0, 0, 0, + 8, 8, 8, 1, 2, 2, 1, 1, 1, + { + 'Y', 'U', 'Y', 'V', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + XvTopToBottom + }, { + DMX_FOURCC_YV12, XvYUV, BITMAP_BIT_ORDER, + { + 'Y', 'V', '1', '2', + 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, + 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 + }, + 12, XvPlanar, 3, + 0, 0, 0, 0, + 8, 8, 8, 1, 2, 2, 1, 2, 2, + { + 'Y', 'V', 'U', 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + XvTopToBottom + } +}; + +static int +dmxXvFreePort (XvPortPtr pPort) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pPort->pAdaptor->pScreen->myNum]; + + DMX_XV_PORT_PRIV (pPort); + + if (pPortPriv->port) + { + XLIB_PROLOGUE (dmxScreen); + XvUngrabPort (dmxScreen->beDisplay, pPortPriv->port, CurrentTime); + XLIB_EPILOGUE (dmxScreen); + + pPortPriv->port = 0; + } + + if (pPortPriv->image) + { + XFree (pPortPriv->image); + pPortPriv->image = NULL; + } + + pPortPriv->id = 0; + + return Success; +} + +static int +dmxXvStopVideo (ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDrawable) +{ + return Success; +} + +static int +dmxSetPortAttribute (ClientPtr client, + XvPortPtr pPort, + Atom atom, + INT32 value) +{ + return BadMatch; +} + +static int +dmxGetPortAttribute (ClientPtr client, + XvPortPtr pPort, + Atom atom, + INT32 *value) +{ + return BadMatch; +} + +static int +dmxXvQueryBestSize (ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 srcWidth, + CARD16 srcHeight, + CARD16 dstWidth, + CARD16 dstHeight, + unsigned int *pWidth, + unsigned int *pHeight) +{ + *pWidth = dstWidth; + *pHeight = dstHeight; + + return Success; +} + +static int +dmxXvPutImage (ClientPtr client, + DrawablePtr pDrawable, + XvPortPtr pPort, + GCPtr pGC, + INT16 srcX, + INT16 srcY, + CARD16 srcWidth, + CARD16 srcHeight, + INT16 dstX, + INT16 dstY, + CARD16 dstWidth, + CARD16 dstHeight, + XvImagePtr pImage, + unsigned char *data, + Bool sync, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV ((WindowPtr) pDrawable); + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV (pGC); + + DMX_XV_PORT_PRIV (pPort); + + if (pPortPriv->id != pImage->id) + { + int p, j; + + DMX_XV_ADAPTOR_PRIV (pPort->pAdaptor); + + for (p = pAdaptorPriv->base; + p < pAdaptorPriv->base + pAdaptorPriv->n; + p++) + { + XvImageFormatValues *fo = NULL; + int formats; + + XLIB_PROLOGUE (dmxScreen); + fo = XvListImageFormats (dmxScreen->beDisplay, p, &formats); + XLIB_EPILOGUE (dmxScreen); + + if (fo) + { + for (j = 0; j < formats; j++) + if (fo[j].id == pImage->id) + break; + + XFree (fo); + + if (j < formats) + { + if (p != pPortPriv->port) + { + int ret = !Success; + + XLIB_PROLOGUE (dmxScreen); + ret = XvGrabPort (dmxScreen->beDisplay, + p, + CurrentTime); + XLIB_EPILOGUE (dmxScreen); + + if (ret == Success) + break; + } + else + break; + } + + } + } + + pPortPriv->id = pImage->id; + + if (pPortPriv->image) + { + XFree (pPortPriv->image); + pPortPriv->image = NULL; + } + + if (pPortPriv->port && p != pPortPriv->port) + { + XLIB_PROLOGUE (dmxScreen); + XvUngrabPort (dmxScreen->beDisplay, pPortPriv->port, CurrentTime); + XLIB_EPILOGUE (dmxScreen); + + pPortPriv->port = 0; + } + + if (p < pAdaptorPriv->base + pAdaptorPriv->n) + { + pPortPriv->port = p; + } + else if (pAdaptorPriv->n) + { + dmxLog (dmxWarning, + "XVIDEO: failed to allocated port " + "for image format: 0x%x\n", pImage->id); + } + } + else if (pPortPriv->image) + { + if (width != pPortPriv->image->width || + height != pPortPriv->image->height) + { + XFree (pPortPriv->image); + pPortPriv->image = NULL; + } + } + + if (!pPortPriv->image && pPortPriv->port) + { + XLIB_PROLOGUE (dmxScreen); + pPortPriv->image = XvCreateImage (dmxScreen->beDisplay, + pPortPriv->port, + pImage->id, + NULL, + width, + height); + XLIB_EPILOGUE (dmxScreen); + + if (!pPortPriv->image) + return BadAlloc; + + dmxLogOutput (dmxScreen, + "XVIDEO: created 0x%x image with dimensions %dx%d\n", + pImage->id, width, height); + } + + if (pPortPriv->image) + { + pPortPriv->image->data = (char *) data; + + XLIB_PROLOGUE (dmxScreen); + XvPutImage (dmxScreen->beDisplay, + pPortPriv->port, + pWinPriv->window, + pGCPriv->gc, + pPortPriv->image, + srcX, srcY, srcWidth, srcHeight, + dstX, dstY, dstWidth, dstHeight); + XLIB_EPILOGUE (dmxScreen); + + dmxSync (dmxScreen, FALSE); + } + + return Success; +} + +static int +dmxXvQueryImageAttributes (ClientPtr client, + XvPortPtr pPort, + XvImagePtr pImage, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets) +{ + if (*width > DMX_XV_IMAGE_MAX_WIDTH) + *width = DMX_XV_IMAGE_MAX_WIDTH; + + if (*height > DMX_XV_IMAGE_MAX_HEIGHT) + *height = DMX_XV_IMAGE_MAX_HEIGHT; + + *width = (*width + 7) & ~7; + + switch (pImage->id) { + case DMX_FOURCC_YUY2: + if (offsets) + offsets[0] = 0; + + if (pitches) + pitches[0] = *width * 2; + + return *width * *height * 2; + case DMX_FOURCC_YV12: + *height = (*height + 1) & ~1; + + if (offsets) + { + offsets[0] = 0; + offsets[1] = *width * *height; + offsets[2] = *width * *height + (*width >> 1) * (*height >> 1); + } + + if (pitches) + { + pitches[0] = *width; + pitches[1] = pitches[2] = *width >> 1; + } + + return *width * *height + (*width >> 1) * *height; + default: + return 0; + } +} + +static void +dmxXvFreeAdaptor (XvAdaptorPtr pAdaptor) +{ + xfree (pAdaptor->pEncodings); + xfree (pAdaptor->pFormats); + + if (pAdaptor->pPorts) + xfree (pAdaptor->pPorts); +} + +static Bool +dmxXvInitAdaptors (ScreenPtr pScreen) +{ + dmxXvAdaptorPtr pAdaptorPriv; + XvAdaptorPtr pAdaptor; + dmxXvPortPtr pPortPriv; + XvPortPtr pPort; + XvFormatPtr pFormat; + XvEncodingPtr pEncoding; + XvImagePtr pImages; + int i, j, nImages = 0; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMX_XV_SCREEN (pScreen); + + pXvScreen->nAdaptors = 0; + pXvScreen->pAdaptors = NULL; + + pImages = xalloc (sizeof (xvImages)); + if (!pImages) + return FALSE; + + for (i = 0; i < dmxXvImageFormatsNum; i++) + { + for (j = 0; j < sizeof (xvImages) / sizeof (XvImageRec); j++) + { + char imageName[5]; + + sprintf (imageName, "%c%c%c%c", + xvImages[j].id & 0xff, + (xvImages[j].id >> 8) & 0xff, + (xvImages[j].id >> 16) & 0xff, + (xvImages[j].id >> 24) & 0xff); + + if (strcmp (imageName, dmxXvImageFormats[i]) == 0 || + strtol (dmxXvImageFormats[i], NULL, 0) == xvImages[j].id) + { + dmxLogOutput (dmxScreen, "XVIDEO: using image format: \n"); + dmxLogOutput (dmxScreen," id: 0x%x", xvImages[j].id); + if (isprint (imageName[0]) && isprint (imageName[1]) && + isprint (imageName[2]) && isprint (imageName[3])) + dmxLogOutputCont (dmxScreen, " (%s)\n", imageName); + else + dmxLogOutputCont (dmxScreen, "\n", imageName); + + dmxLogOutput (dmxScreen, " bits per pixel: %i\n", + xvImages[j].bits_per_pixel); + dmxLogOutput (dmxScreen, " number of planes: %i\n", + xvImages[j].num_planes); + + dmxLogOutput (dmxScreen, " type: %s (%s)\n", + (xvImages[j].type == XvRGB) ? "RGB" : "YUV", + (xvImages[j].format == XvPacked) ? + "packed" : "planar"); + + if (xvImages[j].type == XvRGB) + { + dmxLogOutput (dmxScreen, " depth: %i\n", + xvImages[j].depth); + dmxLogOutput (dmxScreen, + " red, green, blue masks: " + "0x%x, 0x%x, 0x%x\n", + xvImages[j].red_mask, + xvImages[j].green_mask, + xvImages[j].blue_mask); + } + + pImages[nImages++] = xvImages[j]; + break; + } + } + + if (j == sizeof (xvImages) / sizeof (XvImageRec)) + { + dmxLogOutput (dmxScreen, + "XVIDEO: unsupported image format %s\n", + dmxXvImageFormats[i]); + } + } + + if (!nImages) + { + dmxLogOutput (dmxScreen, "XVIDEO: no supported image formats " + "enabled\n"); + xfree (pImages); + return TRUE; + } + + pAdaptor = Xcalloc (1, sizeof (XvAdaptorRec) + sizeof (dmxXvAdaptorRec)); + pAdaptorPriv = (dmxXvAdaptorPtr) (pAdaptor + 1); + if (!pAdaptor) + return FALSE; + + pAdaptor->type = XvInputMask | XvImageMask; + pAdaptor->pScreen = pScreen; + + pAdaptor->ddFreePort = dmxXvFreePort; + pAdaptor->ddStopVideo = dmxXvStopVideo; + pAdaptor->ddSetPortAttribute = dmxSetPortAttribute; + pAdaptor->ddGetPortAttribute = dmxGetPortAttribute; + pAdaptor->ddPutImage = dmxXvPutImage; + pAdaptor->ddQueryBestSize = dmxXvQueryBestSize; + pAdaptor->ddQueryImageAttributes = dmxXvQueryImageAttributes; + + pAdaptor->name = "DMX Video"; + + pEncoding = Xcalloc (1, sizeof (XvEncodingRec)); + if (!pEncoding) + return FALSE; + + pEncoding->id = 0; + pEncoding->pScreen = pScreen; + pEncoding->name = "XV_IMAGE"; + + pEncoding->width = DMX_XV_IMAGE_MAX_WIDTH; + pEncoding->height = DMX_XV_IMAGE_MAX_HEIGHT; + + pEncoding->rate.numerator = 1; + pEncoding->rate.denominator = 1; + + pAdaptor->nEncodings = 1; + pAdaptor->pEncodings = pEncoding; + + pAdaptor->nImages = nImages; + pAdaptor->pImages = pImages; + + pAdaptor->nAttributes = 0; + pAdaptor->pAttributes = 0; + + pFormat = Xcalloc (1, sizeof (XvFormatRec)); + if (!pFormat) + return FALSE; + + pFormat->depth = pScreen->rootDepth; + pFormat->visual = pScreen->rootVisual; + + pAdaptor->nFormats = 1; + pAdaptor->pFormats = pFormat; + + pPort = Xcalloc (DMX_XV_NUM_PORTS, + sizeof (XvPortRec) + sizeof (dmxXvPortRec)); + pPortPriv = (dmxXvPortPtr) (pPort + DMX_XV_NUM_PORTS); + if (!pPort) + return FALSE; + + for (i = 0; i < DMX_XV_NUM_PORTS; i++) + { + pPort[i].id = FakeClientID (0); + + if (!AddResource (pPort[i].id, XvGetRTPort (), &pPort[i])) + return FALSE; + + pPort[i].pAdaptor = pAdaptor; + pPort[i].pNotify = (XvPortNotifyPtr) 0; + pPort[i].pDraw = (DrawablePtr) 0; + pPort[i].client = (ClientPtr) 0; + pPort[i].grab.client = (ClientPtr) 0; + pPort[i].time = currentTime; + pPort[i].devPriv.ptr = pPortPriv + i; + } + + pAdaptor->nPorts = DMX_XV_NUM_PORTS; + pAdaptor->pPorts = pPort; + pAdaptor->base_id = pPort->id; + pAdaptor->devPriv.ptr = pAdaptorPriv; + + pXvScreen->pAdaptors = pAdaptor; + pXvScreen->nAdaptors = 1; + + return TRUE; +} + +static Bool +dmxXvCloseScreen (int i, ScreenPtr pScreen) +{ + int j; + + DMX_XV_SCREEN (pScreen); + + for (j = 0; j < pXvScreen->nAdaptors; j++) + dmxXvFreeAdaptor (&pXvScreen->pAdaptors[j]); + + if (pXvScreen->pAdaptors) + xfree (pXvScreen->pAdaptors); + + return TRUE; +} + +static int +dmxXvQueryAdaptors (ScreenPtr pScreen, + XvAdaptorPtr *pAdaptors, + int *nAdaptors) +{ + DMX_XV_SCREEN (pScreen); + + *nAdaptors = pXvScreen->nAdaptors; + *pAdaptors = pXvScreen->pAdaptors; + + return Success; +} + +void +dmxBEXvScreenInit (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XvAdaptorInfo *ai; + unsigned int nAdaptors; + int i, j, k, l, ret = !Success; + + DMX_XV_SCREEN (pScreen); + + XLIB_PROLOGUE (dmxScreen); + ret = XvQueryAdaptors (dmxScreen->beDisplay, + DefaultRootWindow (dmxScreen->beDisplay), + &nAdaptors, + &ai); + XLIB_EPILOGUE (dmxScreen); + + if (ret != Success) + { + dmxLogOutput (dmxScreen, + "XVIDEO: back-end support unavailable. " + "XvQueryAdaptors returned %d\n", + ret); + return; + } + + for (i = 0; i < pXvScreen->nAdaptors; i++) + { + XvAdaptorPtr pAdaptor = &pXvScreen->pAdaptors[i]; + + DMX_XV_ADAPTOR_PRIV (pAdaptor); + + for (j = 0; j < nAdaptors; j++) + { + if ((pAdaptor->type & ai[j].type) != pAdaptor->type) + continue; + + for (k = 0; k < pAdaptor->nFormats; k++) + { + Visual *visual; + VisualID vid; + int depth = pAdaptor->pFormats[k].depth; + + visual = dmxLookupVisualFromID (pScreen, + pAdaptor->pFormats[k].visual); + if (visual) + vid = XVisualIDFromVisual (visual); + else + vid = 0; + + for (l = 0; l < ai[j].num_formats; l++) + { + if (ai[j].formats[l].depth == depth && + ai[j].formats[l].visual_id == vid) + break; + } + + if (l == ai[j].num_formats) + break; + } + + if (k < pAdaptor->nFormats) + continue; + + dmxLogOutput (dmxScreen, + "XVIDEO: Using back-end adaptor:\n" + " name: %s\n" + " type: %s%s%s%s%s\n" + " ports: %ld\n" + " first port: %ld\n", + ai[j].name, + (ai[j].type & XvInputMask) ? "input | " : "", + (ai[j].type & XvOutputMask) ? "output | " : "", + (ai[j].type & XvVideoMask) ? "video | " : "", + (ai[j].type & XvStillMask) ? "still | " : "", + (ai[j].type & XvImageMask) ? "image" : "", + ai[j].num_ports, + ai[j].base_id); + + pAdaptorPriv->base = ai[j].base_id; + pAdaptorPriv->n = ai[j].num_ports; + break; + } + + if (j == nAdaptors) + dmxLogOutput (dmxScreen, "XVIDEO: No usable back-end adaptors " + "found for '%s'\n", pAdaptor->name); + } + + if (nAdaptors > 0) + XvFreeAdaptorInfo (ai); +} + +void +dmxBEXvScreenFini (ScreenPtr pScreen) +{ + int i, j; + + DMX_XV_SCREEN (pScreen); + + for (i = 0; i < pXvScreen->nAdaptors; i++) + { + DMX_XV_ADAPTOR_PRIV (&pXvScreen->pAdaptors[i]); + + for (j = 0; j < pXvScreen->pAdaptors[i].nPorts; j++) + dmxXvFreePort (&pXvScreen->pAdaptors[i].pPorts[j]); + + pAdaptorPriv->base = 0; + pAdaptorPriv->n = 0; + } +} + +Bool +dmxXvScreenInit (ScreenPtr pScreen) +{ + XvScreenPtr pXvScreen; + int status; + + status = XvScreenInit (pScreen); + if (status != Success) + return FALSE; + + pXvScreen = DMX_GET_XV_SCREEN (pScreen); + pXvScreen->ddCloseScreen = dmxXvCloseScreen; + pXvScreen->ddQueryAdaptors = dmxXvQueryAdaptors; + pXvScreen->devPriv.ptr = (pointer) 0; + + if (!dmxXvInitAdaptors (pScreen)) + return FALSE; + + return TRUE; +} + +#endif diff --git a/hw/dmx/dmxxv.h b/hw/dmx/dmxxv.h new file mode 100644 index 0000000..b3ca5a2 --- /dev/null +++ b/hw/dmx/dmxxv.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifndef DMXXV_H +#define DMXXV_H + +extern Bool dmxXvScreenInit (ScreenPtr pScreen); +extern void dmxBEXvScreenInit (ScreenPtr pScreen); +extern void dmxBEXvScreenFini (ScreenPtr pScreen); + +#endif /* DMXXV_H */ diff --git a/hw/dmx/examples/Makefile.am b/hw/dmx/examples/Makefile.am index d814339..757dc4d 100644 --- a/hw/dmx/examples/Makefile.am +++ b/hw/dmx/examples/Makefile.am @@ -1,13 +1,9 @@ -if DMX_BUILD_USB -# Requires <linux/input.h> -EV_PROG = ev -endif - bin_PROGRAMS = \ xdmx dmxwininfo dmxreconfig dmxresize \ dmxaddscreen dmxrmscreen \ - dmxaddinput dmxrminput -noinst_PROGRAMS = xinput xtest evi res xled xbell $(EV_PROG) + dmxaddinput dmxrminput \ + dmxconnect +noinst_PROGRAMS = xinput xtest evi res xled xbell xdmx_SOURCES = xdmx.c xdmx_LDADD = @DMXEXAMPLES_DEP_LIBS@ @@ -41,6 +37,10 @@ dmxrminput_SOURCES = dmxrminput.c dmxrminput_LDADD = @DMXEXAMPLES_DEP_LIBS@ dmxrminput_CFLAGS = @DMXEXAMPLES_DEP_CFLAGS@ +dmxconnect_SOURCES = dmxconnect.c +dmxconnect_LDADD = @DBUSEXAMPLES_DEP_LIBS@ +dmxconnect_CFLAGS = @DBUSEXAMPLES_DEP_CFLAGS@ -I$(top_srcdir)/hw/dmx + xinput_SOURCES = xinput.c xinput_LDADD = @DMXXIEXAMPLES_DEP_LIBS@ xinput_CFLAGS = @DMXXIEXAMPLES_DEP_CFLAGS@ @@ -64,7 +64,3 @@ xled_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ xbell_SOURCES = xbell.c xbell_LDADD = @X11EXAMPLES_DEP_LIBS@ xbell_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ - -ev_SOURCES = ev.c -ev_LDADD = -ev_CFLAGS = diff --git a/hw/dmx/examples/dmxaddinput.c b/hw/dmx/examples/dmxaddinput.c index dcfd4f5..c2eecf3 100644 --- a/hw/dmx/examples/dmxaddinput.c +++ b/hw/dmx/examples/dmxaddinput.c @@ -46,29 +46,25 @@ int main(int argc, char **argv) int status; if (argc != 5) { - printf("Usage: %s display c|b name|screen isCore\n", argv[0]); + fprintf(stderr, "Usage: %s display c|b name|screen isCore\n", argv[0]); return -1; } if (!(display = XOpenDisplay(argv[1]))) { - printf("Cannot open display %s\n", argv[1]); + fprintf(stderr, "Cannot open display %s\n", argv[1]); return -1; } if (!DMXQueryExtension(display, &event_base, &error_base)) { - printf("DMX extension not present\n"); + fprintf(stderr, "DMX extension not present\n"); return -1; } - printf("DMX extension present: event_base = %d, error_base = %d\n", - event_base, error_base); if (!DMXQueryVersion(display, &major_version, &minor_version, &patch_version)) { - printf("Could not get extension version\n"); + fprintf(stderr, "Could not get extension version\n"); return -1; } - printf("Extension version: %d.%d patch %d\n", - major_version, minor_version, patch_version); if (argv[2][0] == 'c') { status = DMXAddConsoleInput(display, argv[3], atoi(argv[4]), &id); @@ -76,8 +72,8 @@ int main(int argc, char **argv) status = DMXAddBackendInput(display, atoi(argv[3]), atoi(argv[4]),&id); } - printf("status = %d, id = %d\n", status, id); + printf ("%d", id); XCloseDisplay(display); - return 0; + return status ? 0 : -1; } diff --git a/hw/dmx/examples/dmxaddscreen.c b/hw/dmx/examples/dmxaddscreen.c index 8e60872..9c93c9c 100644 --- a/hw/dmx/examples/dmxaddscreen.c +++ b/hw/dmx/examples/dmxaddscreen.c @@ -48,12 +48,12 @@ int main(int argc, char **argv) unsigned int mask = 0; if (argc != 4 && argc != 14) { - printf("Usage: %s display screenNum displayName [scrnx scrny scrnw scrnh rootx rooty rootw rooth originx originy]\n", argv[0]); + fprintf(stderr, "Usage: %s display screenNum displayName [scrnx scrny scrnw scrnh rootx rooty rootw rooth originx originy]\n", argv[0]); return -1; } if (!(display = XOpenDisplay(argv[1]))) { - printf("Cannot open display %s\n", argv[1]); + fprintf(stderr, "Cannot open display %s\n", argv[1]); return -1; } @@ -83,23 +83,25 @@ int main(int argc, char **argv) } if (!DMXQueryExtension(display, &event_base, &error_base)) { - printf("DMX extension not present\n"); + fprintf(stderr, "DMX extension not present\n"); return -1; } - printf("DMX extension present: event_base = %d, error_base = %d\n", - event_base, error_base); if (!DMXQueryVersion(display, &major_version, &minor_version, &patch_version)) { - printf("Could not get extension version\n"); + fprintf(stderr, "Could not get extension version\n"); return -1; } - printf("Extension version: %d.%d patch %d\n", - major_version, minor_version, patch_version); if (!DMXAddScreen(display, argv[3], mask, &attr, &screenNum)) - printf("Failed to add %s as screen #%d\n", argv[2], screenNum); - + { + fprintf(stderr, "Failed to add %s as screen #%d\n", argv[3], screenNum); + XCloseDisplay(display); + return -1; + } + + printf ("%d", screenNum); + XCloseDisplay(display); return 0; } diff --git a/hw/dmx/examples/dmxconnect.c b/hw/dmx/examples/dmxconnect.c new file mode 100644 index 0000000..194d301 --- /dev/null +++ b/hw/dmx/examples/dmxconnect.c @@ -0,0 +1,884 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * 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 + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. 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. + * + * Author: David Reveman <davidr@novell.com> + */ + +/* + * X authentication and transport code adopted from libxcb + * + * Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. + */ + +#include <dbus/dbus.h> +#include <stdio.h> + +#include <X11/Xauth.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <sys/param.h> +#include <unistd.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#ifdef DNETCONN +#include <netdnet/dnetdb.h> +#include <netdnet/dn.h> +#endif +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <xcb/xcb.h> + +#ifdef HASXDMAUTH +#include <X11/Xdmcp.h> +#endif + +#include "dmxdbus.h" + +enum auth_protos { +#ifdef HASXDMAUTH + AUTH_XA1, +#endif + AUTH_MC1, + N_AUTH_PROTOS +}; + +static char *authnames[N_AUTH_PROTOS] = { +#ifdef HASXDMAUTH + "XDM-AUTHORIZATION-1", +#endif + "MIT-MAGIC-COOKIE-1", +}; + +static size_t memdup(char **dst, void *src, size_t len) +{ + if(len) + *dst = malloc(len); + else + *dst = 0; + if(!*dst) + return 0; + memcpy(*dst, src, len); + return len; +} + +static int authname_match(enum auth_protos kind, char *name, int namelen) +{ + if(strlen(authnames[kind]) != namelen) + return 0; + if(memcmp(authnames[kind], name, namelen)) + return 0; + return 1; +} + +#define SIN6_ADDR(s) (&((struct sockaddr_in6 *)s)->sin6_addr) + +static Xauth *get_authptr(struct sockaddr *sockname, unsigned int socknamelen, + int display) +{ + char *addr = 0; + int addrlen = 0; + unsigned short family; + char hostnamebuf[256]; /* big enough for max hostname */ + char dispbuf[40]; /* big enough to hold more than 2^64 base 10 */ + int authnamelens[N_AUTH_PROTOS]; + int i; + + family = FamilyLocal; /* 256 */ + switch(sockname->sa_family) + { +#ifdef AF_INET6 + case AF_INET6: + addr = (char *) SIN6_ADDR(sockname); + addrlen = sizeof(*SIN6_ADDR(sockname)); + if(!IN6_IS_ADDR_V4MAPPED(SIN6_ADDR(sockname))) + { + if(!IN6_IS_ADDR_LOOPBACK(SIN6_ADDR(sockname))) + family = XCB_FAMILY_INTERNET_6; + break; + } + addr += 12; + /* if v4-mapped, fall through. */ +#endif + case AF_INET: + if(!addr) + addr = (char *) &((struct sockaddr_in *)sockname)->sin_addr; + addrlen = sizeof(((struct sockaddr_in *)sockname)->sin_addr); + if(*(in_addr_t *) addr != htonl(INADDR_LOOPBACK)) + family = XCB_FAMILY_INTERNET; + break; + case AF_UNIX: + break; + default: + return 0; /* cannot authenticate this family */ + } + + snprintf(dispbuf, sizeof(dispbuf), "%d", display); + + if (family == FamilyLocal) { + if (gethostname(hostnamebuf, sizeof(hostnamebuf)) == -1) + return 0; /* do not know own hostname */ + addr = hostnamebuf; + addrlen = strlen(addr); + } + + for (i = 0; i < N_AUTH_PROTOS; i++) + authnamelens[i] = strlen(authnames[i]); + return XauGetBestAuthByAddr (family, + (unsigned short) addrlen, addr, + (unsigned short) strlen(dispbuf), dispbuf, + N_AUTH_PROTOS, authnames, authnamelens); +} + +#ifdef HASXDMAUTH +static int next_nonce(void) +{ + static int nonce = 0; + static pthread_mutex_t nonce_mutex = PTHREAD_MUTEX_INITIALIZER; + int ret; + pthread_mutex_lock(&nonce_mutex); + ret = nonce++; + pthread_mutex_unlock(&nonce_mutex); + return ret; +} + +static void do_append(char *buf, int *idxp, void *val, size_t valsize) { + memcpy(buf + *idxp, val, valsize); + *idxp += valsize; +} +#endif + +static int compute_auth(xcb_auth_info_t *info, Xauth *authptr, struct sockaddr *sockname) +{ + if (authname_match(AUTH_MC1, authptr->name, authptr->name_length)) { + info->datalen = memdup(&info->data, authptr->data, authptr->data_length); + if(!info->datalen) + return 0; + return 1; + } +#ifdef HASXDMAUTH +#define APPEND(buf,idx,val) do_append((buf),&(idx),&(val),sizeof(val)) + if (authname_match(AUTH_XA1, authptr->name, authptr->name_length)) { + int j; + + info->data = malloc(192 / 8); + if(!info->data) + return 0; + + for (j = 0; j < 8; j++) + info->data[j] = authptr->data[j]; + switch(sockname->sa_family) { + case AF_INET: + /*block*/ { + struct sockaddr_in *si = (struct sockaddr_in *) sockname; + APPEND(info->data, j, si->sin_addr.s_addr); + APPEND(info->data, j, si->sin_port); + } + break; +#ifdef AF_INET6 + case AF_INET6: + /*block*/ { + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *) sockname; + if(IN6_IS_ADDR_V4MAPPED(SIN6_ADDR(sockname))) + { + APPEND(info->data, j, si6->sin6_addr.s6_addr[12]); + APPEND(info->data, j, si6->sin6_port); + } + else + { + /* XDM-AUTHORIZATION-1 does not handle IPv6 correctly. Do the + same thing Xlib does: use all zeroes for the 4-byte address + and 2-byte port number. */ + uint32_t fakeaddr = 0; + uint16_t fakeport = 0; + APPEND(info->data, j, fakeaddr); + APPEND(info->data, j, fakeport); + } + } + break; +#endif + case AF_UNIX: + /*block*/ { + uint32_t fakeaddr = htonl(0xffffffff - next_nonce()); + uint16_t fakeport = htons(getpid()); + APPEND(info->data, j, fakeaddr); + APPEND(info->data, j, fakeport); + } + break; + default: + free(info->data); + return 0; /* do not know how to build this */ + } + { + uint32_t now = htonl(time(0)); + APPEND(info->data, j, now); + } + assert(j <= 192 / 8); + while (j < 192 / 8) + info->data[j++] = 0; + info->datalen = j; + XdmcpWrap ((unsigned char *) info->data, (unsigned char *) authptr->data + 8, (unsigned char *) info->data, info->datalen); + return 1; + } +#undef APPEND +#endif + + return 0; /* Unknown authorization type */ +} + +int _get_auth_info (int fd, xcb_auth_info_t *info, int display) +{ + /* code adapted from Xlib/ConnDis.c, xtrans/Xtranssocket.c, + xtrans/Xtransutils.c */ + char sockbuf[sizeof(struct sockaddr) + MAXPATHLEN]; + unsigned int socknamelen = sizeof(sockbuf); /* need extra space */ + struct sockaddr *sockname = (struct sockaddr *) &sockbuf; + Xauth *authptr = 0; + int ret = 1; + + if (getpeername(fd, sockname, &socknamelen) == -1) + return 0; /* can only authenticate sockets */ + + authptr = get_authptr(sockname, socknamelen, display); + if (authptr == 0) + return 0; /* cannot find good auth data */ + + info->namelen = memdup(&info->name, authptr->name, authptr->name_length); + if(info->namelen) + ret = compute_auth(info, authptr, sockname); + if(!ret) + { + free(info->name); + info->name = 0; + info->namelen = 0; + } + XauDisposeAuth(authptr); + return ret; +} + +static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port); +static int _xcb_open_unix(char *protocol, const char *file); +#ifdef DNETCONN +static int _xcb_open_decnet(const char *host, char *protocol, const unsigned short port); +#endif + +static int _xcb_open(char *host, char *protocol, const int display) +{ + int fd; + static const char base[] = "/tmp/.X11-unix/X"; + char file[sizeof(base) + 20]; + + if(*host) + { +#ifdef DNETCONN + /* DECnet displays have two colons, so _xcb_parse_display will have + left one at the end. However, an IPv6 address can end with *two* + colons, so only treat this as a DECnet display if host ends with + exactly one colon. */ + char *colon = strchr(host, ':'); + if(colon && *(colon+1) == '\0') + { + *colon = '\0'; + return _xcb_open_decnet(host, protocol, display); + } + else +#endif + if (protocol + || strcmp("unix",host)) { /* follow the old unix: rule */ + + /* display specifies TCP */ + unsigned short port = X_TCP_PORT + display; + return _xcb_open_tcp(host, protocol, port); + } + } + + /* display specifies Unix socket */ + snprintf(file, sizeof(file), "%s%d", base, display); + return _xcb_open_unix(protocol, file); + + + return fd; +} + +#ifdef DNETCONN +static int _xcb_open_decnet(const char *host, const char *protocol, const unsigned short port) +{ + int fd; + struct sockaddr_dn addr; + struct accessdata_dn accessdata; + struct nodeent *nodeaddr = getnodebyname(host); + + if(!nodeaddr) + return -1; + if (protocol && strcmp("dnet",protocol)) + return -1; + addr.sdn_family = AF_DECnet; + + addr.sdn_add.a_len = nodeaddr->n_length; + memcpy(addr.sdn_add.a_addr, nodeaddr->n_addr, addr.sdn_add.a_len); + + sprintf((char *)addr.sdn_objname, "X$X%d", port); + addr.sdn_objnamel = strlen((char *)addr.sdn_objname); + addr.sdn_objnum = 0; + + fd = socket(PF_DECnet, SOCK_STREAM, 0); + if(fd == -1) + return -1; + + memset(&accessdata, 0, sizeof(accessdata)); + sprintf((char*)accessdata.acc_acc, "%d", getuid()); + accessdata.acc_accl = strlen((char *)accessdata.acc_acc); + setsockopt(fd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata)); + + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} +#endif + +static int _xcb_open_tcp(char *host, char *protocol, const unsigned short port) +{ + int fd = -1; + struct addrinfo hints = { 0 +#ifdef AI_ADDRCONFIG + | AI_ADDRCONFIG +#endif +#ifdef AI_NUMERICSERV + | AI_NUMERICSERV +#endif + , AF_UNSPEC, SOCK_STREAM }; + char service[6]; /* "65535" with the trailing '\0' */ + struct addrinfo *results, *addr; + char *bracket; + + if (protocol && strcmp("tcp",protocol)) + return -1; + +#ifdef AF_INET6 + /* Allow IPv6 addresses enclosed in brackets. */ + if(host[0] == '[' && (bracket = strrchr(host, ']')) && bracket[1] == '\0') + { + *bracket = '\0'; + ++host; + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_INET6; + } +#endif + + snprintf(service, sizeof(service), "%hu", port); + if(getaddrinfo(host, service, &hints, &results)) + /* FIXME: use gai_strerror, and fill in error connection */ + return -1; + + for(addr = results; addr; addr = addr->ai_next) + { + fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if(fd >= 0 && connect(fd, addr->ai_addr, addr->ai_addrlen) >= 0) + break; + fd = -1; + } + freeaddrinfo(results); + return fd; +} + +static int _xcb_open_unix(char *protocol, const char *file) +{ + int fd; + struct sockaddr_un addr; + + if (protocol && strcmp("unix",protocol)) + return -1; + + strcpy(addr.sun_path, file); + addr.sun_family = AF_UNIX; +#if HAVE_SOCKADDR_SUN_LEN + addr.sun_len = SUN_LEN(&addr); +#endif + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd == -1) + return -1; + if(connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + return -1; + return fd; +} + +xcb_connection_t * +connect_to_display (const char *name, + xcb_auth_info_t *auth) +{ + int fd, len, screen, display = 0; + char *host; + char *protocol = NULL; + char *slash; + xcb_connection_t *c; + + slash = strrchr(name, '/'); + if (slash) { + len = slash - name; + protocol = malloc(len + 1); + if(!protocol) + return 0; + memcpy (protocol, name, len); + (protocol)[len] = '\0'; + } + + if (!xcb_parse_display (name, &host, &display, &screen)) + return NULL; + + fd = _xcb_open (host, protocol, display); + free (host); + + if (fd == -1) + return NULL; + + if (_get_auth_info (fd, auth, display)) + { + c = xcb_connect_to_fd (fd, auth); + } + else + { + c = xcb_connect_to_fd (fd, 0); + auth->name = NULL; + auth->data = NULL; + } + + return c; +} + +void +append_auth_info (DBusMessageIter *iter, + xcb_auth_info_t *auth) +{ + DBusMessageIter subiter; + int i; + + dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &subiter); + for (i = 0; i < auth->namelen; i++) + dbus_message_iter_append_basic (&subiter, + DBUS_TYPE_BYTE, + &auth->name[i]); + dbus_message_iter_close_container (iter, &subiter); + + dbus_message_iter_open_container (iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &subiter); + for (i = 0; i < auth->datalen; i++) + dbus_message_iter_append_basic (&subiter, + DBUS_TYPE_BYTE, + &auth->data[i]); + dbus_message_iter_close_container (iter, &subiter); +} + +static const unsigned int hexvalues[256] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 9 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 19 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 29 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 39 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, /* 49 */ + 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, /* 59 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xb, 0xb, 0xd, 0xe, /* 69 */ + 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 79 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 89 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xb, 0xc, /* 99 */ + 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +int +main (int argc, char **argv) +{ + DBusError err; + DBusConnection *conn; + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + int i, ret, fd, len, screen_num, display = 0; + char *host; + char *protocol = NULL; + char *slash; + xcb_connection_t *c = NULL; + xcb_auth_info_t auth = { 0 }; + char *displayname = NULL; + char *name = NULL; + char *auth_name = NULL; + char *auth_data = NULL; + int dmxdisplay = 0; + int dmxscreen = -1; + int viewonly = 0; + uint32_t window = 0; + uint32_t screen = 0; + dbus_bool_t core = TRUE; + char dest[256]; + char path[256]; + uint32_t index; + + for (i = 1; i < argc; i++) + { + if (*argv[i] == '-') + { + if (strcmp (argv[i], "-display") == 0) + { + if (++i < argc) + dmxdisplay = strtol (argv[i], NULL, 0); + } + else if (strcmp (argv[i], "-screen") == 0) + { + if (++i < argc) + dmxscreen = strtol (argv[i], NULL, 0); + } + else if (strcmp (argv[i], "-window") == 0) + { + if (++i < argc) + window = strtol (argv[i], NULL, 0); + } + else if (strcmp (argv[i], "-name") == 0) + { + if (++i < argc) + name = argv[i]; + } + else if (strcmp (argv[i], "-authtype") == 0) + { + if (++i < argc) + auth_name = argv[i]; + } + else if (strcmp (argv[i], "-authdata") == 0) + { + if (++i < argc) + auth_data = argv[i]; + } + else if (strcmp (argv[i], "-viewonly") == 0) + { + viewonly = TRUE; + } + else + { + break; + } + } + else if (!displayname) + { + displayname = argv[i]; + } + } + + if (i < argc || !displayname) + { + fprintf (stderr, + "usage: %s " + "[-display <Xdmx-display>] " + "[-screen <Xdmx-screen>] " + "[-window <wid>] " + "[-name <name>] " + "[-authtype <protoname>] " + "[-authdata <hexkey>] " + "[-viewonly] " + "host[:port]\n", + argv[0]); + return 1; + } + + dbus_error_init (&err); + + conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set (&err)) + { + fprintf (stderr, "DBus Error: %s\n", err.message); + dbus_error_free (&err); + + return 1; + } + + if (!xcb_parse_display (displayname, &host, &display, &screen_num)) + { + fprintf (stderr, "Bad display name: %s\n", displayname); + return 1; + } + + if (!name) + { + name = host; + if (!name) + name = "localhost"; + } + + slash = strrchr(displayname, '/'); + if (slash) { + len = slash - displayname; + protocol = malloc(len + 1); + if(!protocol) + { + fprintf (stderr, "Not enough memory\n"); + free (host); + return 1; + } + memcpy (protocol, displayname, len); + (protocol)[len] = '\0'; + } + + fd = _xcb_open (host, protocol, display); + + if (protocol) + free (protocol); + + if (fd == -1) + { + fprintf (stderr, "Can't open socket: %s\n", displayname); + free (host); + return 1; + } + + auth.namelen = 0; + auth.datalen = 0; + + if (auth_name && auth_data) + { + char *data, *ptr, *hexdata = auth_data; + int size; + + size = strlen (hexdata) / 2; + data = ptr = malloc (size); + if (data) + { + int j; + + for (j = 0; j < size; j++) + { + *ptr++ = (char) + ((hexvalues[(int) hexdata[0]] * 16) + + (hexvalues[(int) hexdata[1]])); + hexdata += 2; + } + + auth.namelen = strlen (auth_name); + auth.name = strdup (auth_name); + + auth.datalen = size; + auth.data = data; + + c = xcb_connect_to_fd (fd, &auth); + if (!c) + { + free (auth.name); + free (auth.data); + auth.namelen = 0; + auth.datalen = 0; + } + } + } + + if (!c) + { + if (_get_auth_info (fd, &auth, display)) + { + c = xcb_connect_to_fd (fd, &auth); + if (!c) + { + free (auth.name); + free (auth.data); + auth.namelen = 0; + auth.datalen = 0; + } + } + else + { + c = xcb_connect_to_fd (fd, 0); + } + + if (!c) + { + fprintf (stderr, "Can't open display: %s\n", displayname); + free (host); + return 1; + } + } + + sprintf (dest, "org.x.config.display%d", dmxdisplay); + sprintf (path, "/org/x/config/dmx/%d", dmxdisplay); + + if (!name) + name = host; + + if (dmxscreen >= 0) + screen = dmxscreen; + + do + { + message = dbus_message_new_method_call (dest, + path, + "org.x.config.dmx", + "attachScreen"); + if (!message) + { + dbus_set_error (&err, + DBUS_ERROR_NO_MEMORY, + "Not enough memory"); + break; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_UINT32, + &screen); + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &displayname); + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &name); + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_UINT32, + &window); + + append_auth_info (&iter, &auth); + + reply = dbus_connection_send_with_reply_and_block (conn, + message, + -1, + &err); + + dbus_message_unref (message); + + if (dbus_error_is_set (&err)) + { + if (dmxscreen < 0) + { + if (strcmp (err.name, DMX_ERROR_SCREEN_IN_USE) == 0) + { + dbus_error_free (&err); + dbus_error_init (&err); + + screen++; /* try next screen */ + } + else + { + if (strcmp (err.name, DMX_ERROR_INVALID_SCREEN) == 0) + { + dbus_error_free (&err); + dbus_error_init (&err); + + dbus_set_error (&err, + DMX_ERROR_SCREEN_IN_USE, + "No available screens on display %d", + dmxdisplay); + } + + break; + } + } + else + { + break; + } + } + } while (!reply); + + xcb_disconnect (c); + + if (dbus_error_is_set (&err)) + { + fprintf (stderr, "Error: %s\n", err.message); + dbus_error_free (&err); + + return 1; + } + + dbus_message_unref (reply); + + /* failing to add input is not an error */ + if (!viewonly) + { + message = dbus_message_new_method_call (dest, + path, + "org.x.config.dmx", + "addInput"); + if (!message) + { + fprintf (stderr, "Warning: addInput: Not enough memory\n"); + return 0; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_UINT32, + &screen); + + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_BOOLEAN, + &core); + + reply = dbus_connection_send_with_reply_and_block (conn, + message, + -1, + &err); + + dbus_message_unref (message); + + if (dbus_error_is_set (&err)) + { + fprintf (stderr, "Warning: addInput: %s\n", err.message); + dbus_error_free (&err); + + return 0; + } + + dbus_message_unref (reply); + } + + message = dbus_message_new_method_call (dest, + path, + "org.x.config.dmx", + "enableScreen"); + if (!message) + { + fprintf (stderr, "Warning: enableScreen: Not enough memory\n"); + return 0; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_UINT32, + &screen); + + if (dbus_connection_send (conn, message, NULL)) + dbus_connection_flush (conn); + else + fprintf (stderr, "Warning: enableScreen failed\n"); + + dbus_message_unref (message); + + return 0; +} diff --git a/hw/dmx/examples/dmxresize.c b/hw/dmx/examples/dmxresize.c index caed91d..6110b97 100644 --- a/hw/dmx/examples/dmxresize.c +++ b/hw/dmx/examples/dmxresize.c @@ -100,5 +100,5 @@ int main(int argc, char **argv) } XCloseDisplay(display); - return 0; + return (status == Success) ? 0 : -1; } diff --git a/hw/dmx/examples/dmxrminput.c b/hw/dmx/examples/dmxrminput.c index ef62cab..defe68d 100644 --- a/hw/dmx/examples/dmxrminput.c +++ b/hw/dmx/examples/dmxrminput.c @@ -74,5 +74,5 @@ int main(int argc, char **argv) printf("status = %d\n", status); XCloseDisplay(display); - return 0; + return status ? 0 : -1; } diff --git a/hw/dmx/examples/dmxrmscreen.c b/hw/dmx/examples/dmxrmscreen.c index fecf0f6..59a38d6 100644 --- a/hw/dmx/examples/dmxrmscreen.c +++ b/hw/dmx/examples/dmxrmscreen.c @@ -73,8 +73,12 @@ int main(int argc, char **argv) major_version, minor_version, patch_version); if (!DMXRemoveScreen(display, screenNum)) + { printf("Failed to remove screen #%d\n", screenNum); - + XCloseDisplay(display); + return -1; + } + XCloseDisplay(display); return 0; } diff --git a/hw/dmx/examples/xinput.c b/hw/dmx/examples/xinput.c index 74353a9..c930e17 100644 --- a/hw/dmx/examples/xinput.c +++ b/hw/dmx/examples/xinput.c @@ -77,7 +77,8 @@ static void printdmxinfo(Display *display, int id) case DMXBackendInputType: if (iinf.physicalId >= 0) { if ((backend = XOpenDisplay(iinf.name))) { - XExtensionVersion *ext = XGetExtensionVersion(backend, INAME); + XExtensionVersion *ext = + XQueryInputVersion (backend, XI_2_Major, XI_2_Minor); if (ext && ext != (XExtensionVersion *)NoSuchExtension) { int count, i; XDeviceInfo *devInfo = XListInputDevices(backend, &count); @@ -136,7 +137,7 @@ int main(int argc, char **argv) return -1; } - ext = XGetExtensionVersion(display, INAME); + ext = XQueryInputVersion (display, XI_2_Major, XI_2_Minor); if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { printf("No XInputExtension\n"); return -1; diff --git a/hw/dmx/glxProxy/glxsingle.c b/hw/dmx/glxProxy/glxsingle.c index 27a27c3..8a4fa48 100644 --- a/hw/dmx/glxProxy/glxsingle.c +++ b/hw/dmx/glxProxy/glxsingle.c @@ -826,10 +826,10 @@ int __glXDisp_ReadPixels(__GLXclientState *cl, GLbyte *pc) for (s=from_screen; s<=to_screen; s++) { DMXScreenInfo *dmxScreen = &dmxScreens[s]; Display *dpy = GetBackEndDisplay(cl,s); - int scr_x1 = dmxScreen->rootXOrigin; - int scr_x2 = dmxScreen->rootXOrigin + dmxScreen->scrnWidth - 1; - int scr_y1 = dmxScreen->rootYOrigin; - int scr_y2 = dmxScreen->rootYOrigin + dmxScreen->scrnHeight - 1; + int scr_x1 = 0; + int scr_x2 = dmxScreen->scrnWidth - 1; + int scr_y1 = 0; + int scr_y2 = dmxScreen->scrnHeight - 1; int wx1, wx2, wy1, wy2; int sx, sy, sw, sh; int npixels; diff --git a/hw/kdrive/fake/Makefile.am b/hw/kdrive/fake/Makefile.am index 76ed9fc..3c1464b 100644 --- a/hw/kdrive/fake/Makefile.am +++ b/hw/kdrive/fake/Makefile.am @@ -18,8 +18,7 @@ Xfake_SOURCES = \ Xfake_LDADD = \ libfake.a \ - @KDRIVE_LIBS@ \ - @XSERVER_LIBS@ + @KDRIVE_LIBS@ Xfake_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) diff --git a/hw/kdrive/fake/fake.c b/hw/kdrive/fake/fake.c index d77c4f1..a7b3425 100644 --- a/hw/kdrive/fake/fake.c +++ b/hw/kdrive/fake/fake.c @@ -59,8 +59,10 @@ fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) { if (!screen->width || !screen->height) { - screen->width = 1024; - screen->height = 768; + screen->width = 800; + screen->height = 600; + screen->width_mm = 212; + screen->height_mm = 159; screen->rate = 72; } @@ -70,7 +72,7 @@ fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) screen->height = 1; if (!screen->fb[0].depth) - screen->fb[0].depth = 16; + screen->fb[0].depth = 24; if (screen->fb[0].depth <= 8) { diff --git a/hw/kdrive/fake/fakeinit.c b/hw/kdrive/fake/fakeinit.c index 2cfcbed..65699b9 100644 --- a/hw/kdrive/fake/fakeinit.c +++ b/hw/kdrive/fake/fakeinit.c @@ -78,6 +78,72 @@ OsVendorInit (void) KdOsInit (&FakeOsFuncs); } +static Bool +fakeRealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + return TRUE; +} + +static Bool +fakeUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + return TRUE; +} + +static void +fakeSetCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor, + int x, + int y) +{ +} + +static void +fakeMoveCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + int x, + int y) +{ +} + +static Bool +fakeDeviceCursorInitialize (DeviceIntPtr pDev, + ScreenPtr pScreen) +{ + return TRUE; +} + +static void +fakeDeviceCursorCleanup (DeviceIntPtr pDev, + ScreenPtr pScreen) +{ +} + +static miPointerSpriteFuncRec fakePointerSpriteFuncs = { + fakeRealizeCursor, + fakeUnrealizeCursor, + fakeSetCursor, + fakeMoveCursor, + fakeDeviceCursorInitialize, + fakeDeviceCursorCleanup +}; + +static Bool +fakeCursorInit (ScreenPtr pScreen) +{ + miPointerInitialize (pScreen, + &fakePointerSpriteFuncs, + &kdPointerScreenFuncs, + FALSE); + + return TRUE; +} + KdCardFuncs fakeFuncs = { fakeCardInit, /* cardinit */ fakeScreenInit, /* scrinit */ @@ -91,8 +157,8 @@ KdCardFuncs fakeFuncs = { fakeRestore, /* restore */ fakeScreenFini, /* scrfini */ fakeCardFini, /* cardfini */ - - 0, /* initCursor */ + + fakeCursorInit, /* initCursor */ 0, /* enableCursor */ 0, /* disableCursor */ 0, /* finiCursor */ diff --git a/hw/kdrive/fake/os.c b/hw/kdrive/fake/os.c index 76cd9e7..221a7c1 100644 --- a/hw/kdrive/fake/os.c +++ b/hw/kdrive/fake/os.c @@ -25,15 +25,248 @@ #endif #include "fake.h" +#include <errno.h> +#include <signal.h> +#include <linux/vt.h> +#include <linux/kd.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +static int vtno; +int LinuxConsoleFd; +static int activeVT; +static Bool enabled; + +static void +LinuxVTRequest (int sig) +{ + kdSwitchPending = TRUE; +} + +/* Check before chowning -- this avoids touching the file system */ +static void +LinuxCheckChown (char *file) +{ + struct stat st; + __uid_t u; + __gid_t g; + + if (stat (file, &st) < 0) + return; + u = getuid (); + g = getgid (); + if (st.st_uid != u || st.st_gid != g) + chown (file, u, g); +} + +static int +LinuxInit (void) +{ + int fd = -1; + char vtname[11]; + struct vt_stat vts; + + LinuxConsoleFd = -1; + /* check if we're run with euid==0 */ + if (geteuid() != 0) + { + FatalError("LinuxInit: Server must be suid root\n"); + } + + vtno = kdVirtualTerminal; + + close(fd); + + sprintf(vtname,"/dev/tty%d",vtno); /* /dev/tty1-64 */ + + if ((LinuxConsoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) < 0) + { + FatalError("LinuxInit: Cannot open %s (%s)\n", + vtname, strerror(errno)); + } + + /* change ownership of the vt */ + LinuxCheckChown (vtname); + + /* + * the current VT device we're running on is not "console", we want + * to grab all consoles too + * + * Why is this needed? + */ + LinuxCheckChown ("/dev/tty0"); + /* + * Linux doesn't switch to an active vt after the last close of a vt, + * so we do this ourselves by remembering which is active now. + */ + memset (&vts, '\0', sizeof (vts)); /* valgrind */ + if (ioctl(LinuxConsoleFd, VT_GETSTATE, &vts) == 0) + { + activeVT = vts.v_active; + } + + return 1; +} + +static void +LinuxSetSwitchMode (int mode) +{ + struct sigaction act; + struct vt_mode VT; + + if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) < 0) + { + FatalError ("LinuxInit: VT_GETMODE failed\n"); + } + + if (mode == VT_PROCESS) + { + act.sa_handler = LinuxVTRequest; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGUSR1, &act, 0); + + VT.mode = mode; + VT.relsig = SIGUSR1; + VT.acqsig = SIGUSR1; + } + else + { + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGUSR1, &act, 0); + + VT.mode = mode; + VT.relsig = 0; + VT.acqsig = 0; + } + if (ioctl(LinuxConsoleFd, VT_SETMODE, &VT) < 0) + { + FatalError("LinuxInit: VT_SETMODE failed\n"); + } +} + +#ifdef FNONBLOCK +#define NOBLOCK FNONBLOCK +#else +#define NOBLOCK FNDELAY +#endif + +static void +LinuxEnable (void) +{ + if (enabled) + return; + if (kdSwitchPending) + { + kdSwitchPending = FALSE; + ioctl (LinuxConsoleFd, VT_RELDISP, VT_ACKACQ); + } + + /* + * now get the VT + */ + LinuxSetSwitchMode (VT_AUTO); + if (ioctl(LinuxConsoleFd, VT_ACTIVATE, vtno) != 0) + { + FatalError("LinuxInit: VT_ACTIVATE failed\n"); + } + if (ioctl(LinuxConsoleFd, VT_WAITACTIVE, vtno) != 0) + { + FatalError("LinuxInit: VT_WAITACTIVE failed\n"); + } + LinuxSetSwitchMode (VT_PROCESS); + if (ioctl(LinuxConsoleFd, KDSETMODE, KD_GRAPHICS) < 0) + { + FatalError("LinuxInit: KDSETMODE KD_GRAPHICS failed\n"); + } + enabled = TRUE; +} + +static void +LinuxDisable (void) +{ + ioctl(LinuxConsoleFd, KDSETMODE, KD_TEXT); /* Back to text mode ... */ + if (kdSwitchPending) + { + kdSwitchPending = FALSE; + ioctl (LinuxConsoleFd, VT_RELDISP, 1); + } + enabled = FALSE; +} + +static void +LinuxFini (void) +{ + struct vt_mode VT; + struct vt_stat vts; + int fd; + + if (LinuxConsoleFd < 0) + return; + + if (ioctl(LinuxConsoleFd, VT_GETMODE, &VT) != -1) + { + VT.mode = VT_AUTO; + ioctl(LinuxConsoleFd, VT_SETMODE, &VT); /* set dflt vt handling */ + } + memset (&vts, '\0', sizeof (vts)); /* valgrind */ + ioctl (LinuxConsoleFd, VT_GETSTATE, &vts); + if (vtno == vts.v_active) + { + /* + * Find a legal VT to switch to, either the one we started from + * or the lowest active one that isn't ours + */ + if (activeVT < 0 || + activeVT == vts.v_active || + !(vts.v_state & (1 << activeVT))) + { + for (activeVT = 1; activeVT < 16; activeVT++) + if (activeVT != vtno && (vts.v_state & (1 << activeVT))) + break; + if (activeVT == 16) + activeVT = -1; + } + /* + * Perform a switch back to the active VT when we were started + */ + if (activeVT >= -1) + { + ioctl (LinuxConsoleFd, VT_ACTIVATE, activeVT); + ioctl (LinuxConsoleFd, VT_WAITACTIVE, activeVT); + activeVT = -1; + } + } + close(LinuxConsoleFd); /* make the vt-manager happy */ + LinuxConsoleFd = -1; + fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0); + if (fd >= 0) + { + memset (&vts, '\0', sizeof (vts)); /* valgrind */ + ioctl (fd, VT_GETSTATE, &vts); + if (ioctl (fd, VT_DISALLOCATE, vtno) < 0) + fprintf (stderr, "Can't deallocate console %d %s\n", vtno, strerror(errno)); + close (fd); + } + return; +} + static int FakeInit (void) { + if (kdVirtualTerminal >= 0) + return LinuxInit (); + return 1; } static void FakeEnable (void) { + if (kdVirtualTerminal >= 0) + LinuxEnable (); } static Bool @@ -45,11 +278,15 @@ FakeSpecialKey (KeySym sym) static void FakeDisable (void) { + if (kdVirtualTerminal >= 0) + LinuxDisable (); } static void FakeFini (void) { + if (kdVirtualTerminal >= 0) + return LinuxFini (); } KdOsFuncs FakeOsFuncs = { diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c index e31cc25..f96c2e8 100644 --- a/hw/kdrive/src/kdrive.c +++ b/hw/kdrive/src/kdrive.c @@ -55,7 +55,7 @@ typedef struct _kdDepths { KdDepths kdDepths[] = { { 1, 1 }, - { 4, 4 }, + { 4, 8 }, { 8, 8 }, { 15, 16 }, { 16, 16 }, @@ -1394,6 +1394,7 @@ OsVendorFatalError(void) int DPMSSet(ClientPtr client, int level) { + return -1; } int diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 6400b69..1616191 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -406,6 +406,9 @@ /* Support HAL for hotplug */ #undef CONFIG_HAL +/* Support Avahi */ +#undef HAVE_AVAHI + /* Use only built-in fonts */ #undef BUILTIN_FONTS diff --git a/include/window.h b/include/window.h index 04cbe26..0b08548 100644 --- a/include/window.h +++ b/include/window.h @@ -268,5 +268,7 @@ extern void DisableMapUnmapEvents( WindowPtr /* pWin */ ); extern void EnableMapUnmapEvents( WindowPtr /* pWin */ ); +extern Bool MapUnmapEventsEnabled( + WindowPtr /* pWin */ ); #endif /* WINDOW_H */ diff --git a/mi/miinitext.c b/mi/miinitext.c index 6516f43..22ecbe1 100644 --- a/mi/miinitext.c +++ b/mi/miinitext.c @@ -49,6 +49,10 @@ SOFTWARE. #include <dix-config.h> #endif +#ifndef XINPUT +#define XINPUT +#endif + #ifdef HAVE_XORG_CONFIG_H #include <xorg-config.h> #endif diff --git a/miext/damage/damage.c b/miext/damage/damage.c index 56864c5..9155e98 100755 --- a/miext/damage/damage.c +++ b/miext/damage/damage.c @@ -1411,11 +1411,17 @@ damageText (DrawablePtr pDrawable, damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n, charinfo, imageblt, pGC->subWindowMode); if (imageblt) - (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, - FONTGLYPHS(pGC->font)); + { + if (pGC->ops->ImageGlyphBlt) + (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); + } else - (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, - FONTGLYPHS(pGC->font)); + { + if (pGC->ops->PolyGlyphBlt) + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); + } } xfree(charinfo); return x + w; @@ -1432,8 +1438,12 @@ damagePolyText8(DrawablePtr pDrawable, DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage (pDrawable, pGC)) + { x = damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, Linear8Bit, TT_POLY8); + if (!pGC->ops->PolyGlyphBlt) + (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); + } else x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); damageReportPostOp (pDrawable); @@ -1452,9 +1462,13 @@ damagePolyText16(DrawablePtr pDrawable, DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage (pDrawable, pGC)) + { x = damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, TT_POLY16); + if (!pGC->ops->PolyGlyphBlt) + (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); + } else x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); damageReportPostOp (pDrawable); @@ -1473,8 +1487,12 @@ damageImageText8(DrawablePtr pDrawable, DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage (pDrawable, pGC)) + { damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, Linear8Bit, TT_IMAGE8); + if (!pGC->ops->ImageGlyphBlt) + (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); + } else (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); damageReportPostOp (pDrawable); @@ -1492,9 +1510,13 @@ damageImageText16(DrawablePtr pDrawable, DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); if (checkGCDamage (pDrawable, pGC)) + { damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, TT_IMAGE16); + if (!pGC->ops->ImageGlyphBlt) + (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); + } else (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); damageReportPostOp (pDrawable); diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index 7c22437..d7da059 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -24,6 +24,10 @@ #include "swaprep.h" #include "registry.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + RESTYPE RRCrtcType; /* @@ -795,13 +799,23 @@ ProcRRSetCrtcConfig (ClientPtr client) { int source_width = mode->mode.width; int source_height = mode->mode.height; + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif if ((rotation & 0xf) == RR_Rotate_90 || (rotation & 0xf) == RR_Rotate_270) { source_width = mode->mode.height; source_height = mode->mode.width; } - if (stuff->x + source_width > pScreen->width) + if (stuff->x + source_width > w) { client->errorValue = stuff->x; if (outputs) @@ -809,7 +823,7 @@ ProcRRSetCrtcConfig (ClientPtr client) return BadValue; } - if (stuff->y + source_height > pScreen->height) + if (stuff->y + source_height > h) { client->errorValue = stuff->y; if (outputs) diff --git a/randr/rrscreen.c b/randr/rrscreen.c index f391973..f51094e 100644 --- a/randr/rrscreen.c +++ b/randr/rrscreen.c @@ -22,6 +22,10 @@ #include "randrstr.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + extern char *ConnectionInfo; static int padlength[4] = {0, 3, 2, 1}; @@ -44,6 +48,16 @@ RREditConnectionInfo (ScreenPtr pScreen) xVisualType *visual; int screen = 0; int d; + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif connSetup = (xConnSetup *) ConnectionInfo; vendor = (char *) connSetup + sizeof (xConnSetup); @@ -66,8 +80,8 @@ RREditConnectionInfo (ScreenPtr pScreen) root = (xWindowRoot *) ((char *) depth); screen++; } - root->pixWidth = pScreen->width; - root->pixHeight = pScreen->height; + root->pixWidth = w; + root->pixHeight = h; root->mmWidth = pScreen->mmWidth; root->mmHeight = pScreen->mmHeight; } @@ -77,6 +91,8 @@ RRSendConfigNotify (ScreenPtr pScreen) { WindowPtr pWin = WindowTable[pScreen->myNum]; xEvent event; + int w = pWin->drawable.width; + int h = pWin->drawable.height; event.u.u.type = ConfigureNotify; event.u.configureNotify.window = pWin->drawable.id; @@ -84,10 +100,16 @@ RRSendConfigNotify (ScreenPtr pScreen) event.u.configureNotify.x = 0; event.u.configureNotify.y = 0; - /* XXX xinerama stuff ? */ - - event.u.configureNotify.width = pWin->drawable.width; - event.u.configureNotify.height = pWin->drawable.height; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif + + event.u.configureNotify.width = w; + event.u.configureNotify.height = h; event.u.configureNotify.borderWidth = wBorderWidth (pWin); event.u.configureNotify.override = pWin->overrideRedirect; DeliverEvents(pWin, &event, 1, NullWindow); @@ -100,6 +122,16 @@ RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) xRRScreenChangeNotifyEvent se; RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL; WindowPtr pRoot = WindowTable[pScreen->myNum]; + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif se.type = RRScreenChangeNotify + RREventBase; se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0); @@ -118,13 +150,13 @@ RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) se.sizeID = RR10CurrentSizeID (pScreen); if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) { - se.widthInPixels = pScreen->height; - se.heightInPixels = pScreen->width; + se.widthInPixels = h; + se.heightInPixels = w; se.widthInMillimeters = pScreen->mmHeight; se.heightInMillimeters = pScreen->mmWidth; } else { - se.widthInPixels = pScreen->width; - se.heightInPixels = pScreen->height; + se.widthInPixels = w; + se.heightInPixels = h; se.widthInMillimeters = pScreen->mmWidth; se.heightInMillimeters = pScreen->mmHeight; } @@ -140,19 +172,31 @@ RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) void RRScreenSizeNotify (ScreenPtr pScreen) { + int w = pScreen->width; + int h = pScreen->height; + rrScrPriv(pScreen); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif + /* * Deliver ConfigureNotify events when root changes * pixel size */ - if (pScrPriv->width == pScreen->width && - pScrPriv->height == pScreen->height && + if (pScrPriv->width == w && + pScrPriv->height == h && pScrPriv->mmWidth == pScreen->mmWidth && pScrPriv->mmHeight == pScreen->mmHeight) return; - pScrPriv->width = pScreen->width; - pScrPriv->height = pScreen->height; + pScrPriv->width = w; + pScrPriv->height = h; pScrPriv->mmWidth = pScreen->mmWidth; pScrPriv->mmHeight = pScreen->mmHeight; pScrPriv->changed = TRUE; @@ -741,7 +785,7 @@ ProcRRSetScreenConfig (ClientPtr client) RRModePtr mode; RR10DataPtr pData = NULL; RRScreenSizePtr pSize; - int width, height; + int width, height, w, h; UpdateCurrentTime (); @@ -896,7 +940,19 @@ ProcRRSetScreenConfig (ClientPtr client) width = mode->mode.height; height = mode->mode.width; } - if (width != pScreen->width || height != pScreen->height) + + w = pScreen->width; + h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif + + if (width != w || height != h) { int c; @@ -960,6 +1016,16 @@ RR10CurrentSizeID (ScreenPtr pScreen) { CARD16 sizeID = 0xffff; RROutputPtr output = RRFirstOutput (pScreen); + int w = pScreen->width; + int h = pScreen->height; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + w = PanoramiXPixWidth; + h = PanoramiXPixHeight; + } +#endif if (output) { @@ -968,8 +1034,8 @@ RR10CurrentSizeID (ScreenPtr pScreen) { int i; for (i = 0; i < data->nsize; i++) - if (data->sizes[i].width == pScreen->width && - data->sizes[i].height == pScreen->height) + if (data->sizes[i].width == w && + data->sizes[i].height == h) { sizeID = (CARD16) i; break; diff --git a/render/animcur.c b/render/animcur.c index 362607f..354987c 100644 --- a/render/animcur.c +++ b/render/animcur.c @@ -47,16 +47,6 @@ #include "inputstr.h" #include "xace.h" -typedef struct _AnimCurElt { - CursorPtr pCursor; /* cursor to show */ - CARD32 delay; /* in ms */ -} AnimCurElt; - -typedef struct _AnimCur { - int nelt; /* number of elements in the elts array */ - AnimCurElt *elts; /* actually allocated right after the structure */ -} AnimCurRec, *AnimCurPtr; - typedef struct _AnimScrPriv { CursorPtr pCursor; int elt; @@ -86,15 +76,13 @@ static AnimCurStateRec animCurState[MAX_DEVICES]; static unsigned char empty[4]; -static CursorBits animCursorBits = { +CursorBits animCursorBits = { empty, empty, 2, 1, 1, 0, 0, 1 }; static int AnimCurGeneration; static DevPrivateKey AnimCurScreenPrivateKey = &AnimCurScreenPrivateKey; -#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) -#define GetAnimCur(c) ((AnimCurPtr) ((c) + 1)) #define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) #define GetAnimCurScreenIfSet(s) GetAnimCurScreen(s) #define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) @@ -286,10 +274,7 @@ AnimCurRealizeCursor (DeviceIntPtr pDev, Bool ret; Unwrap (as, pScreen, RealizeCursor); - if (IsAnimCur(pCursor)) - ret = TRUE; - else - ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); + ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); return ret; } @@ -303,6 +288,7 @@ AnimCurUnrealizeCursor (DeviceIntPtr pDev, Bool ret; Unwrap (as, pScreen, UnrealizeCursor); + ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); if (IsAnimCur(pCursor)) { AnimCurPtr ac = GetAnimCur(pCursor); @@ -311,10 +297,7 @@ AnimCurUnrealizeCursor (DeviceIntPtr pDev, if (pScreen->myNum == 0) for (i = 0; i < ac->nelt; i++) FreeCursor (ac->elts[i].pCursor, 0); - ret = TRUE; } - else - ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); return ret; } @@ -379,9 +362,11 @@ AnimCurInit (ScreenPtr pScreen) int AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) { - CursorPtr pCursor; - int rc, i; - AnimCurPtr ac; + CursorPtr pCursor; + int rc, nscr, i; + AnimCurPtr ac; + ScreenPtr pscr; + DeviceIntPtr pDev; for (i = 0; i < screenInfo.numScreens; i++) if (!GetAnimCurScreenIfSet (screenInfo.screens[i])) @@ -433,7 +418,54 @@ AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *pp ac->elts[i].pCursor = cursors[i]; ac->elts[i].delay = deltas[i]; } - + + /* + * realize the cursor for every screen + * Do not change the refcnt, this will be changed when ChangeToCursor + * actually changes the sprite. + */ + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + if (!( *pscr->RealizeCursor)(pDev, pscr, pCursor)) + { + /* Realize failed for device pDev on screen pscr. + * We have to assume that for all devices before, realize + * worked. We need to rollback all devices so far on the + * current screen and then all devices on previous + * screens. + */ + DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ + while(pDevIt && pDevIt != pDev) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCursor); + pDevIt = pDevIt->next; + } + while (--nscr >= 0) + { + pscr = screenInfo.screens[nscr]; + /* now unrealize all devices on previous screens */ + pDevIt = inputInfo.devices; + while (pDevIt) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCursor); + pDevIt = pDevIt->next; + } + ( *pscr->UnrealizeCursor)(pDev, pscr, pCursor); + } + dixFreePrivates(pCursor->devPrivates); + xfree(pCursor); + return BadAlloc; + } + } + } + } *ppCursor = pCursor; return Success; } diff --git a/render/glyph.c b/render/glyph.c index de01970..e5bd1ca 100644 --- a/render/glyph.c +++ b/render/glyph.c @@ -422,6 +422,8 @@ AllocateGlyph (xGlyphInfo *gi, int fdepth) for (i = 0; i < screenInfo.numScreens; i++) { + *GetGlyphPrivatesForScreen (glyph, screenInfo.screens[i]) = NULL; + ps = GetPictureScreenIfSet (screenInfo.screens[i]); if (ps) diff --git a/render/picturestr.h b/render/picturestr.h index acd15c7..34632dc 100644 --- a/render/picturestr.h +++ b/render/picturestr.h @@ -26,6 +26,7 @@ #include "scrnintstr.h" #include "glyphstr.h" +#include "cursorstr.h" #include "resource.h" #include "privates.h" @@ -620,6 +621,22 @@ PictureGradientColor (PictGradientStopPtr stop1, void RenderExtensionInit (void); + +typedef struct _AnimCurElt { + CursorPtr pCursor; /* cursor to show */ + CARD32 delay; /* in ms */ +} AnimCurElt; + +typedef struct _AnimCur { + int nelt; /* number of elements in the elts array */ + AnimCurElt *elts; /* actually allocated right after the structure */ +} AnimCurRec, *AnimCurPtr; + +extern CursorBits animCursorBits; + +#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) +#define GetAnimCur(c) ((AnimCurPtr) ((c) + 1)) + Bool AnimCurInit (ScreenPtr pScreen); diff --git a/render/render.c b/render/render.c index 538697b..5a2e1d0 100644 --- a/render/render.c +++ b/render/render.c @@ -2736,6 +2736,8 @@ PanoramiXRenderCreatePicture (ClientPtr client) else newPict->u.pict.root = FALSE; + newPict->u.pict.sourcePict = FALSE; + for(j = 1; j < PanoramiXNumScreens; j++) newPict->info[j].id = FakeClientID(client->index); @@ -2766,10 +2768,18 @@ PanoramiXRenderChangePicture (ClientPtr client) VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess, RenderErrBase + BadPicture); - FOR_NSCREENS_BACKWARD(j) { - stuff->picture = pict->info[j].id; - result = (*PanoramiXSaveRenderVector[X_RenderChangePicture]) (client); - if(result != Success) break; + if (pict->u.pict.sourcePict) + { + stuff->picture = pict->info[0].id; + result = (*PanoramiXSaveRenderVector[X_RenderChangePicture]) (client); + } + else + { + FOR_NSCREENS_BACKWARD(j) { + stuff->picture = pict->info[j].id; + result = (*PanoramiXSaveRenderVector[X_RenderChangePicture]) (client); + if(result != Success) break; + } } return (result); @@ -2807,11 +2817,19 @@ PanoramiXRenderSetPictureTransform (ClientPtr client) VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess, RenderErrBase + BadPicture); - - FOR_NSCREENS_BACKWARD(j) { - stuff->picture = pict->info[j].id; - result = (*PanoramiXSaveRenderVector[X_RenderSetPictureTransform]) (client); - if(result != Success) break; + + if (pict->u.pict.sourcePict) + { + stuff->picture = pict->info[0].id; + result = (*PanoramiXSaveRenderVector[X_RenderSetPictureTransform]) (client); + } + else + { + FOR_NSCREENS_BACKWARD(j) { + stuff->picture = pict->info[j].id; + result = (*PanoramiXSaveRenderVector[X_RenderSetPictureTransform]) (client); + if(result != Success) break; + } } return (result); @@ -2830,9 +2848,9 @@ PanoramiXRenderSetPictureFilter (ClientPtr client) RenderErrBase + BadPicture); FOR_NSCREENS_BACKWARD(j) { - stuff->picture = pict->info[j].id; - result = (*PanoramiXSaveRenderVector[X_RenderSetPictureFilter]) (client); - if(result != Success) break; + stuff->picture = pict->info[j].id; + result = (*PanoramiXSaveRenderVector[X_RenderSetPictureFilter]) (client); + if(result != Success) break; } return (result); @@ -2853,10 +2871,18 @@ PanoramiXRenderFreePicture (ClientPtr client) RenderErrBase + BadPicture); - FOR_NSCREENS_BACKWARD(j) { - stuff->picture = pict->info[j].id; + if (pict->u.pict.sourcePict) + { + stuff->picture = pict->info[0].id; result = (*PanoramiXSaveRenderVector[X_RenderFreePicture]) (client); - if(result != Success) break; + } + else + { + FOR_NSCREENS_BACKWARD(j) { + stuff->picture = pict->info[j].id; + result = (*PanoramiXSaveRenderVector[X_RenderFreePicture]) (client); + if(result != Success) break; + } } /* Since ProcRenderFreePicture is using FreeResource, it will free @@ -3268,6 +3294,114 @@ PanoramiXRenderAddTraps (ClientPtr client) return result; } +static int +PanoramiXRenderCreateSolidFill (ClientPtr client) +{ + REQUEST(xRenderCreateSolidFillReq); + PanoramiXRes *newPict; + int result = Success, j; + + REQUEST_AT_LEAST_SIZE(xRenderCreateSolidFillReq); + if (!(newPict = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newPict->type = XRT_PICTURE; + for (j = 0; j < PanoramiXNumScreens; j++) + newPict->info[j].id = stuff->pid; + + newPict->u.pict.root = FALSE; + newPict->u.pict.sourcePict = TRUE; + + result = (*PanoramiXSaveRenderVector[X_RenderCreateSolidFill]) (client); + if (result == Success) + AddResource (newPict->info[0].id, XRT_PICTURE, newPict); + else + xfree (newPict); + + return result; +} + +static int +PanoramiXRenderCreateLinearGradient (ClientPtr client) +{ + REQUEST(xRenderCreateLinearGradientReq); + PanoramiXRes *newPict; + int result = Success, j; + + REQUEST_AT_LEAST_SIZE(xRenderCreateLinearGradientReq); + if (!(newPict = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newPict->type = XRT_PICTURE; + for (j = 0; j < PanoramiXNumScreens; j++) + newPict->info[j].id = stuff->pid; + + newPict->u.pict.root = FALSE; + newPict->u.pict.sourcePict = TRUE; + + result = (*PanoramiXSaveRenderVector[X_RenderCreateLinearGradient]) (client); + if (result == Success) + AddResource (newPict->info[0].id, XRT_PICTURE, newPict); + else + xfree (newPict); + + return result; +} + +static int +PanoramiXRenderCreateRadialGradient (ClientPtr client) +{ + REQUEST(xRenderCreateRadialGradientReq); + PanoramiXRes *newPict; + int result = Success, j; + + REQUEST_AT_LEAST_SIZE(xRenderCreateRadialGradientReq); + if (!(newPict = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newPict->type = XRT_PICTURE; + for (j = 0; j < PanoramiXNumScreens; j++) + newPict->info[j].id = stuff->pid; + + newPict->u.pict.root = FALSE; + newPict->u.pict.sourcePict = TRUE; + + result = (*PanoramiXSaveRenderVector[X_RenderCreateRadialGradient]) (client); + if (result == Success) + AddResource (newPict->info[0].id, XRT_PICTURE, newPict); + else + xfree (newPict); + + return result; +} + +static int +PanoramiXRenderCreateConicalGradient (ClientPtr client) +{ + REQUEST(xRenderCreateConicalGradientReq); + PanoramiXRes *newPict; + int result = Success, j; + + REQUEST_AT_LEAST_SIZE(xRenderCreateConicalGradientReq); + if (!(newPict = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newPict->type = XRT_PICTURE; + for (j = 0; j < PanoramiXNumScreens; j++) + newPict->info[j].id = stuff->pid; + + newPict->u.pict.root = FALSE; + newPict->u.pict.sourcePict = TRUE; + + result = (*PanoramiXSaveRenderVector[X_RenderCreateConicalGradient]) (client); + if (result == Success) + AddResource (newPict->info[0].id, XRT_PICTURE, newPict); + else + xfree (newPict); + + return result; +} + void PanoramiXRenderInit (void) { @@ -3296,6 +3430,10 @@ PanoramiXRenderInit (void) ProcRenderVector[X_RenderTriStrip] = PanoramiXRenderTriStrip; ProcRenderVector[X_RenderTriFan] = PanoramiXRenderTriFan; ProcRenderVector[X_RenderAddTraps] = PanoramiXRenderAddTraps; + ProcRenderVector[X_RenderCreateSolidFill] = PanoramiXRenderCreateSolidFill; + ProcRenderVector[X_RenderCreateLinearGradient] = PanoramiXRenderCreateLinearGradient; + ProcRenderVector[X_RenderCreateRadialGradient] = PanoramiXRenderCreateRadialGradient; + ProcRenderVector[X_RenderCreateConicalGradient] = PanoramiXRenderCreateConicalGradient; } void diff --git a/xfixes/region.c b/xfixes/region.c old mode 100644 new mode 100755 index cac24b5..3a90530 --- a/xfixes/region.c +++ b/xfixes/region.c @@ -864,3 +864,84 @@ SProcXFixesExpandRegion (ClientPtr client) return (*ProcXFixesVector[stuff->xfixesReqType]) (client); } +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" + +#define VERIFY_XIN_PICTURE(pPicture, pid, client, mode, err) {\ + pPicture = SecurityLookupIDByType(client, pid, XRT_PICTURE, mode);\ + if (!pPicture) { \ + client->errorValue = pid; \ + return err; \ + } \ +} + +extern unsigned long XRT_PICTURE; + +extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr); + +int +PanoramiXFixesSetGCClipRegion (ClientPtr client) +{ + REQUEST(xXFixesSetGCClipRegionReq); + int result = Success, j; + PanoramiXRes *gc; + REQUEST_SIZE_MATCH(xXFixesSetGCClipRegionReq); + + if(!(gc = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->gc, XRT_GC, DixReadAccess))) + return BadGC; + + FOR_NSCREENS_BACKWARD(j) { + stuff->gc = gc->info[j].id; + result = (*PanoramiXSaveXFixesVector[X_XFixesSetGCClipRegion]) (client); + if(result != Success) break; + } + + return (result); +} + +int +PanoramiXFixesSetWindowShapeRegion (ClientPtr client) +{ + int result = Success, j; + PanoramiXRes *win; + REQUEST(xXFixesSetWindowShapeRegionReq); + + REQUEST_SIZE_MATCH(xXFixesSetWindowShapeRegionReq); + + if(!(win = (PanoramiXRes *)SecurityLookupIDByType( + client, stuff->dest, XRT_WINDOW, DixWriteAccess))) + return BadWindow; + + FOR_NSCREENS_FORWARD(j) { + stuff->dest = win->info[j].id; + result = (*PanoramiXSaveXFixesVector[X_XFixesSetWindowShapeRegion]) (client); + if(result != Success) break; + } + + return (result); +} + +int +PanoramiXFixesSetPictureClipRegion (ClientPtr client) +{ + REQUEST(xXFixesSetPictureClipRegionReq); + int result = Success, j; + PanoramiXRes *pict; + + REQUEST_SIZE_MATCH (xXFixesSetPictureClipRegionReq); + + VERIFY_XIN_PICTURE(pict, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + + FOR_NSCREENS_BACKWARD(j) { + stuff->picture = pict->info[j].id; + result = (*PanoramiXSaveXFixesVector[X_XFixesSetPictureClipRegion]) (client); + if(result != Success) break; + } + + return (result); +} + +#endif diff --git a/xfixes/xfixes.c b/xfixes/xfixes.c index 0db4989..858208f 100755 --- a/xfixes/xfixes.c +++ b/xfixes/xfixes.c @@ -259,3 +259,33 @@ XFixesExtensionInit(void) (EventSwapPtr) SXFixesCursorNotifyEvent; } } + +#ifdef PANORAMIX + +int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr); + +void +PanoramiXFixesInit (void) +{ + int i; + + for (i = 0; i < XFixesNumberRequests; i++) + PanoramiXSaveXFixesVector[i] = ProcXFixesVector[i]; + /* + * Stuff in Xinerama aware request processing hooks + */ + ProcXFixesVector[X_XFixesSetGCClipRegion] = PanoramiXFixesSetGCClipRegion; + ProcXFixesVector[X_XFixesSetWindowShapeRegion] = PanoramiXFixesSetWindowShapeRegion; + ProcXFixesVector[X_XFixesSetPictureClipRegion] = PanoramiXFixesSetPictureClipRegion; +} + +void +PanoramiXFixesReset (void) +{ + int i; + + for (i = 0; i < XFixesNumberRequests; i++) + ProcXFixesVector[i] = PanoramiXSaveXFixesVector[i]; +} + +#endif diff --git a/xfixes/xfixesint.h b/xfixes/xfixesint.h index 33a3205..4a4e783 100755 --- a/xfixes/xfixesint.h +++ b/xfixes/xfixesint.h @@ -255,6 +255,17 @@ ProcXFixesExpandRegion (ClientPtr client); int SProcXFixesExpandRegion (ClientPtr client); +#ifdef PANORAMIX +int +PanoramiXFixesSetGCClipRegion (ClientPtr client); + +int +PanoramiXFixesSetWindowShapeRegion (ClientPtr client); + +int +PanoramiXFixesSetPictureClipRegion (ClientPtr client); +#endif + /* Cursor Visibility (Version 4) */ int @@ -269,4 +280,9 @@ ProcXFixesShowCursor (ClientPtr client); int SProcXFixesShowCursor (ClientPtr client); +#ifdef PANORAMIX +void PanoramiXFixesInit (void); +void PanoramiXFixesReset (void); +#endif + #endif /* _XFIXESINT_H_ */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor