/**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ /* Copyright (c) 2008-2014 Oleksandr Shneyder */ /* Copyright (c) 2011-2016 Mike Gabriel */ /* Copyright (c) 2014-2016 Mihai Moldovan */ /* Copyright (c) 2014-2016 Ulrich Sibiller */ /* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ /* */ /* NXAGENT, NX protocol compression and NX extensions to this software */ /* are copyright of the aforementioned persons and companies. */ /* */ /* Redistribution and use of the present software is allowed according */ /* to terms specified in the file LICENSE which comes in the source */ /* distribution. */ /* */ /* All rights reserved. */ /* */ /* NOTE: This software has received contributions from various other */ /* contributors, only the core maintainers and supporters are listed as */ /* copyright holders. Please contact us, if you feel you should be listed */ /* as copyright holder, as well. */ /* */ /**************************************************************************/ #include "scrnintstr.h" #include "miscstruct.h" #include "pixmapstr.h" #include "dixstruct.h" #include "regionstr.h" #include "../../include/gc.h" #include "servermd.h" #include "mi.h" #include "../../fb/fb.h" #include "Agent.h" #include "Display.h" #include "Screen.h" #include "Pixmaps.h" #include "Trap.h" #include "GCs.h" #include "GCOps.h" #include "Image.h" #include "Split.h" #include "Drawable.h" #include "Visual.h" #include "Client.h" #include "Events.h" #include "Holder.h" #include "Args.h" #include "compext/Compext.h" #include RESTYPE RT_NX_PIXMAP; /* * Set here the required log level. */ #define PANIC #define WARNING #undef TEST #undef DEBUG #undef DUMP #ifdef TEST #include "Font.h" #endif int nxagentPixmapPrivateIndex; int nxagentCorruptedPixmaps; int nxagentCorruptedBackgrounds; /* * Force deallocation of the virtual pixmap. */ static Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap); /* * This serves as a tool to check the synchronization * between pixmaps in framebuffer and the correspondent * pixmaps in the real X server. */ #ifdef TEST Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap); #endif struct nxagentPixmapPair { Pixmap pixmap; PixmapPtr pMap; }; PixmapPtr nxagentCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, unsigned usage_hint) { nxagentPrivPixmapPtr pPixmapPriv, pVirtualPriv; PixmapPtr pPixmap; PixmapPtr pVirtual; #ifdef DEBUG fprintf(stderr, "nxagentCreatePixmap: Creating pixmap with width [%d] " "height [%d] depth [%d] and allocation hint [%d].\n", width, height, depth, usage_hint); #endif /* * Create the pixmap structure but do * not allocate memory for the data. */ pPixmap = AllocatePixmap(pScreen, 0); if (!pPixmap) { #ifdef WARNING fprintf(stderr, "nxagentCreatePixmap: WARNING! Failed to create pixmap with " "width [%d] height [%d] depth [%d] and allocation hint [%d].\n", width, height, depth, usage_hint); #endif return NullPixmap; } /* * Initialize the core members. */ pPixmap -> drawable.type = DRAWABLE_PIXMAP; pPixmap -> drawable.class = 0; pPixmap -> drawable.pScreen = pScreen; pPixmap -> drawable.depth = depth; pPixmap -> drawable.bitsPerPixel = BitsPerPixel(depth); pPixmap -> drawable.id = 0; pPixmap -> drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap -> drawable.x = 0; pPixmap -> drawable.y = 0; pPixmap -> drawable.width = width; pPixmap -> drawable.height = height; pPixmap -> devKind = 0; pPixmap -> refcnt = 1; pPixmap -> devPrivate.ptr = NULL; pPixmap -> usage_hint = usage_hint; /* * Initialize the privates of the real picture. */ pPixmapPriv = nxagentPixmapPriv(pPixmap); pPixmapPriv -> isVirtual = False; pPixmapPriv -> isShared = nxagentShmPixmapTrap; /* * The shared memory pixmaps are never * synchronized with the remote X Server. */ if (pPixmapPriv -> isShared == 1) { BoxRec box; box.x1 = 0; box.y1 = 0; box.x2 = width; box.y2 = height; pPixmapPriv -> corruptedRegion = RegionCreate(&box, 1); } else { pPixmapPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1); } pPixmapPriv -> corruptedBackground = 0; pPixmapPriv -> containGlyphs = 0; pPixmapPriv -> containTrapezoids = 0; /* * The lazy encoding policy generally does * not send on remote X server the off-screen * images, by preferring to synchronize the * windows content. Anyway this behaviour may * be inadvisable if a pixmap is used, for * example, for multiple copy areas on screen. * This counter serves the purpose, taking in- * to account the number of times the pixmap * has been used as source for a deferred * operation. */ pPixmapPriv -> usageCounter = 0; pPixmapPriv -> corruptedBackgroundId = 0; pPixmapPriv -> corruptedId = 0; pPixmapPriv -> synchronizationBitmap = NullPixmap; pPixmapPriv -> corruptedTimestamp = 0; pPixmapPriv -> splitResource = NULL; pPixmapPriv -> isBackingPixmap = 0; /* * Create the pixmap based on the default * windows. The proxy knows this and uses * this information to optimize encode the * create pixmap message by including the * id of the drawable in the checksum. */ if (width != 0 && height != 0 && nxagentGCTrap == 0) { pPixmapPriv -> id = XCreatePixmap(nxagentDisplay, nxagentDefaultWindows[pScreen -> myNum], width, height, depth); } else { pPixmapPriv -> id = 0; #ifdef TEST fprintf(stderr, "nxagentCreatePixmap: Skipping the creation of pixmap at [%p] on real " "X server with nxagentGCTrap [%d].\n", (void *) pPixmap, nxagentGCTrap); #endif } pPixmapPriv -> mid = FakeClientID(serverClient -> index); AddResource(pPixmapPriv -> mid, RT_NX_PIXMAP, pPixmap); pPixmapPriv -> pRealPixmap = pPixmap; pPixmapPriv -> pVirtualPixmap = NULL; pPixmapPriv -> pPicture = NULL; /* * Create the pixmap in the virtual framebuffer. */ pVirtual = fbCreatePixmap(pScreen, width, height, depth, usage_hint); if (pVirtual == NULL) { #ifdef PANIC fprintf(stderr, "nxagentCreatePixmap: PANIC! Failed to create virtual pixmap with " "width [%d] height [%d] depth [%d] and allocation hint [%d].\n", width, height, depth, usage_hint); #endif nxagentDestroyPixmap(pPixmap); return NullPixmap; } #ifdef TEST fprintf(stderr,"nxagentCreatePixmap: Allocated memory for the Virtual %sPixmap %p of real Pixmap %p (%dx%d),", "allocation hint [%d].\n", nxagentShmPixmapTrap ? "Shm " : "", (void *) pVirtual, (void *) pPixmap, width, height, usage_hint); #endif pPixmapPriv -> pVirtualPixmap = pVirtual; /* * Initialize the privates of the virtual picture. We * could avoid to use a flag and just check the pointer * to the virtual pixmap that, if the pixmap is actually * virtual, will be NULL. Unfortunately the flag can be * changed in nxagentValidateGC(). That code should be * removed in future. */ pVirtualPriv = nxagentPixmapPriv(pVirtual); pVirtualPriv -> isVirtual = True; pVirtualPriv -> isShared = nxagentShmPixmapTrap; pVirtualPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1); pVirtualPriv -> corruptedBackground = 0; pVirtualPriv -> containGlyphs = 0; pVirtualPriv -> containTrapezoids = 0; pVirtualPriv -> usageCounter = 0; pVirtualPriv -> corruptedBackgroundId = 0; pVirtualPriv -> corruptedId = 0; pVirtualPriv -> synchronizationBitmap = NullPixmap; pVirtualPriv -> corruptedTimestamp = 0; pVirtualPriv -> splitResource = NULL; /* * We might distinguish real and virtual pixmaps by * checking the pointers to pVirtualPixmap. We should * also remove the copy of id and use the one of the * real pixmap. */ pVirtualPriv -> id = pPixmapPriv -> id; pVirtualPriv -> mid = 0; /* * Storing a pointer back to the real pixmap is * silly. Unfortunately this is the way it has * been originally implemented. See also the * comment in destroy of the pixmap. */ pVirtualPriv -> pRealPixmap = pPixmap; pVirtualPriv -> pVirtualPixmap = NULL; pVirtualPriv -> pPicture = NULL; /* * Check that the virtual pixmap is created with * the appropriate bits-per-plane, otherwise free * everything and return. */ if (pVirtual -> drawable.bitsPerPixel == 0) { #ifdef WARNING fprintf(stderr, "nxagentCreatePixmap: WARNING! Virtual pixmap at [%p] has invalid " "bits per pixel.\n", (void *) pVirtual); fprintf(stderr, "nxagentCreatePixmap: WARNING! Real pixmap created with width [%d] " "height [%d] depth [%d] bits per pixel [%d] and allocation hint [%d].\n", pPixmap -> drawable.width, pPixmap -> drawable.height = height, pPixmap -> drawable.depth, pPixmap -> drawable.bitsPerPixel, usage_hint); #endif if (!nxagentRenderTrap) { #ifdef WARNING fprintf(stderr, "Warning: Disabling render extension due to missing pixmap format.\n"); #endif nxagentRenderTrap = 1; } nxagentDestroyPixmap(pPixmap); return NullPixmap; } #ifdef TEST fprintf(stderr, "nxagentCreatePixmap: Created pixmap at [%p] virtual at [%p] with width [%d] " "height [%d] depth [%d] and allocation hint [%d].\n", (void *) pPixmap, (void *) pVirtual, width, height, depth, usage_hint); #endif return pPixmap; } Bool nxagentDestroyPixmap(PixmapPtr pPixmap) { PixmapPtr pVirtual; nxagentPrivPixmapPtr pPixmapPriv; if (!pPixmap) { #ifdef PANIC fprintf(stderr, "nxagentDestroyPixmap: PANIC! Invalid attempt to destroy " "a null pixmap pointer.\n"); #endif return False; } pPixmapPriv = nxagentPixmapPriv(pPixmap); pVirtual = pPixmapPriv -> pVirtualPixmap; #ifdef TEST fprintf(stderr, "nxagentDestroyPixmap: Destroying pixmap at [%p] with virtual at [%p].\n", (void *) pPixmap, (void *) pVirtual); #endif if (pPixmapPriv -> isVirtual) { int refcnt; /* * For some pixmaps we receive the destroy only for the * virtual. Infact to draw in the framebuffer we can use * the virtual pixmap instead of the pointer to the real * one. As the virtual pixmap can collect references, we * must transfer those references to the real pixmap so * we can continue as the destroy had been requested for * it. */ pVirtual = pPixmap; pPixmap = pPixmapPriv -> pRealPixmap; pPixmapPriv = nxagentPixmapPriv(pPixmap); /* * Move the references accumulated by the virtual * pixmap into the references of the real one. */ refcnt = pVirtual -> refcnt - 1; #ifdef TEST fprintf(stderr, "nxagentDestroyPixmap: Adding [%d] references to pixmap at [%p].\n", refcnt, (void *) pPixmap); #endif pPixmap -> refcnt += refcnt; pVirtual -> refcnt -= refcnt; } --pPixmap -> refcnt; #ifdef TEST fprintf(stderr, "nxagentDestroyPixmap: Pixmap has now [%d] references with virtual pixmap [%d].\n", pPixmap -> refcnt, pVirtual -> refcnt); if (pVirtual != NULL && pVirtual -> refcnt != 1) { fprintf(stderr, "nxagentDestroyPixmap: PANIC! Virtual pixmap has [%d] references.\n", pVirtual -> refcnt); } #endif if (pPixmap -> refcnt > 0) { return True; } #ifdef TEST fprintf(stderr, "nxagentDestroyPixmap: Managing to destroy the pixmap at [%p]\n", (void *) pPixmap); #endif nxagentRemoveItemBSPixmapList(nxagentPixmap(pPixmap)); nxagentDestroyVirtualPixmap(pPixmap); if (pPixmapPriv -> corruptedRegion != NullRegion) { RegionDestroy(pPixmapPriv -> corruptedRegion); pPixmapPriv -> corruptedRegion = NullRegion; } if (nxagentSynchronization.pDrawable == (DrawablePtr) pPixmap) { nxagentSynchronization.pDrawable = NULL; #ifdef TEST fprintf(stderr, "nxagentDestroyPixmap: Synchronization drawable [%p] removed from resources.\n", (void *) pPixmap); #endif } nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); nxagentDestroyDrawableBitmap((DrawablePtr) pPixmap); if (pPixmapPriv -> splitResource != NULL) { nxagentReleaseSplit((DrawablePtr) pPixmap); } /* * A pixmap with width and height set to 0 is * created at the beginning. To this pixmap is * not assigned an id. This is likely a scratch * pixmap used by the X server. */ if (pPixmapPriv -> id) { XFreePixmap(nxagentDisplay, pPixmapPriv -> id); } if (pPixmapPriv -> mid) { FreeResource(pPixmapPriv -> mid, RT_NONE); } free(pPixmap); return True; } Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap) { PixmapPtr pVirtual; nxagentPrivPixmapPtr pVirtualPriv; pVirtual = nxagentPixmapPriv(pPixmap) -> pVirtualPixmap; /* * Force the routine to get rid of the virtual * pixmap. */ if (pVirtual != NULL) { pVirtual -> refcnt = 1; pVirtualPriv = nxagentPixmapPriv(pVirtual); if (pVirtualPriv -> corruptedRegion != NullRegion) { RegionDestroy(pVirtualPriv -> corruptedRegion); pVirtualPriv -> corruptedRegion = NullRegion; } fbDestroyPixmap(pVirtual); } return True; } RegionPtr nxagentPixmapToRegion(PixmapPtr pPixmap) { #ifdef TEST fprintf(stderr, "nxagentPixmapToRegion: Pixmap = [%p] nxagentVirtualPixmap = [%p]\n", (void *) pPixmap, (void *) nxagentVirtualPixmap(pPixmap)); #endif return fbPixmapToRegion(nxagentVirtualPixmap(pPixmap)); } Bool nxagentModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, void * pPixData) { PixmapPtr pVirtualPixmap; /* * See miModifyPixmapHeader() in miscrinit.c. This * function is used to recycle the scratch pixmap * for this screen. We let it refer to the virtual * pixmap. */ if (!pPixmap) { return False; } if (nxagentPixmapIsVirtual(pPixmap)) { #ifdef PANIC fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] is virtual.\n", (void *) pPixmap); #endif FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap is virtual."); } pVirtualPixmap = nxagentVirtualPixmap(pPixmap); #ifdef TEST fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap at [%p] Virtual at [%p].\n", (void *) pPixmap, (void *) pVirtualPixmap); fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap has width [%d] height [%d] depth [%d] " "bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", pPixmap->drawable.width, pPixmap->drawable.height, pPixmap->drawable.depth, pPixmap->drawable.bitsPerPixel, pPixmap->devKind, (void *) pPixmap->devPrivate.ptr); fprintf(stderr, "nxagentModifyPixmapHeader: New parameters are width [%d] height [%d] depth [%d] " "bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", width, height, depth, bitsPerPixel, devKind, (void *) pPixData); #endif if ((width > 0) && (height > 0) && (depth > 0) && (bitsPerPixel > 0) && (devKind > 0) && pPixData) { pPixmap->drawable.depth = depth; pPixmap->drawable.bitsPerPixel = bitsPerPixel; pPixmap->drawable.id = 0; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.x = 0; pPixmap->drawable.y = 0; pPixmap->drawable.width = width; pPixmap->drawable.height = height; pPixmap->devKind = devKind; pPixmap->refcnt = 1; pPixmap->devPrivate.ptr = pPixData; pVirtualPixmap->drawable.depth = depth; pVirtualPixmap->drawable.bitsPerPixel = bitsPerPixel; pVirtualPixmap->drawable.id = 0; pVirtualPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pVirtualPixmap->drawable.x = 0; pVirtualPixmap->drawable.y = 0; pVirtualPixmap->drawable.width = width; pVirtualPixmap->drawable.height = height; pVirtualPixmap->devKind = devKind; pVirtualPixmap->refcnt = 1; pVirtualPixmap->devPrivate.ptr = pPixData; } else { if (width > 0) pPixmap->drawable.width = width; if (height > 0) pPixmap->drawable.height = height; if (depth > 0) pPixmap->drawable.depth = depth; if (bitsPerPixel > 0) pPixmap->drawable.bitsPerPixel = bitsPerPixel; else if ((bitsPerPixel < 0) && (depth > 0)) pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); if (devKind > 0) pPixmap->devKind = devKind; else if ((devKind < 0) && ((width > 0) || (depth > 0))) pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, pPixmap->drawable.depth); if (pPixData) pPixmap->devPrivate.ptr = pPixData; /* * XXX This was the previous assignment: * * pVirtualPixmap->devPrivate.ptr = pPixData; */ if (width > 0) pVirtualPixmap->drawable.width = width; if (height > 0) pVirtualPixmap->drawable.height = height; if (depth > 0) pVirtualPixmap->drawable.depth = depth; if (bitsPerPixel > 0) pVirtualPixmap->drawable.bitsPerPixel = bitsPerPixel; else if ((bitsPerPixel < 0) && (depth > 0)) pVirtualPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); if (devKind > 0) pVirtualPixmap->devKind = devKind; else if ((devKind < 0) && ((width > 0) || (depth > 0))) pVirtualPixmap->devKind = PixmapBytePad(pVirtualPixmap->drawable.width, pVirtualPixmap->drawable.depth); if (pPixData) pVirtualPixmap->devPrivate.ptr = pPixData; #ifdef PANIC if (pPixmap->drawable.x != 0 || pPixmap->drawable.y != 0) { fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] has x [%d] and y [%d].\n", (void *) pPixmap, pPixmap->drawable.x, pPixmap->drawable.y); FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap has x or y greater than zero."); } #endif } return True; } static void nxagentPixmapMatchID(void *p0, XID x1, void *p2) { PixmapPtr pPixmap = (PixmapPtr)p0; struct nxagentPixmapPair *pPair = p2; if ((pPair -> pMap == NULL) && (nxagentPixmap(pPixmap) == pPair -> pixmap)) { pPair -> pMap = pPixmap; } } PixmapPtr nxagentPixmapPtr(Pixmap pixmap) { struct nxagentPixmapPair pair; if (pixmap == None) { return NULL; } pair.pixmap = pixmap; pair.pMap = NULL; FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentPixmapMatchID, &pair); for (int i = 0; (pair.pMap == NULL) && (i < MAXCLIENTS); i++) { if (clients[i]) { FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentPixmapMatchID, &pair); } } #ifdef WARNING if (pair.pMap == NULL) { fprintf(stderr, "nxagentPixmapPtr: WARNING! Failed to find " "remote pixmap [%ld].\n", (long int) pair.pixmap); } else if (nxagentDrawableStatus((DrawablePtr) pair.pMap) == NotSynchronized) { fprintf(stderr, "WARNING! Rootless icon at [%p] [%d,%d] is not synchronized.\n", (void *) pair.pMap, pair.pMap -> drawable.width, pair.pMap -> drawable.height); } #endif return pair.pMap; } /* * Reconnection stuff. */ int nxagentDestroyNewPixmapResourceType(void * p, XID id) { /* * Address of the destructor is set in Init.c. */ #ifdef TEST fprintf(stderr, "nxagentDestroyNewPixmapResourceType: Destroying mirror id [%ld] for pixmap at [%p].\n", nxagentPixmapPriv((PixmapPtr) p) -> mid, (void *) p); #endif nxagentPixmapPriv((PixmapPtr) p) -> mid = None; return True; } void nxagentDisconnectPixmap(void *p0, XID x1, void *p2) { PixmapPtr pPixmap = (PixmapPtr) p0; #ifdef TEST Bool *pBool; pBool = (Bool*) p2; fprintf(stderr, "nxagentDisconnectPixmap: Called with bool [%d] and pixmap at [%p].\n", *pBool, (void *) pPixmap); fprintf(stderr, "nxagentDisconnectPixmap: Virtual pixmap is [%ld].\n", nxagentPixmap(pPixmap)); #endif nxagentPixmap(pPixmap) = None; if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized) { nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); } } Bool nxagentDisconnectAllPixmaps(void) { int i; int r = 1; #ifdef TEST fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to iterate through pixmap resources.\n"); #endif /* * The RT_NX_PIXMAP resource type is allocated * only on the server client, so we don't need * to find it through the other clients too. */ FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentDisconnectPixmap, &r); #ifdef WARNING if (r == 0) { fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " "pixmap for client [%d].\n", serverClient -> index); } #endif for (i = 0, r = 1; i < MAXCLIENTS; r = 1, i++) { if (clients[i]) { #ifdef TEST fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to disconnect pixmaps of client [%d].\n", i); #endif FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentDisconnectPixmap, &r); #ifdef WARNING if (r == 0) { fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " "pixmap for client [%d].\n", i); } #endif } } #ifdef WARNING if (r == 0) { fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " "pixmap for client [%d].\n", i); } #endif #ifdef TEST fprintf(stderr, "nxagentDisconnectAllPixmaps: Pixmaps disconnection completed.\n"); #endif return r; } void nxagentReconnectPixmap(void *p0, XID x1, void *p2) { PixmapPtr pPixmap = (PixmapPtr) p0; Bool *pBool = (Bool*) p2; nxagentPrivPixmapPtr pPixmapPriv; if (!*pBool || pPixmap == NULL || NXDisplayError(nxagentDisplay) == 1) { *pBool = False; #ifdef TEST fprintf(stderr, "nxagentReconnectPixmap: Ignoring pixmap at [%p] while " "recovering from the error.\n", (void *) pPixmap); #endif return; } else if (pPixmap == nxagentDefaultScreen -> pScratchPixmap) { /* * Every time the scratch pixmap is used its * data is changed, so we don't need to recon- * nect it. */ #ifdef TEST fprintf(stderr, "nxagentReconnectPixmap: Ignoring scratch pixmap at [%p].\n", (void *) pPixmap); #endif return; } #ifdef TEST fprintf(stderr, "nxagentReconnectPixmap: Called with result [%d] and pixmap at [%p].\n", *pBool, (void *) pPixmap); fprintf(stderr, "nxagentReconnectPixmap: Virtual pixmap is at [%p] picture is at [%p].\n", (void *) nxagentPixmapPriv(pPixmap) -> pVirtualPixmap, (void *) nxagentPixmapPriv(pPixmap) -> pPicture); #endif pPixmapPriv = nxagentPixmapPriv(pPixmap); if (pPixmap -> drawable.width && pPixmap -> drawable.height) { pPixmapPriv -> id = XCreatePixmap(nxagentDisplay, nxagentDefaultWindows[pPixmap -> drawable.pScreen -> myNum], pPixmap -> drawable.width, pPixmap -> drawable.height, pPixmap -> drawable.depth); nxagentPixmap(pPixmapPriv -> pVirtualPixmap) = pPixmapPriv -> id; #ifdef TEST fprintf(stderr, "nxagentReconnectPixmap: Created virtual pixmap with id [%ld] for pixmap at [%p].\n", nxagentPixmap(pPixmap), (void *) pPixmap); #endif if (pPixmap == (PixmapPtr) nxagentDefaultScreen -> devPrivate) { #ifdef WARNING fprintf(stderr, "nxagentReconnectPixmap: WARNING! Pixmap is root screen. Returning.\n"); #endif return; } nxagentSplitTrap = 1; *pBool = nxagentSynchronizeDrawableData((DrawablePtr) pPixmap, NEVER_BREAK, NULL); nxagentSplitTrap = 0; if (!*pBool) { #ifdef PANIC fprintf(stderr, "nxagentReconnectPixmap: PANIC! Failed to synchronize the pixmap.\n"); #endif } if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized) { if (nxagentIsCorruptedBackground(pPixmap) == 1) { nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); nxagentFillRemoteRegion((DrawablePtr) pPixmap, nxagentCorruptedRegion((DrawablePtr) pPixmap)); } else { nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); } } } } Bool nxagentReconnectAllPixmaps(void *p0) { Bool result = 1; #ifdef TEST fprintf(stderr, "nxagentReconnectAllPixmaps: Going to recreate all pixmaps.\n"); #endif /* * Reset the geometry and alpha information * used by proxy to unpack the packed images. */ nxagentResetVisualCache(); nxagentResetAlphaCache(); /* * The RT_NX_PIXMAP resource type is allocated * only on the server client, so we don't need * to find it through the other clients too. */ FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentReconnectPixmap, &result); #ifdef WARNING if (result == 0) { fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect " "pixmap for client [%d].\n", serverClient -> index); } #endif for (int i = 0, result = 1; i < MAXCLIENTS; result = 1, i++) { if (clients[i] != NULL) { #ifdef TEST fprintf(stderr, "nxagentReconnectAllPixmaps: Going to reconnect pixmaps of client [%d].\n", i); #endif /* * Let the pixmap be reconnected as it was an * image request issued by the client owning * the resource. The client index is used as * a subscript by the image routines to cache * the data per-client. */ FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentReconnectPixmap, &result); #ifdef WARNING if (result == 0) { fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect " "pixmap for client [%d].\n", serverClient -> index); } #endif } } #ifdef TEST fprintf(stderr, "nxagentReconnectAllPixmaps: Pixmaps reconnection completed.\n"); #endif return result; } #ifdef TEST static void nxagentCheckOnePixmapIntegrity(void *p0, XID x1, void *p2) { PixmapPtr pPixmap = (PixmapPtr) p0; Bool *pBool = (Bool*) p2; if (!*pBool) { return; } if (pPixmap == nxagentDefaultScreen -> devPrivate) { #ifdef TEST fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is screen.\n", (void *) pPixmap); #endif return; } if (pPixmap == nxagentDefaultScreen -> PixmapPerDepth[0]) { #ifdef TEST fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is default stipple of screen.\n", (void *) pPixmap); #endif return; } *pBool = nxagentCheckPixmapIntegrity(pPixmap); } Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap) { Bool integrity = True; XImage *image; char *data; int format; unsigned long plane_mask = AllPlanes; unsigned int width, height, length, depth; PixmapPtr pVirtual = nxagentVirtualPixmap(pPixmap); width = pPixmap -> drawable.width; height = pPixmap -> drawable.height; depth = pPixmap -> drawable.depth; format = (depth == 1) ? XYPixmap : ZPixmap; if (width && height) { length = nxagentImageLength(width, height, format, 0, depth); data = malloc(length); if (data == NULL) { FatalError("nxagentCheckPixmapIntegrity: Failed to allocate a buffer of size %d.\n", length); } image = XGetImage(nxagentDisplay, nxagentPixmap(pPixmap), 0, 0, width, height, plane_mask, format); if (image == NULL) { FatalError("XGetImage: Failed.\n"); free(data); return False; } #ifdef WARNING fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from X has length [%d] and checksum [0x%s].\n", length, nxagentChecksum(image->data, length)); #endif NXCleanImage(image); #ifdef WARNING fprintf(stderr, "nxagentCheckPixmapIntegrity: Image after clean has checksum [0x%s].\n", nxagentChecksum(image->data, length)); #endif fbGetImage((DrawablePtr) pVirtual, 0, 0, width, height, format, plane_mask, data); #ifdef WARNING fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from FB has length [%d] and checksum [0x%s].\n", length, nxagentChecksum(data, length)); #endif if (image != NULL && memcmp(image -> data, data, length) != 0) { integrity = False; } else { integrity = True; #ifdef TEST fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] has been realized. " "Now remote and framebuffer data are synchronized.\n", (void *) pPixmap); #endif } #ifdef WARNING if (!integrity) { char *p, *q; for (int i = 0, p = image -> data, q = data; i < length; i++) { if (p[i] != q[i]) { fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d]. " "Buffers differ!\n", i, p[i], q[i]); } else { fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d].\n", i, p[i], q[i]); } } fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] width [%d], height [%d], has been realized " "but the data buffer still differs.\n", (void *) pPixmap, width, height); fprintf(stderr, "nxagentCheckPixmapIntegrity: bytes_per_line [%d] byte pad [%d] format [%d].\n", image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image -> format); FatalError("nxagentCheckPixmapIntegrity: Image is corrupted!!\n"); } #endif if (image != NULL) { XDestroyImage(image); } free(data); } else { #ifdef WARNING fprintf(stderr, "nxagentCheckPixmapIntegrity: Ignored pixmap at [%p] with geometry [%d] [%d].\n", (void *) pPixmap, width, height); #endif } return integrity; } Bool nxagentCheckAllPixmapIntegrity(void) { Bool imageIsGood = True; #ifdef TEST fprintf(stderr, "nxagentCheckAllPixmapIntegrity\n"); #endif FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentCheckOnePixmapIntegrity, &imageIsGood); for (int i = 0; (i < MAXCLIENTS) && (imageIsGood); i++) { if (clients[i]) { FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentCheckOnePixmapIntegrity, &imageIsGood); } } #ifdef TEST fprintf(stderr, "nxagentCheckAllPixmapIntegrity: pixmaps integrity = %d.\n", imageIsGood); #endif return imageIsGood; } #endif void nxagentSynchronizeShmPixmap(DrawablePtr pDrawable, int xPict, int yPict, int wPict, int hPict) { GCPtr pGC; char *data; int width, height; int depth, length, format; CARD32 attributes[3]; int saveTrap; if (pDrawable -> type == DRAWABLE_PIXMAP && nxagentIsShmPixmap((PixmapPtr) pDrawable) == 1) { #ifdef TEST fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Synchronizing shared pixmap at [%p].\n", (void *) pDrawable); #endif pGC = nxagentGetScratchGC(pDrawable -> depth, pDrawable -> pScreen); attributes[0] = 0x228b22; attributes[1] = 0xffffff; attributes[2] = FillSolid; ChangeGC(pGC, GCForeground | GCBackground | GCFillStyle, attributes); ValidateGC(pDrawable, pGC); width = (wPict != 0 && wPict <= pDrawable -> width) ? wPict : pDrawable -> width; height = (hPict != 0 && hPict <= pDrawable -> height) ? hPict : pDrawable -> height; depth = pDrawable -> depth; format = (depth == 1) ? XYPixmap : ZPixmap; length = nxagentImageLength(width, height, format, 0, depth); saveTrap = nxagentGCTrap; nxagentGCTrap = 0; nxagentSplitTrap = 1; nxagentFBTrap = 1; if ((data = malloc(length)) != NULL) { fbGetImage(nxagentVirtualDrawable(pDrawable), xPict, yPict, width, height, format, 0xffffffff, data); nxagentPutImage(pDrawable, pGC, depth, xPict, yPict, width, height, 0, format, data); free(data); } #ifdef WARNING else { fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Failed to allocate memory for the operation.\n"); } #endif nxagentGCTrap = saveTrap; nxagentSplitTrap = 0; nxagentFBTrap = 0; nxagentFreeScratchGC(pGC); } } #ifdef DUMP /* * This function is useful to visualize a pixmap and check * its data consistency. To avoid the creation of many * windows, one pixmap only can be monitored at a time. */ Bool nxagentPixmapOnShadowDisplay(PixmapPtr pMap) { static Display *shadow; static Window win; static int init = True; static int showTime; static PixmapPtr pPixmap; static int depth; static int width; static int height; static int length; static unsigned int format; XlibGC gc; XGCValues value; XImage *image; Visual *pVisual; char *data = NULL; if (init) { if (pMap == NULL) { return False; } else { pPixmap = pMap; } depth = pPixmap -> drawable.depth; width = pPixmap -> drawable.width; height = pPixmap -> drawable.height; format = (depth == 1) ? XYPixmap : ZPixmap; shadow = XOpenDisplay("localhost:0"); if (shadow == NULL) { #ifdef WARNING fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Shadow display not opened.\n"); #endif return False; } init = False; win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0, width, height, 0, 0xFFCC33, 0xFF); XMapWindow(shadow, win); XClearWindow(shadow, win); } /* FIXME: If the pixmap has a different depth from the window, the XPutImage returns a BadMatch. For example this may happen if the Render extension is enabled. Can we fix this creating a new pixmap? */ if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth) { #ifdef WARNING fprintf(stderr, "nxagentPixmapOnShadowDisplay: Pixmap and Window depths [%d - %d] are not equals!\n", depth, DisplayPlanes(shadow, DefaultScreen(shadow))); #endif return False; } /* * If the framebuffer is updated continuously, the nxagent * visualization becomes much too slow. */ if ((GetTimeInMillis() - showTime) < 500) { return False; } showTime = GetTimeInMillis(); length = nxagentImageLength(width, height, format, 0, depth); if ((data = malloc(length)) == NULL) { #ifdef WARNING fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n"); #endif return False; } fbGetImage((DrawablePtr) nxagentVirtualPixmap(pPixmap), 0, 0, width, height, format, AllPlanes, data); pVisual = nxagentImageVisual((DrawablePtr) pPixmap, depth); if (pVisual == NULL) { #ifdef WARNING fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Visual not found. Using default visual.\n"); #endif pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; } image = XCreateImage(nxagentDisplay, pVisual, depth, format, 0, (char *) data, width, height, BitmapPad(nxagentDisplay), nxagentImagePad(width, format, 0, depth)); if (image == NULL) { #ifdef WARNING fprintf(stderr, "nxagentPixmapOnShadowDisplay: XCreateImage failed.\n"); #endif free(data); return False; } value.foreground = 0xff0000; value.background = 0x000000; value.plane_mask = 0xffffff; value.fill_style = FillSolid; gc = XCreateGC(shadow, win, GCBackground | GCForeground | GCFillStyle | GCPlaneMask, &value); NXCleanImage(image); XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height); XFreeGC(shadow, gc); if (image != NULL) { XDestroyImage(image); } return True; } Bool nxagentFbOnShadowDisplay(void) { static Display *shadow; static Window win; static int init = True; static int showTime; static int prevWidth, prevHeight; XlibGC gc; XGCValues value; XImage *image; Visual *pVisual; WindowPtr pWin = screenInfo.screens[0]->root; unsigned int format; int depth, width, height, length; char *data = NULL; if (pWin == NULL) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: The parent window is NULL.\n"); #endif return False; } depth = pWin -> drawable.depth; width = pWin -> drawable.width; height = pWin -> drawable.height; format = (depth == 1) ? XYPixmap : ZPixmap; if (init) { shadow = XOpenDisplay("localhost:0"); if (shadow == NULL) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Shadow display not opened.\n"); #endif return False; } init = False; prevWidth = width; prevHeight = height; win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0, width, height, 0, 0xFFCC33, 0xFF); XMapWindow(shadow, win); XClearWindow(shadow, win); } if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: Depths [%d - %d] are not equals!\n", depth, DisplayPlanes(shadow, DefaultScreen(shadow))); #endif return False; } /* * If the framebuffer is updated continuously, the nxagent * visualization becomes too much slow. */ if ((GetTimeInMillis() - showTime) < 500) { return False; } showTime = GetTimeInMillis(); /* * If the root window is resized, also the window on shadow * display must be resized. */ if (prevWidth != width || prevHeight != height) { XWindowChanges values; prevWidth = width; prevHeight = height; values.width = width; values.height = height; XConfigureWindow(shadow, win, CWWidth | CWHeight, &values); } length = nxagentImageLength(width, height, format, 0, depth); if ((data = malloc(length)) == NULL) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n"); #endif return False; } fbGetImage((DrawablePtr)pWin, 0, 0, width, height, format, AllPlanes, data); pVisual = nxagentImageVisual((DrawablePtr) pWin, depth); if (pVisual == NULL) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Visual not found. Using default visual.\n"); #endif pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; } image = XCreateImage(nxagentDisplay, pVisual, depth, format, 0, (char *) data, width, height, BitmapPad(nxagentDisplay), nxagentImagePad(width, format, 0, depth)); if (image == NULL) { #ifdef WARNING fprintf(stderr, "nxagentFbOnShadowDisplay: XCreateImage failed.\n"); #endif free(data); return False; } value.foreground = 0xff0000; value.background = 0x000000; value.plane_mask = 0xffffff; value.fill_style = FillSolid; gc = XCreateGC(shadow, win, GCBackground | GCForeground | GCFillStyle | GCPlaneMask, &value); NXCleanImage(image); XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height); XFreeGC(shadow, gc); if (image != NULL) { XDestroyImage(image); } return True; } #endif #ifdef DEBUG void nxagentPrintResourceTypes(void) { fprintf(stderr, "nxagentPrintResourceTypes: RT_PIXMAP [%lu].\n", (unsigned long) RT_PIXMAP); fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_PIXMAP [%lu].\n", (unsigned long) RT_NX_PIXMAP); fprintf(stderr, "nxagentPrintResourceTypes: RT_GC [%lu].\n", (unsigned long) RT_GC); fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_GC [%lu].\n", (unsigned long) RT_NX_GC); fprintf(stderr, "nxagentPrintResourceTypes: RT_FONT [%lu].\n", (unsigned long) RT_FONT); fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_FONT [%lu].\n", (unsigned long) RT_NX_FONT); fprintf(stderr, "nxagentPrintResourceTypes: RT_CURSOR [%lu].\n", (unsigned long) RT_CURSOR); fprintf(stderr, "nxagentPrintResourceTypes: RT_WINDOW [%lu].\n", (unsigned long) RT_WINDOW); fprintf(stderr, "nxagentPrintResourceTypes: RT_COLORMAP [%lu].\n", (unsigned long) RT_COLORMAP); } void nxagentPrintResourcePredicate(void *value, XID id, XID type, void *cdata) { fprintf(stderr, "nxagentPrintResourcePredicate: Resource [%p] id [%lu] type [%lu].\n", (void *) value, (unsigned long) id, (unsigned long) type); } void nxagentPrintResources(void) { Bool result; nxagentPrintResourceTypes(); for (int i = 0; i < MAXCLIENTS; i++) { if (clients[i]) { fprintf(stderr, "nxagentPrintResources: Printing resources for client [%d]:\n", i); FindAllClientResources(clients[i], nxagentPrintResourcePredicate, &result); } } } #endif