aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/nxagent/Drawable.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/Drawable.c')
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Drawable.c3267
1 files changed, 3267 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Drawable.c b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c
new file mode 100644
index 000000000..9c167743f
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c
@@ -0,0 +1,3267 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */
+/* */
+/* NXAGENT, NX protocol compression and NX extensions to this software */
+/* are copyright of NoMachine. Redistribution and use of the present */
+/* software is allowed according to terms specified in the file LICENSE */
+/* which comes in the source distribution. */
+/* */
+/* Check http://www.nomachine.com/licensing.html for applicability. */
+/* */
+/* NX and NoMachine are trademarks of Medialogic S.p.A. */
+/* */
+/* All rights reserved. */
+/* */
+/**************************************************************************/
+
+#include "dixstruct.h"
+#include "../../fb/fb.h"
+
+#include "Agent.h"
+#include "Display.h"
+#include "Screen.h"
+#include "Trap.h"
+#include "Image.h"
+#include "Drawable.h"
+#include "Client.h"
+#include "Visual.h"
+#include "Events.h"
+#include "GCs.h"
+#include "Utils.h"
+#include "Handlers.h"
+#include "Pixels.h"
+#include "Reconnect.h"
+#include "GCOps.h"
+
+#include "NXlib.h"
+
+#include "mibstorest.h"
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+#undef DUMP
+
+/*
+ * The list of rectangles composing a region
+ * s returned by nxagentGetOptimizedRegion-
+ * Boxes() instead of REGION_RECTS().
+ */
+
+#define USE_OPTIMIZED_BOXES
+
+/*
+ * The rectangles composing a region are de-
+ * fragmented to reduce the number of synch-
+ * ronizing PutImage's.
+ */
+
+#define ADVANCED_BOXES_DEFRAG
+
+/*
+ * If defined, send the XClearArea at the end
+ * of the loop synchronizing the shadow pixmap.
+ * In this way, large images can be splitted but
+ * the user will see more updates togheter.
+ */
+
+#undef COLLECTED_UPDATES
+
+#ifdef ADVANCED_BOXES_DEFRAG
+#define INCLUDE_MARGIN 10
+#endif
+
+struct nxagentExposeBackground
+{
+ PixmapPtr pBackground;
+ RegionPtr pExpose;
+};
+
+RESTYPE RT_NX_CORR_BACKGROUND;
+RESTYPE RT_NX_CORR_WINDOW;
+RESTYPE RT_NX_CORR_PIXMAP;
+
+int nxagentCorruptedPixmaps = 0;
+int nxagentCorruptedWindows = 0;
+int nxagentCorruptedBackgrounds = 0;
+
+int nxagentForceSynchronization = 0;
+
+_nxagentSynchronizationRec nxagentSynchronization = { (DrawablePtr) NULL, 0, 0, 0, 0, 0 };
+
+RegionPtr nxagentDeferredBackgroundExposures = NullRegion;
+
+/*
+ * Predicate functions used to synchronize the
+ * content of the remote drawable with the data
+ * stored in the virtual frame-buffer.
+ */
+
+void nxagentSynchronizeDrawablePredicate(void *p0, XID x1, void *p2);
+void nxagentExposeBackgroundPredicate(void *p0, XID x1, void *p2);
+
+/*
+ * Imported from NXresource.c
+ */
+
+extern int nxagentFindClientResource(int, RESTYPE, pointer);
+
+unsigned long nxagentGetColor(DrawablePtr pDrawable, int xPixel, int yPixel);
+unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable);
+unsigned long nxagentGetRegionColor(DrawablePtr pDrawable, RegionPtr pRegion);
+
+int nxagentSynchronizeDrawable(DrawablePtr pDrawable, int wait, unsigned int breakMask, WindowPtr owner)
+{
+ int result;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ if (nxagentLosslessTrap == 0)
+ {
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawable: Drawable [%s][%p] with id [%ld] already "
+ "synchronized.\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, pDrawable -> id);
+ #endif
+
+ return 0;
+ }
+ }
+
+ /*
+ * What we want here is to avoid drawing on the
+ * framebuffer and just perform the operation
+ * on the real X server. This is the purpose of
+ * the FB trap. At the same time we also want
+ * to avoid a split, so that the image will be
+ * transferred in a single operation.
+ */
+
+ nxagentFBTrap = 1;
+
+ nxagentSplitTrap = 1;
+
+ result = nxagentSynchronizeDrawableData(pDrawable, breakMask, owner);
+
+ nxagentSplitTrap = 0;
+
+ nxagentFBTrap = 0;
+
+ if (wait == DO_WAIT && nxagentSplitResource(pDrawable) != NULL)
+ {
+ nxagentWaitDrawable(pDrawable);
+ }
+
+ #ifdef TEST
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ fprintf(stderr, "nxagentSynchronizeDrawable: Drawable %s [%p] with id [%ld] now synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable, pDrawable -> id);
+ }
+ else
+ {
+ fprintf(stderr, "nxagentSynchronizeDrawable: Drawable %s [%p] with id [%ld] not fully synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable, pDrawable -> id);
+ }
+
+ #endif
+
+ return result;
+}
+
+int nxagentSynchronizeDrawableData(DrawablePtr pDrawable, unsigned int breakMask, WindowPtr owner)
+{
+ int width, height, depth, length;
+ unsigned int leftPad, format;
+
+ char *data = NULL;
+ DrawablePtr pSrcDrawable;
+ GCPtr pGC;
+
+ int success;
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ leftPad = 0;
+
+ width = pDrawable -> width;
+ height = pDrawable -> height;
+ depth = pDrawable -> depth;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawableData: Synchronizing drawable (%s) with geometry [%d][%d][%d].\n",
+ nxagentDrawableType(pDrawable), width, height, depth);
+ #endif
+
+ format = (depth == 1) ? XYPixmap : ZPixmap;
+
+ length = nxagentImageLength(width, height, format, leftPad, depth);
+
+ if ((data = xalloc(length)) == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to allocate memory for the operation.\n");
+ #endif
+
+ success = 0;
+
+ goto nxagentSynchronizeDrawableDataEnd;
+ }
+
+ pSrcDrawable = (pDrawable -> type == DRAWABLE_PIXMAP ?
+ ((DrawablePtr) nxagentVirtualPixmap((PixmapPtr) pDrawable)) :
+ pDrawable);
+
+ /*
+ * Synchronize the whole pixmap if we need
+ * to download a fresh copy with lossless
+ * compression turned off.
+ */
+
+ if (nxagentLosslessTrap == 1)
+ {
+ pGC = nxagentGetGraphicContext(pDrawable);
+
+ if (pGC == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to get the temporary GC.\n");
+ #endif
+
+ success = 0;
+
+ goto nxagentSynchronizeDrawableDataFree;
+ }
+
+ ValidateGC(pDrawable, pGC);
+
+ fbGetImage(pSrcDrawable, 0, 0,
+ width, height, format, AllPlanes, data);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawableData: Forcing synchronization of "
+ "pixmap at [%p] with lossless compression.\n", (void *) pDrawable);
+ #endif
+
+ nxagentPutImage(pDrawable, pGC, depth, 0, 0,
+ width, height, leftPad, format, data);
+
+ success = 1;
+
+ goto nxagentSynchronizeDrawableDataFree;
+ }
+ else if (nxagentReconnectTrap == 1)
+ {
+ /*
+ * The pixmap data is not synchronized unless
+ * we need it. We noticed we have to reconnect
+ * the pixmaps used by the GC's clip mask.
+ * The other data will be synchronized on demand.
+ */
+
+ if (pDrawable -> depth == 1)
+ {
+ #ifdef TEST
+
+ if (nxagentReconnectTrap == 1)
+ {
+ static int totalLength;
+ static int totalReconnectedPixmaps;
+
+ totalLength += length;
+ totalReconnectedPixmaps++;
+
+ fprintf(stderr, "nxagentSynchronizeDrawableData: Reconnecting pixmap at [%p] [%dx%d] "
+ "Depth [%d] Size [%d]. Total size [%d]. Total reconnected pixmaps [%d].\n",
+ (void *) pDrawable, width, height, depth, length,
+ totalLength, totalReconnectedPixmaps);
+ }
+
+ #endif
+
+ pGC = nxagentGetGraphicContext(pDrawable);
+
+ if (pGC == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to create the temporary GC.\n");
+ #endif
+
+ success = 0;
+
+ goto nxagentSynchronizeDrawableDataFree;
+ }
+
+ ValidateGC(pDrawable, pGC);
+
+ fbGetImage(pSrcDrawable, 0, 0,
+ width, height, format, AllPlanes, data);
+
+ nxagentPutImage(pDrawable, pGC, depth, 0, 0,
+ width, height, leftPad, format, data);
+
+ success = 1;
+
+ goto nxagentSynchronizeDrawableDataFree;
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawableData: Skipping synchronization of "
+ "pixmap at [%p][%p] during reconnection.\n", (void *) pDrawable, (void*) nxagentVirtualPixmap((PixmapPtr)pDrawable));
+ #endif
+
+ nxagentMarkCorruptedRegion(pDrawable, NullRegion);
+
+ success = 1;
+
+ goto nxagentSynchronizeDrawableDataFree;
+ }
+ }
+ }
+
+ /*
+ * By calling this function with the NullRegion
+ * as parameter we are requesting to synchro-
+ * nize the full visible corrupted region of
+ * the drawable.
+ */
+
+ success = nxagentSynchronizeRegion(pDrawable, NullRegion, breakMask, owner);
+
+nxagentSynchronizeDrawableDataFree:
+
+ if (data != NULL)
+ {
+ xfree(data);
+ }
+
+nxagentSynchronizeDrawableDataEnd:
+
+ return success;
+}
+
+/*
+ * If pRegion is NullRegion, all the viewable
+ * corrupted region will be synchronized.
+ */
+
+int nxagentSynchronizeRegion(DrawablePtr pDrawable, RegionPtr pRegion, unsigned int breakMask, WindowPtr owner)
+{
+ GCPtr pGC;
+ DrawablePtr pSrcDrawable;
+ BoxPtr pBox;
+ RegionPtr clipRegion;
+
+ RegionRec tileRegion;
+ RegionRec exposeRegion;
+ BoxRec box;
+ BoxRec tileBox;
+
+ #ifdef COLLECTED_UPDATES
+ RegionRec collectedUpdates;
+ #endif
+
+ char *data;
+
+ int nBox;
+ int x, y;
+ int w, h;
+ int extentWidth, extentHeight;
+ int tileWidth, tileHeight;
+ int length, format, leftPad;
+ int i;
+ int saveTrap;
+ int success;
+ int useStoredBitmap;
+
+ unsigned long now;
+ unsigned long elapsedTime;
+
+
+ leftPad = 0;
+ success = 0;
+ data = NULL;
+ pGC = NULL;
+ clipRegion = NullRegion;
+
+ #ifdef COLLECTED_UPDATES
+ REGION_INIT(pDrawable -> pScreen, &collectedUpdates, NullBox, 1);
+ #endif
+
+ REGION_INIT(pDrawable -> pScreen, &exposeRegion, NullBox, 1);
+
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap &&
+ nxagentDrawableStatus((DrawablePtr) nxagentDrawableBitmap(pDrawable)) == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Drawable [%s] at [%p] has an already synchronized "
+ "bitmap at [%p].\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable));
+ #endif
+
+ nxagentDestroyDrawableBitmap(pDrawable);
+ }
+
+ /*
+ * The stored bitmap may be used if we
+ * are going to synchronize the full
+ * drawable.
+ */
+
+ useStoredBitmap = (nxagentDrawableBitmap(pDrawable) != NullPixmap && pRegion == NullRegion);
+
+ if (useStoredBitmap != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Drawable [%s] at [%p] has a synchronization bitmap at [%p] "
+ "[%d,%d,%d,%d] with [%ld] rects.\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable),
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2,
+ REGION_NUM_RECTS(nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable))));
+ #endif
+
+ clipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height);
+
+ /*
+ * Intersecting the viewable region of the
+ * drawable with the region remaining from
+ * a previous loop.
+ */
+
+ REGION_INTERSECT(pDrawable -> pScreen, clipRegion, clipRegion,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)));
+
+ /*
+ * The bitmap regions used in the synchro-
+ * nizations are only those corrupted also
+ * on the drawable. In this way, if we put
+ * a tile in a bad position (e.g. if the
+ * corrupted region moves), the next synch-
+ * ronization will fix the error.
+ */
+
+ REGION_INTERSECT(pDrawable -> pScreen, clipRegion, clipRegion,
+ nxagentCorruptedRegion(pDrawable));
+
+ /*
+ * The bitmap to synchronize is clipped.
+ */
+
+ if (REGION_NIL(clipRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: The bitmap region [%d,%d,%d,%d] is not viewable. "
+ "Destroying it.\n", clipRegion -> extents.x1, clipRegion -> extents.y1,
+ clipRegion -> extents.x2, clipRegion -> extents.y2);
+ #endif
+
+ nxagentDestroyDrawableBitmap(pDrawable);
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ /*
+ * Using the saved bitmap as source, instead
+ * of the drawable itself.
+ */
+
+ pSrcDrawable = ((DrawablePtr) nxagentVirtualPixmap(nxagentDrawableBitmap(pDrawable)));
+ }
+ else
+ {
+ if (pRegion != NullRegion && REGION_NIL(pRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Region [%d,%d,%d,%d] is nil. Skipping synchronization.\n",
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2);
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: The [%s] at [%p] is already synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ /*
+ * Creating a region containing the viewable
+ * area of drawable.
+ */
+
+ clipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height);
+
+ /*
+ * If the corrupted region is not viewable, we
+ * can skip the synchronization.
+ */
+
+ REGION_INTERSECT(pDrawable -> pScreen, clipRegion, clipRegion, nxagentCorruptedRegion(pDrawable));
+
+ if (REGION_NIL(clipRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: The corrupted region [%d,%d,%d,%d] is not viewable "
+ "on [%s] at [%p]. Skipping the synchronization.\n", clipRegion -> extents.x1,
+ clipRegion -> extents.y1, clipRegion -> extents.x2, clipRegion -> extents.y2,
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ /*
+ * We can skip the synchronization if the re-
+ * quested region is not corrupted. Specifying
+ * a NullRegion as parameter, all the viewable
+ * corrupted region will be synchronized.
+ */
+
+ if (pRegion != NullRegion)
+ {
+ REGION_INTERSECT(pDrawable -> pScreen, clipRegion, clipRegion, pRegion);
+
+ if (REGION_NIL(clipRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Region requested [%d,%d,%d,%d] already "
+ "synchronized on [%s] at [%p].\n", pRegion -> extents.x1,
+ pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2,
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+ }
+
+ pSrcDrawable = (pDrawable -> type == DRAWABLE_PIXMAP ?
+ ((DrawablePtr) nxagentVirtualPixmap((PixmapPtr) pDrawable)) :
+ pDrawable);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronizing region with coordinates [%d,%d,%d,%d] "
+ "on [%s] at [%p].\n", clipRegion -> extents.x1, clipRegion -> extents.y1,
+ clipRegion -> extents.x2, clipRegion -> extents.y2,
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ saveTrap = nxagentGCTrap;
+
+ nxagentGCTrap = 0;
+
+ nxagentFBTrap = 1;
+
+ nxagentSplitTrap = 1;
+
+ pGC = nxagentGetGraphicContext(pDrawable);
+
+ if (pGC == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to create the temporary GC.\n");
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ ValidateGC(pDrawable, pGC);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Going to synchronize [%ld] rects of [%s] at [%p].\n",
+ REGION_NUM_RECTS(clipRegion), nxagentDrawableType(pDrawable), (void *) pDrawable);
+
+ fprintf(stderr, "nxagentSynchronizeRegion: Extents geometry [%d,%d,%d,%d].\n",
+ clipRegion -> extents.x1, clipRegion -> extents.y1, clipRegion -> extents.x2, clipRegion -> extents.y2);
+
+ fprintf(stderr, "nxagentSynchronizeRegion: Drawable geometry [%d,%d,%d,%d].\n",
+ pDrawable -> x, pDrawable -> y, pDrawable -> width, pDrawable -> height);
+ #endif
+
+ /*
+ * We are going to synchronize the corrupted
+ * area, so we use the corrupted extents as
+ * maximum size of the image data. It's im-
+ * portant to avoid using the drawable size,
+ * because in case of a huge window it had to
+ * result in a failed data memory allocation.
+ */
+
+ extentWidth = clipRegion -> extents.x2 - clipRegion -> extents.x1;
+ extentHeight = clipRegion -> extents.y2 - clipRegion -> extents.y1;
+
+ w = tileWidth = (nxagentOption(TileWidth) > extentWidth ? extentWidth : nxagentOption(TileWidth));
+ h = tileHeight = (nxagentOption(TileHeight) > extentHeight ? extentHeight : nxagentOption(TileHeight));
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentSynchronizeRegion: Using tiles of size [%dx%d].\n", tileWidth, tileHeight);
+ #endif
+
+ data = nxagentAllocateImageData(w, h, pDrawable -> depth, &length, &format);
+
+ if (data == NULL)
+ {
+ #ifdef WARNING
+
+ fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to allocate memory for synchronization.\n");
+
+ /*
+ * Print detailed informations if the
+ * image length is zero.
+ */
+
+ if (length == 0)
+ {
+ fprintf(stderr, "nxagentSynchronizeRegion: Drawable [%s] at [%p] with region geometry [%ld][%d,%d,%d,%d].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable, REGION_NUM_RECTS(clipRegion),
+ clipRegion -> extents.x1, clipRegion -> extents.y1,
+ clipRegion -> extents.x2, clipRegion -> extents.y2);
+ }
+
+ #endif
+
+ goto nxagentSynchronizeRegionFree;
+ }
+
+ #ifndef USE_OPTIMIZED_BOXES
+
+ pBox = REGION_RECTS(clipRegion);
+
+ #else
+
+ pBox = nxagentGetOptimizedRegionBoxes(clipRegion);
+
+ #endif /* USE_OPTIMIZED_BOXES */
+
+ nBox = REGION_NUM_RECTS(clipRegion);
+
+ now = GetTimeInMillis();
+
+ nxagentSynchronization.abort = 0;
+
+ /*
+ * Going to split the updated region into small blocks.
+ */
+
+ for (i = 0; i < nBox; i++)
+ {
+ #ifdef USE_OPTIMIZED_BOXES
+
+ if (pBox[i].x1 == 0 && pBox[i].y1 == 0 &&
+ pBox[i].x2 == 0 && pBox[i].y2 == 0)
+ {
+ continue;
+ }
+
+ #endif
+
+ box = pBox[i];
+
+ for (y = box.y1; y < box.y2; y += h)
+ {
+ h = MIN(box.y2 - y, tileHeight);
+
+ for (x = box.x1; x < box.x2; x += w)
+ {
+ w = MIN(box.x2 - x, tileWidth);
+
+ /*
+ * FIXME: This should not occur.
+ */
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ #ifdef WARNING
+
+ if (pDrawable -> type == DRAWABLE_WINDOW && pSrcDrawable != pDrawable)
+ {
+ fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Trying to synchronize "
+ "the clean drawable type [%d] at [%p] with source at [%p].\n",
+ pDrawable -> type, (void *) pDrawable, (void *) pSrcDrawable);
+ }
+
+ #endif
+
+ goto nxagentSynchronizeRegionStop;
+ }
+
+ if (canBreakOnTimeout(breakMask))
+ {
+ /*
+ * Abort the synchronization loop if it
+ * lasts for more than DeferTimeout
+ * milliseconds.
+ */
+
+ elapsedTime = GetTimeInMillis() - now;
+
+ if (elapsedTime > nxagentOption(DeferTimeout))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with "
+ "[%lu] ms elapsed.\n", elapsedTime);
+ #endif
+
+ nxagentSynchronization.abort = 1;
+
+ goto nxagentSynchronizeRegionStop;
+ }
+ }
+
+ /*
+ * Abort the loop if we go out of bandwidth.
+ */
+
+ if (breakOnCongestionDrawable(breakMask, pDrawable) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with "
+ "congestion [%d] blocking [%d].\n", nxagentCongestion,
+ nxagentBlocking);
+ #endif
+
+ nxagentSynchronization.abort = 1;
+
+ goto nxagentSynchronizeRegionStop;
+ }
+
+ /*
+ * Abort the loop if the display blocks.
+ */
+
+ if (breakOnBlocking(breakMask) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with "
+ "blocking [%d] congestion [%d].\n", nxagentBlocking,
+ nxagentCongestion);
+ #endif
+
+ nxagentSynchronization.abort = 1;
+
+ goto nxagentSynchronizeRegionStop;
+ }
+
+ tileBox.x1 = x;
+ tileBox.y1 = y;
+ tileBox.x2 = x + w;
+ tileBox.y2 = y + h;
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentSynchronizeRegion: Going to synchronize tile [%d,%d,%d,%d].\n",
+ tileBox.x1, tileBox.y1, tileBox.x2, tileBox.y2);
+ #endif
+
+ nxagentGetImage(pSrcDrawable, x, y, w, h, format, AllPlanes, data);
+
+ /*
+ * Going to unmark the synchronized
+ * region.
+ */
+
+ REGION_INIT(pDrawable -> pScreen, &tileRegion, &tileBox, 1);
+
+ REGION_UNION(pDrawable -> pScreen, &exposeRegion, &exposeRegion, &tileRegion);
+
+ #ifdef COLLECTED_UPDATES
+ REGION_APPEND(pDrawable -> pScreen, &collectedUpdates, &tileRegion);
+ #endif
+
+ if (useStoredBitmap != 0)
+ {
+ /*
+ * When a bitmap's tile is synchronized,
+ * we can clear the corresponding region.
+ * We can't use the nxagentUnmarkCorrupted-
+ * Region because we have not a resource
+ * associated to this pixmap.
+ */
+
+ REGION_SUBTRACT(pDrawable -> pScreen, nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)),
+ nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), &tileRegion);
+
+ /*
+ * The drawable's corrupted region can
+ * be cleared if the bitmap's tile data
+ * matches the drawable's content at the
+ * same position.
+ */
+
+ if (nxagentDrawableStatus(pDrawable) == NotSynchronized)
+ {
+ char *cmpData;
+
+ int cmpLength, cmpFormat;
+
+ cmpData = nxagentAllocateImageData(w, h, pDrawable -> depth, &cmpLength, &cmpFormat);
+
+ if (cmpData != NULL)
+ {
+ nxagentGetImage(pDrawable, x, y, w, h, format, AllPlanes, cmpData);
+
+ if (memcmp(data, cmpData, cmpLength) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Tile [%d,%d,%d,%d] matches drawable's data at same position.\n",
+ x, y, x + w, y + h);
+ #endif
+
+ nxagentUnmarkCorruptedRegion(pDrawable, &tileRegion);
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentSynchronizeRegion: Tile [%d,%d,%d,%d] on drawable [%p] doesn't match.\n",
+ x, y, x + w, y + h, (void *) pDrawable);
+ }
+ #endif
+ }
+ else
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to allocate memory to compare tiles.\n");
+ #endif
+ }
+
+ if (cmpData != NULL)
+ {
+ xfree(cmpData);
+ }
+ }
+ }
+ else
+ {
+ nxagentUnmarkCorruptedRegion(pDrawable, &tileRegion);
+
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Going to clean bitmap at [%p] with newer data.\n",
+ (void *) nxagentDrawableBitmap(pDrawable));
+ #endif
+
+ REGION_SUBTRACT(pDrawable -> pScreen, nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)),
+ nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), &tileRegion);
+ }
+ }
+
+ /*
+ * Realize the image after comparing the
+ * source data with the bitmap data.
+ */
+
+ nxagentRealizeImage(pDrawable, pGC, pDrawable -> depth,
+ x, y, w, h, leftPad, format, data);
+
+ REGION_UNINIT(pDrawable -> pScreen, &tileRegion);
+
+ #if !defined(COLLECTED_UPDATES)
+
+ if (owner != NULL)
+ {
+ if (nxagentOption(Shadow) == 1 &&
+ (nxagentOption(XRatio) != DONT_SCALE ||
+ nxagentOption(YRatio) != DONT_SCALE))
+ {
+ int scaledx;
+ int scaledy;
+ int scaledw;
+ int scaledh;
+
+ scaledx = nxagentScale(x, nxagentOption(XRatio));
+ scaledy = nxagentScale(y, nxagentOption(YRatio));
+
+ scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx;
+ scaledh = nxagentScale(y + h, nxagentOption(YRatio)) - scaledy;
+
+ XClearArea(nxagentDisplay, nxagentWindow(owner), scaledx, scaledy, scaledw, scaledh, 0);
+ }
+ else
+ {
+ XClearArea(nxagentDisplay, nxagentWindow(owner), x, y, w, h, 0);
+ }
+ }
+
+ #endif /* #if !defined(COLLECTED_UPDATES) */
+
+ /*
+ * Abort the loop on the user's input.
+ * This is done here to check for events
+ * read after the flush caused by the
+ * PutImage.
+ */
+
+ nxagentDispatchHandler((ClientPtr) 0, 0, 0);
+
+ if (breakOnEvent(breakMask) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with "
+ "new input events.\n");
+ #endif
+
+ nxagentSynchronization.abort = 1;
+
+ goto nxagentSynchronizeRegionStop;
+ }
+ }
+ }
+ }
+
+nxagentSynchronizeRegionStop:
+
+ nxagentSplitTrap = 0;
+
+ nxagentFBTrap = 0;
+
+ nxagentGCTrap = saveTrap;
+
+ success = 1;
+
+ if (nxagentOption(Shadow) == 0)
+ {
+ if (nxagentSynchronization.abort == 1)
+ {
+ /*
+ * Storing the pointer to the drawable we
+ * were synchronizing when the loop aborted.
+ * It is used in nxagentSynchronizeDrawable-
+ * Predicate.
+ */
+
+ nxagentSynchronization.pDrawable = pDrawable;
+ nxagentSynchronization.drawableType = pDrawable -> type;
+
+ if (nxagentDrawableBitmap(pDrawable) == NullPixmap)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Going to create the synchronization bitmap.\n");
+ #endif
+
+ nxagentCreateDrawableBitmap(pDrawable);
+ }
+ }
+ else
+ {
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeRegion: Synchronization loop finished. Going to destroy synchronization bitmap.\n");
+ #endif
+
+ nxagentDestroyDrawableBitmap(pDrawable);
+ }
+ }
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP &&
+ nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1 &&
+ REGION_NIL(&exposeRegion) == 0)
+ {
+ struct nxagentExposeBackground eb;
+
+ int i;
+
+ eb.pBackground = (PixmapPtr) pDrawable;
+ eb.pExpose = &exposeRegion;
+
+ for (i = 0; i < MAXCLIENTS; i++)
+ {
+ if (clients[i] != NULL)
+ {
+ FindClientResourcesByType(clients[i], RT_WINDOW,
+ nxagentExposeBackgroundPredicate, &eb);
+ }
+ }
+ }
+ }
+ #ifdef COLLECTED_UPDATES
+ else
+ {
+ if (owner != NULL)
+ {
+ int overlap = 0;
+
+ REGION_VALIDATE(pDrawable -> pScreen, &collectedUpdates, &overlap);
+
+ for (i = 0; i < REGION_NUM_RECTS(&collectedUpdates); i++)
+ {
+ x = REGION_RECTS(&collectedUpdates)[i].x1;
+ y = REGION_RECTS(&collectedUpdates)[i].y1;
+ w = REGION_RECTS(&collectedUpdates)[i].x2 - REGION_RECTS(&collectedUpdates)[i].x1;
+ h = REGION_RECTS(&collectedUpdates)[i].y2 - REGION_RECTS(&collectedUpdates)[i].y1;
+
+ if (nxagentOption(Shadow) == 1 &&
+ (nxagentOption(XRatio) != DONT_SCALE ||
+ nxagentOption(YRatio) != DONT_SCALE))
+ {
+ int scaledx;
+ int scaledy;
+ int scaledw;
+ int scaledh;
+
+ scaledx = nxagentScale(x, nxagentOption(XRatio));
+ scaledy = nxagentScale(y, nxagentOption(YRatio));
+
+ scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx;
+ scaledh = nxagentScale(y + h, nxagentOption(YRatio)) - scaledy;
+
+ XClearArea(nxagentDisplay, nxagentWindow(owner), scaledx, scaledy, scaledw, scaledh, 0);
+ }
+ else
+ {
+ XClearArea(nxagentDisplay, nxagentWindow(owner), x, y, w, h, 0);
+ }
+ }
+ }
+ }
+ #endif /* #ifdef COLLECTED_UPDATES */
+
+nxagentSynchronizeRegionFree:
+
+ if (clipRegion != NullRegion)
+ {
+ nxagentFreeRegion(pDrawable, clipRegion);
+ }
+
+ if (data != NULL)
+ {
+ xfree(data);
+ }
+
+ REGION_UNINIT(pDrawable -> pScreen, &exposeRegion);
+
+ #ifdef COLLECTED_UPDATES
+
+ REGION_UNINIT(pDrawable -> pScreen, &collectedUpdates);
+
+ #endif /* #ifdef COLLECTED_UPDATES */
+
+ return success;
+}
+
+void nxagentSynchronizeBox(DrawablePtr pDrawable, BoxPtr pBox, unsigned int breakMask)
+{
+ RegionPtr pRegion;
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeBox: The [%s] at [%p] is already synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ if (pBox == NullBox)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeBox: Going to synchronize the whole [%s] at [%p].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ nxagentSynchronizeRegion(pDrawable, NullRegion, breakMask, NULL);
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeBox: Going to create a region from box [%d,%d,%d,%d].\n",
+ pBox -> x1, pBox -> y1, pBox -> x2, pBox -> y2);
+ #endif
+
+ pRegion = nxagentCreateRegion(pDrawable, NULL, pBox -> x1, pBox -> y1,
+ pBox -> x2 - pBox -> x1, pBox -> y2 - pBox -> y1);
+
+
+ if (REGION_NIL(pRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeBox: Resulting region [%d,%d,%d,%d] is nil. Skipping synchronization.\n",
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2);
+ #endif
+
+ nxagentFreeRegion(pDrawable, pRegion);
+
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeBox: Going to synchronize the region [%d,%d,%d,%d] of "
+ "[%s] at [%p].\n", pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2,
+ pRegion -> extents.y2, nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ nxagentSynchronizeRegion(pDrawable, pRegion, breakMask, NULL);
+
+ nxagentFreeRegion(pDrawable, pRegion);
+ }
+}
+
+void nxagentSynchronizeDrawablePredicate(void *p0, XID x1, void *p2)
+{
+ DrawablePtr pDrawable = (DrawablePtr) p0;
+ unsigned int *breakMask = (unsigned int *) p2;
+
+ int shouldClearHiddenRegion = 1;
+
+ /*
+ * The nxagentSynchronization.abort propa-
+ * gates a break condition across the resour-
+ * ces loop, in order to block also the sub-
+ * sequent synchronizations.
+ */
+
+ if (nxagentSynchronization.abort == 1 ||
+ nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ return;
+ }
+
+ /*
+ * In order to implement a kind of round-robin
+ * synchronization, the previous incomplete
+ * drawable synchronization is saved to jump
+ * to the next resource available of same type.
+ */
+
+ if (nxagentSynchronization.pDrawable != NULL &&
+ pDrawable -> type == nxagentSynchronization.drawableType)
+ {
+ if (nxagentSynchronization.pDrawable != pDrawable)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping drawable [%s][%p] while looking "
+ "for last synchronized drawable [%p].\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, (void *) nxagentSynchronization.pDrawable);
+ #endif
+
+ return;
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Last synchronized drawable [%p] found. "
+ "Skipping to the next resource.\n", (void *) nxagentSynchronization.pDrawable);
+ #endif
+
+ nxagentSynchronization.pDrawable = NULL;
+
+ return;
+ }
+ }
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ /*
+ * The pixmaps to be synchronized are those
+ * used as background or used as source of
+ * any deferred operations for at least 2
+ * times.
+ */
+
+ if (NXAGENT_SHOULD_SYNCHRONIZE_PIXMAP(pDrawable) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping pixmap at [%p] "
+ "with usage [%d] background [%d].\n", (void *) pDrawable,
+ nxagentPixmapUsageCounter((PixmapPtr) pDrawable),
+ nxagentIsCorruptedBackground((PixmapPtr) pDrawable));
+ #endif
+
+ return;
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Synchronizing pixmap at [%p] "
+ "with usage [%d] background [%d].\n", (void *) pDrawable,
+ nxagentPixmapUsageCounter((PixmapPtr) pDrawable),
+ nxagentIsCorruptedBackground((PixmapPtr) pDrawable));
+ }
+ #endif
+ }
+ else if (NXAGENT_SHOULD_SYNCHRONIZE_WINDOW(pDrawable) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping not visible window at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ if (shouldClearHiddenRegion == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Clearing out the not visible window "
+ "at [%p].\n", (void *) pDrawable);
+ #endif
+
+ nxagentCleanCorruptedDrawable(pDrawable);
+ }
+
+ return;
+ }
+
+ /*
+ * Postpone the synchronization if we went
+ * out of bandwidth or if the display blocks.
+ * The pixmap synchronization is more careful
+ * with bandwidth usage.
+ */
+
+/*
+FIXME: This condition sounds only as a
+ complication, as the break parameters
+ are already checked while synchroni-
+ zing the drawable.
+
+ if (breakOnCongestion(*breakMask) == 1 ||
+ (pDrawable -> type == DRAWABLE_PIXMAP &&
+ *breakMask != NEVER_BREAK && nxagentCongestion > 0))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: WARNING! Breaking the "
+ "synchronization with congestion [%d] blocking [%d].\n",
+ nxagentCongestion, nxagentBlocking);
+ #endif
+
+ nxagentSynchronization.abort = 1;
+
+ return;
+ }
+*/
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Synchronizing drawable [%s][%p] "
+ "with geometry (%dx%d).\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, pDrawable -> width, pDrawable -> height);
+
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Corrupted extents [%d,%d,%d,%d] "
+ "with [%ld] rects.\n", nxagentCorruptedRegion(pDrawable) -> extents.x1,
+ nxagentCorruptedRegion(pDrawable) -> extents.y1, nxagentCorruptedRegion(pDrawable) ->
+ extents.x2, nxagentCorruptedRegion(pDrawable) -> extents.y2,
+ REGION_NUM_RECTS(nxagentCorruptedRegion(pDrawable)));
+ #endif
+
+ /*
+ * The stored bitmap is destroyed inside
+ * the synchronization loop, so we have
+ * to check here its presence to know if
+ * we can clear the dirty windows.
+ */
+
+ shouldClearHiddenRegion = (nxagentDrawableBitmap(pDrawable) == NullPixmap);
+
+ nxagentSynchronizeDrawable(pDrawable, DONT_WAIT, *breakMask, NULL);
+
+ if (nxagentDrawableStatus(pDrawable) == NotSynchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Drawable [%s][%p] not fully synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ /*
+ * If the remaining corrupted region is on
+ * an hidden section (not viewable or outside
+ * of the pixmap's area) of a drawable,
+ * we can clear it.
+ */
+
+ if (nxagentSynchronization.abort == 0 &&
+ shouldClearHiddenRegion == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Clearing out the remaining corrupted "
+ "[%s] at [%p].\n", nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ nxagentCleanCorruptedDrawable(pDrawable);
+ }
+ }
+}
+
+void nxagentSynchronizationLoop(unsigned int mask)
+{
+ unsigned int breakMask;
+
+ int doRoundRobin;
+
+/*
+FIXME: All drawables should be set as synchronized and
+ never marked as corrupted while the display is
+ down.
+*/
+ if (NXDisplayError(nxagentDisplay) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: WARNING! Not synchronizing the drawables "
+ "with the display down.\n");
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Synchronizing [%d] windows [%d] pixmaps "
+ "and [%d] backgrounds with mask [%u].\n", nxagentCorruptedWindows, nxagentCorruptedPixmaps,
+ nxagentCorruptedBackgrounds, mask);
+
+ fprintf(stderr, "nxagentSynchronizationLoop: Stored bitmaps [%d] windows [%d] pixmaps "
+ "and [%d] backgrounds.\n", nxagentSynchronization.windowBitmaps,
+ nxagentSynchronization.pixmapBitmaps, nxagentSynchronization.backgroundBitmaps);
+
+ fprintf(stderr, "nxagentSynchronizationLoop: Starting loops with congestion [%d] "
+ "blocking [%d].\n", nxagentCongestion, nxagentBlocking);
+ #endif
+
+ breakMask = mask;
+
+ /*
+ * The resource counter can be reset if we
+ * have not aborted the synchronization loop,
+ * if we are not skipping resources to do
+ * round-robin and if the bitmaps are all
+ * synchronized.
+ */
+
+ doRoundRobin = (nxagentSynchronization.pDrawable != NULL);
+
+ nxagentSynchronization.abort = 0;
+
+ /*
+ * Synchronize the windows.
+ */
+
+ if (NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_WINDOWS(mask))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted window resources.\n");
+ #endif
+
+ FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_WINDOW,
+ nxagentSynchronizeDrawablePredicate, &breakMask);
+
+ #ifdef TEST
+
+ if (nxagentSynchronization.abort == 0 &&
+ nxagentSynchronization.windowBitmaps == 0 &&
+ doRoundRobin == 0)
+ {
+ if (nxagentCorruptedWindows > 0)
+ {
+ fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] "
+ "corrupted windows.\n", nxagentCorruptedWindows);
+ }
+
+ nxagentCorruptedWindows = 0;
+ }
+
+ #endif
+ }
+
+ /*
+ * Synchronize the backgrounds.
+ */
+
+ if (nxagentSynchronization.abort == 0 &&
+ NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_BACKGROUNDS(mask))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted background resources.\n");
+ #endif
+
+ FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_BACKGROUND,
+ nxagentSynchronizeDrawablePredicate, &breakMask);
+
+ #ifdef TEST
+
+ if (nxagentSynchronization.abort == 0 &&
+ nxagentSynchronization.backgroundBitmaps == 0 &&
+ doRoundRobin == 0)
+ {
+ if (nxagentCorruptedBackgrounds > 0)
+ {
+ fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] "
+ "corrupted backgrounds.\n", nxagentCorruptedBackgrounds);
+ }
+
+ nxagentCorruptedBackgrounds = 0;
+ }
+
+ #endif
+ }
+
+ /*
+ * If there is bandwidth remaining, synchronize
+ * the pixmaps. Synchronizing a pixmap doesn't
+ * produce any visible results. Better is to
+ * synchronize them on demand, before using the
+ * pixmap in a copy or in a composite operation.
+ */
+
+ if (nxagentSynchronization.abort == 0 &&
+ NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_PIXMAPS(mask))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted pixmap resources.\n");
+ #endif
+
+ FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_PIXMAP,
+ nxagentSynchronizeDrawablePredicate, &breakMask);
+
+
+ if (nxagentSynchronization.abort == 0 &&
+ nxagentSynchronization.pixmapBitmaps == 0 &&
+ doRoundRobin == 0)
+ {
+ #ifdef TEST
+
+ if (nxagentCorruptedPixmaps > 0)
+ {
+ fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] "
+ "corrupted pixmaps.\n", nxagentCorruptedPixmaps);
+ }
+
+ #endif
+
+ nxagentCorruptedPixmaps = 0;
+ }
+
+ }
+
+ /*
+ * If the last synchronized drawable has been
+ * removed, we have to reset the variable sto-
+ * ring its pointer.
+ */
+
+ if (nxagentSynchronization.pDrawable != NULL &&
+ nxagentFindClientResource(serverClient -> index, RT_NX_CORR_WINDOW,
+ nxagentSynchronization.pDrawable) == 0 &&
+ nxagentFindClientResource(serverClient -> index, RT_NX_CORR_BACKGROUND,
+ nxagentSynchronization.pDrawable) == 0 &&
+ nxagentFindClientResource(serverClient -> index, RT_NX_CORR_PIXMAP,
+ nxagentSynchronization.pDrawable) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Synchronization drawable [%p] removed from resources.\n",
+ (void *) nxagentSynchronization.pDrawable);
+ #endif
+
+ nxagentSynchronization.pDrawable = NULL;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizationLoop: Closing loops with congestion [%d] "
+ "blocking [%d].\n", nxagentCongestion, nxagentBlocking);
+
+ fprintf(stderr, "nxagentSynchronizationLoop: There are now [%d] windows [%d] pixmaps "
+ "and [%d] backgrounds to synchronize.\n", nxagentCorruptedWindows,
+ nxagentCorruptedPixmaps, nxagentCorruptedBackgrounds);
+ #endif
+}
+
+RegionPtr nxagentCreateRegion(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+ int width, int height)
+{
+ RegionPtr pRegion;
+ BoxRec box;
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + width;
+ box.y2 = y + height;
+
+ pRegion = REGION_CREATE(pDrawable -> pScreen, &box, 1);
+
+ /*
+ * Clipping the region.
+ */
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ BoxRec tmpBox;
+ RegionRec tmpRegion;
+
+ /*
+ * The region created doesn't need to be clipped
+ * if it has the pixmap dimensions.
+ */
+
+ if (x != 0 || y != 0 ||
+ width != pDrawable -> width ||
+ height != pDrawable -> height)
+ {
+ tmpBox.x1 = 0;
+ tmpBox.y1 = 0;
+ tmpBox.x2 = pDrawable -> width;
+ tmpBox.y2 = pDrawable -> height;
+
+ REGION_INIT(pDrawable -> pScreen, &tmpRegion, &tmpBox, 1);
+
+ REGION_INTERSECT(pDrawable -> pScreen, pRegion, &tmpRegion, pRegion);
+
+ REGION_UNINIT(pDrawable -> pScreen, &tmpRegion);
+ }
+ }
+ else
+ {
+ /*
+ * We use the clipList because the borderClip
+ * contains also parts of the window covered
+ * by its children.
+ */
+
+ REGION_TRANSLATE(pDrawable -> pScreen, pRegion,
+ pDrawable -> x, pDrawable -> y);
+
+ if (nxagentWindowPriv((WindowPtr) pDrawable) -> hasTransparentChildren == 1)
+ {
+ REGION_INTERSECT(pDrawable -> pScreen, pRegion, pRegion, &((WindowPtr) pDrawable) -> borderClip);
+ }
+ else
+ {
+ REGION_INTERSECT(pDrawable -> pScreen, pRegion, pRegion, &((WindowPtr) pDrawable) -> clipList);
+ }
+
+ REGION_TRANSLATE(pDrawable -> pScreen, pRegion,
+ -pDrawable -> x, -pDrawable -> y);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateRegion: New region created with coordinates [%d,%d,%d,%d].\n",
+ pRegion -> extents.x1, pRegion -> extents.y1,
+ pRegion -> extents.x2, pRegion -> extents.y2);
+ #endif
+
+ /*
+ * If the pRegion is NIL we don't need
+ * to intersect it with the GC's clipmask.
+ */
+
+ if (REGION_NIL(pRegion) == 0 &&
+ pGC != NULL && pGC -> clientClip != NULL &&
+ pGC -> clientClipType == CT_REGION)
+ {
+ RegionRec clipRegion;
+
+ REGION_INIT(pDrawable -> pScreen, &clipRegion, NullBox, 1);
+
+ REGION_COPY(pDrawable -> pScreen, &clipRegion, (RegionPtr) pGC -> clientClip);
+
+ /*
+ * The clip origin is relative to the origin of
+ * the destination drawable. The clip mask coor-
+ * dinates are relative to the clip origin.
+ */
+
+ if (pGC -> clipOrg.x != 0 || pGC -> clipOrg.y != 0)
+ {
+ REGION_TRANSLATE(pDrawable -> pScreen, &clipRegion, pGC -> clipOrg.x, pGC -> clipOrg.y);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateRegion: Clipping region to the clip mask with coordinates [%d,%d,%d,%d].\n",
+ clipRegion.extents.x1, clipRegion.extents.y1,
+ clipRegion.extents.x2, clipRegion.extents.y2);
+ #endif
+
+ REGION_INTERSECT(pDrawable -> pScreen, pRegion, pRegion, &clipRegion);
+
+ REGION_UNINIT(pDrawable -> pScreen, &clipRegion);
+ }
+
+ return pRegion;
+}
+
+void nxagentMarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ int x;
+ int y;
+ int width;
+ int height;
+
+ if (pRegion != NullRegion && REGION_NIL(pRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentMarkCorruptedRegion: Region [%d,%d,%d,%d] is nil. Skipping operation.\n",
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2);
+ #endif
+
+ return;
+ }
+
+ /*
+ * If the drawable was synchronized, the counter
+ * reporting the number of corrupted drawables
+ * must be increased. Moreover the corrupted ti-
+ * mestamp must be set.
+ */
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ if (pDrawable -> type == DRAWABLE_WINDOW)
+ {
+ nxagentAllocateCorruptedResource(pDrawable, RT_NX_CORR_WINDOW);
+ }
+
+ nxagentSetCorruptedTimestamp(pDrawable);
+ }
+
+ if (pRegion == NullRegion)
+ {
+ x = 0;
+ y = 0;
+
+ width = pDrawable -> width;
+ height = pDrawable -> height;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentMarkCorruptedRegion: Fully invalidating %s [%p] with "
+ "coordinates [%d,%d][%d,%d].\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, x, y, width, height);
+ #endif
+
+ pRegion = nxagentCreateRegion(pDrawable, NULL, x, y, width, height);
+
+ nxagentValidateSplit(pDrawable, pRegion);
+
+ REGION_UNION(pDrawable -> pScreen, nxagentCorruptedRegion(pDrawable),
+ nxagentCorruptedRegion(pDrawable), pRegion);
+
+ nxagentFreeRegion(pDrawable, pRegion);
+ }
+ else
+ {
+ #ifdef TEST
+
+ x = pRegion -> extents.x1;
+ y = pRegion -> extents.y1;
+
+ width = pRegion -> extents.x2 - pRegion -> extents.x1;
+ height = pRegion -> extents.y2 - pRegion -> extents.y1;
+
+ fprintf(stderr, "nxagentMarkCorruptedRegion: Partly invalidating %s [%p] with "
+ "coordinates [%d,%d][%d,%d].\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable, x, y, width, height);
+
+ #endif
+
+ nxagentValidateSplit(pDrawable, pRegion);
+
+ REGION_UNION(pDrawable -> pScreen, nxagentCorruptedRegion(pDrawable),
+ nxagentCorruptedRegion(pDrawable), pRegion);
+ }
+}
+
+void nxagentUnmarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ int oldStatus;
+
+ if (pRegion != NullRegion && REGION_NIL(pRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentUnmarkCorruptedRegion: Region [%d,%d,%d,%d] is nil. Skipping operation.\n",
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2);
+ #endif
+
+ return;
+ }
+
+ oldStatus = nxagentDrawableStatus(pDrawable);
+
+ if (oldStatus == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentUnmarkCorruptedRegion: Drawable %s [%p] already synchronized.\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ if (pRegion == NullRegion)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentUnmarkCorruptedRegion: Fully validating %s [%p].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ nxagentValidateSplit(pDrawable, NULL);
+
+ REGION_EMPTY(pDrawable -> pScreen, nxagentCorruptedRegion(pDrawable));
+ }
+ else
+ {
+ #ifdef TEST
+
+ fprintf(stderr, "nxagentUnmarkCorruptedRegion: Validating %s [%p] with region [%d,%d,%d,%d].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable,
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2);
+
+ #endif
+
+ nxagentValidateSplit(pDrawable, pRegion);
+
+ REGION_SUBTRACT(pDrawable -> pScreen, nxagentCorruptedRegion(pDrawable),
+ nxagentCorruptedRegion(pDrawable), pRegion);
+ }
+
+ /*
+ * If the drawable becomes synchronized, the
+ * counter reporting the number of corrupted
+ * drawables must be decreased. Moreover the
+ * corrupted timestamp must be reset.
+ */
+
+ if (oldStatus == NotSynchronized &&
+ nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_BACKGROUND);
+
+ nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_PIXMAP);
+
+ nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> containTrapezoids = 0;
+ }
+ else
+ {
+ nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_WINDOW);
+ }
+
+ nxagentResetCorruptedTimestamp(pDrawable);
+
+ /*
+ * If the resource is no longer dirty,
+ * the associated bitmap is destroyed.
+ */
+
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ nxagentDestroyDrawableBitmap(pDrawable);
+ }
+ }
+}
+
+void nxagentMoveCorruptedRegion(WindowPtr pWin, unsigned int mask)
+{
+ /*
+ * If a window is resized, its corrupted
+ * region is moved according to the bit
+ * gravity.
+ */
+
+ if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized)
+ {
+ if (((mask & CWHeight) && nxagentWindowPriv(pWin) -> height != pWin -> drawable.height) ||
+ ((mask & CWWidth) && nxagentWindowPriv(pWin) -> width != pWin -> drawable.width))
+ {
+ int nx, ny;
+
+ GravityTranslate(0, 0,
+ nxagentWindowPriv(pWin) -> x - pWin -> origin.x + wBorderWidth(pWin),
+ nxagentWindowPriv(pWin) -> y - pWin -> origin.y + wBorderWidth(pWin),
+ pWin -> drawable.width - nxagentWindowPriv(pWin) -> width,
+ pWin -> drawable.height - nxagentWindowPriv(pWin) -> height,
+ pWin -> bitGravity, &nx, &ny);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentMoveCorruptedRegion: Moving the corrupted region to [%d,%d] for window [%p].\n",
+ nx, ny, (void *) pWin);
+ #endif
+
+ REGION_TRANSLATE(pWin -> pScreen, nxagentCorruptedRegion((DrawablePtr) pWin),
+ nx, ny);
+
+ /*
+ * Having moved the corrupted region, we
+ * need to invalidate the pending commits
+ * or otherwise the image will fall in
+ * the wrong area.
+ */
+
+ nxagentValidateSplit((DrawablePtr) pWin, NULL);
+
+
+ /*
+ * The window reconfiguration invalidates
+ * the synchronization bitmap.
+ */
+
+ nxagentDestroyDrawableBitmap((DrawablePtr) pWin);
+ }
+ }
+}
+
+/*
+ * The DDX layer uses an 'Y-X banding' representation of
+ * regions: it sorts all rectangles composing a region
+ * using first the y-dimension, than the x-dimension; mo-
+ * reover it organizes the rectangles in 'bands' sharing
+ * the same y-dimension. This representation does not mi-
+ * nimize the number of rectangles. For example, the fol-
+ * lowing region has 4 rectangles:
+ *
+ * +-----------+
+ * | | +---+
+ * | A | | B |
+ * | | +---+
+ * +-----------+
+ *
+ * The rectangle 'B' creates a band which splits the rec-
+ * tangle A in 3 parts, for a total of 3 bands. The num-
+ * ber of rectangles composing the region is 4.
+ *
+ * This kind of representation is not advisable for the
+ * lazy synchronization because, in the example above,
+ * the nxagent had to send 4 put images instead of 2.
+ *
+ * To minimize the problem we use the following function:
+ * by traversing the list of rectangles we merge all bo-
+ * xes with same x coordinates and coincident y, in order
+ * to create an X-Y banding.
+ *
+ * Be careful: all the coordinates of boxes merged are
+ * set to 0, so take care of this when looping through
+ * the box list returned by this function.
+ */
+
+BoxPtr nxagentGetOptimizedRegionBoxes(RegionPtr pRegion)
+{
+ BoxPtr pBox;
+
+ BoxRec boxExtents;
+
+ int nBox;
+ int i, j;
+
+ #ifdef DEBUG
+ int nBoxOptim;
+ #endif
+
+ pBox = REGION_RECTS(pRegion);
+
+ nBox = REGION_NUM_RECTS(pRegion);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to optimize region at [%p] with [%d] rects.\n",
+ (void *) pRegion, nBox);
+ #endif
+
+ if (nBox <= 1)
+ {
+ return pBox;
+ }
+
+ #ifdef DEBUG
+ nBoxOptim = nBox;
+ #endif
+
+ /*
+ * The boxes are now grouped to grown as much
+ * as possible, using their overlapping vertex
+ * as rule.
+ */
+
+ for (i = 0; i < nBox; i++)
+ {
+ /*
+ * If the coordinates are (0,0) the box
+ * has been already merged, so we can skip
+ * it.
+ */
+
+ if (pBox[i].x1 == 0 && pBox[i].y1 == 0 &&
+ pBox[i].x2 == 0 && pBox[i].y2 == 0)
+ {
+ continue;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Referential box [%d] has coordinates [%d,%d,%d,%d].\n",
+ i, pBox[i].x1, pBox[i].y1, pBox[i].x2, pBox[i].y2);
+ #endif
+
+ #ifdef ADVANCED_BOXES_DEFRAG
+
+ boxExtents.x1 = pBox[i].x1;
+ boxExtents.y1 = pBox[i].y1;
+ boxExtents.x2 = pBox[i].x2;
+
+ #endif
+
+ boxExtents.y2 = pBox[i].y2;
+
+ for (j = i+1; j < nBox; j++)
+ {
+ if (pBox[j].x1 == 0 && pBox[j].y1 == 0 &&
+ pBox[j].x2 == 0 && pBox[j].y2 == 0)
+ {
+ continue;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Mergeable box [%d] has coordinates [%d,%d,%d,%d].\n",
+ j, pBox[j].x1, pBox[j].y1, pBox[j].x2, pBox[j].y2);
+ #endif
+
+ /*
+ * Each consequent box is merged if its
+ * higher side overlaps the lower side
+ * of current box.
+ * In case of ADVANCED_BOXES_DEFRAG the higher
+ * side must be included within a range
+ * defined by INCLUDE_MARGIN.
+ */
+
+ #ifndef ADVANCED_BOXES_DEFRAG
+
+ if (pBox[j].y1 == boxExtents.y2 &&
+ pBox[j].x1 == pBox[i].x1 &&
+ pBox[j].x2 == pBox[i].x2)
+
+ #else
+
+ if (pBox[j].x1 > boxExtents.x1 - INCLUDE_MARGIN &&
+ pBox[j].x1 < boxExtents.x1 + INCLUDE_MARGIN &&
+ pBox[j].y1 > boxExtents.y2 - INCLUDE_MARGIN &&
+ pBox[j].y1 < boxExtents.y2 + INCLUDE_MARGIN &&
+ pBox[j].x2 > boxExtents.x2 - INCLUDE_MARGIN &&
+ pBox[j].x2 < boxExtents.x2 + INCLUDE_MARGIN)
+
+ #endif
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to merge box at [%d] with box at [%d].\n",
+ j, i);
+ #endif
+
+ #ifdef ADVANCED_BOXES_DEFRAG
+
+ if (pBox[j].x1 < boxExtents.x1)
+ {
+ boxExtents.x1 = pBox[j].x1;
+ }
+
+ if (pBox[j].x2 > boxExtents.x2)
+ {
+ boxExtents.x2 = pBox[j].x2;
+ }
+
+ if (pBox[j].y1 < boxExtents.y1)
+ {
+ boxExtents.y1 = pBox[j].y1;
+ }
+
+ #endif
+
+ if (pBox[j].y2 > boxExtents.y2)
+ {
+ boxExtents.y2 = pBox[j].y2;
+ }
+
+ /*
+ * By appending a box to another, we have
+ * to remove it from the box list. We do
+ * this by setting its coordinates to (0,0)
+ * and by checking their value in the main
+ * loop.
+ */
+
+ pBox[j].x1 = pBox[j].y1 = pBox[j].x2 = pBox[j].y2 = 0;
+
+ #ifdef DEBUG
+ nBoxOptim--;
+ #endif
+ }
+ }
+
+ /*
+ * Extend the box height.
+ */
+
+ #ifdef ADVANCED_BOXES_DEFRAG
+
+ pBox[i].x1 = boxExtents.x1;
+ pBox[i].y1 = boxExtents.y1;
+ pBox[i].x2 = boxExtents.x2;
+
+ #endif
+
+ pBox[i].y2 = boxExtents.y2;
+ }
+
+ #ifdef ADVANCED_BOXES_DEFRAG
+
+ /*
+ * The new list need to be validated to
+ * avoid boxes overlapping. This code may
+ * be improved to remove also the partial-
+ * ly overlapping boxes.
+ */
+
+ for (i = 0; i < nBox; i++)
+ {
+ if (pBox[i].x1 == 0 && pBox[i].y1 == 0 &&
+ pBox[i].x2 == 0 && pBox[i].y2 == 0)
+ {
+ continue;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Referential box [%d] has coordinates [%d,%d,%d,%d].\n",
+ i, pBox[i].x1, pBox[i].y1, pBox[i].x2, pBox[i].y2);
+ #endif
+
+ boxExtents.x1 = pBox[i].x1;
+ boxExtents.y1 = pBox[i].y1;
+ boxExtents.x2 = pBox[i].x2;
+ boxExtents.y2 = pBox[i].y2;
+
+ for (j = i+1; j < nBox; j++)
+ {
+ if (pBox[j].x1 == 0 && pBox[j].y1 == 0 &&
+ pBox[j].x2 == 0 && pBox[j].y2 == 0)
+ {
+ continue;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Mergeable box [%d] has coordinates [%d,%d,%d,%d].\n",
+ j, pBox[j].x1, pBox[j].y1, pBox[j].x2, pBox[j].y2);
+ #endif
+
+ if ((boxExtents.x1 <= pBox[j].x1 &&
+ boxExtents.x2 >= pBox[j].x2 &&
+ boxExtents.y1 <= pBox[j].y1 &&
+ boxExtents.y2 >= pBox[j].y2))
+ {
+ /*
+ * If a box is completely inside
+ * another, we set its coordinates
+ * to 0 to consider it as merged.
+ */
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to merge box [%d,%d,%d,%d] "
+ "with its box container [%d,%d,%d,%d].\n", pBox[j].x1, pBox[j].y1,
+ pBox[j].x2, pBox[j].y2, boxExtents.x1, boxExtents.y1, boxExtents.y1,
+ boxExtents.y2);
+ #endif
+
+ pBox[j].x1 = pBox[j].y1 = pBox[j].x2 = pBox[j].y2 = 0;
+
+ #ifdef DEBUG
+ nBoxOptim--;
+ #endif
+ }
+ }
+ }
+
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Original boxes number [%d] Optimized boxes number [%d].\n",
+ nBox, nBoxOptim);
+ #endif
+
+ return pBox;
+}
+
+unsigned long nxagentGetColor(DrawablePtr pDrawable, int xPixel, int yPixel)
+{
+ XImage *ximage;
+ Visual *pVisual;
+ char *data;
+
+ int depth, format, length;
+ int leftPad = 0;
+ unsigned long pixel;
+
+ depth = pDrawable -> depth;
+ format = (depth == 1) ? XYPixmap : ZPixmap;
+ length = nxagentImageLength(1, 1, format, leftPad, depth);
+
+ if ((data = xalloc(length)) == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentGetColor: WARNING! Failed to allocate memory for the operation.\n");
+ #endif
+
+ return -1;
+ }
+
+ pVisual = nxagentImageVisual(pDrawable, depth);
+
+ if (pVisual == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentGetColor: WARNING! Visual not found. Using default visual.\n");
+ #endif
+
+ pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual;
+ }
+
+ fbGetImage(pDrawable, xPixel, yPixel, 1, 1, format, AllPlanes, data);
+
+ ximage = XCreateImage(nxagentDisplay, pVisual, depth, format, leftPad, (char *) data,
+ 1, 1, BitmapPad(nxagentDisplay),
+ nxagentImagePad(1, format, leftPad, 1));
+
+ if (ximage == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentGetColor: WARNING! Failed to create the XImage.\n");
+ #endif
+
+ xfree(data);
+
+ return -1;
+ }
+
+ pixel = XGetPixel(ximage, 0, 0);
+
+ XDestroyImage(ximage);
+
+ return pixel;
+}
+
+/*
+ * This function could be used to determine
+ * the ClearArea color of corrupted regions
+ * on screen.
+ */
+
+unsigned long nxagentGetRegionColor(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ int xPicker, yPicker;
+
+ if (REGION_NIL(pRegion) == 1)
+ {
+ return nxagentGetDrawableColor(pDrawable);
+ }
+
+ /*
+ * The pixel used as reference is the first
+ * outer pixel at the bottom right corner
+ * of corrupted region extents.
+ */
+
+ xPicker = pRegion -> extents.x2 + 1;
+
+ if (xPicker > pDrawable -> width)
+ {
+ xPicker = pDrawable -> width;
+ }
+
+ yPicker = pRegion -> extents.y2 + 1;
+
+ if (yPicker > pDrawable -> height)
+ {
+ yPicker = pDrawable -> height;
+ }
+
+ return nxagentGetColor(pDrawable, xPicker, yPicker);
+}
+
+unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable)
+{
+ int xPicker, yPicker;
+
+ /*
+ * The pixel used to determine the co-
+ * lor of a drawable is at coordinates
+ * (x + width - 4, y + 4).
+ */
+
+ xPicker = pDrawable -> width - 4;
+
+ yPicker = 4;
+
+ return nxagentGetColor(pDrawable, xPicker, yPicker);
+}
+
+void nxagentClearRegion(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ WindowPtr pWin;
+ BoxPtr pBox;
+
+ unsigned long color;
+ unsigned long backupPixel = 0;
+ int nBox, i;
+ int restore;
+
+ #ifdef DEBUG
+ static int nBoxCleared;
+ #endif
+
+ if (pDrawable -> type != DRAWABLE_WINDOW)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentClearRegion: Cannot clear a pixmap. Exiting.\n");
+ #endif
+
+ return;
+ }
+
+ if (pRegion == NullRegion || REGION_NIL(pRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentClearRegion: The region is empty. Exiting.\n");
+ #endif
+
+ return;
+ }
+
+ pWin = (WindowPtr) pDrawable;
+
+ restore = 0;
+
+ /*
+ * If the window has already a background, we
+ * can hope it will be nice.
+ */
+
+ if (pWin -> backgroundState != None)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClearRegion: Window at [%p] has background state [%u].\n",
+ (void *) pWin, pWin -> backgroundState);
+ #endif
+ }
+ else
+ {
+ /*
+ * Save the original state.
+ */
+
+ backupPixel = pWin -> background.pixel;
+
+ color = nxagentGetDrawableColor((DrawablePtr) pWin);
+
+ if (color == -1)
+ {
+ color = 0xffffff;
+ }
+
+ pWin -> backgroundState = BackgroundPixel;
+ pWin -> background.pixel = color;
+
+ nxagentChangeWindowAttributes(pWin, CWBackPixel);
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClearRegion: Window at [%p] now has pixel background [%ld].\n",
+ (void *) pWin, color);
+ #endif
+
+ restore = 1;
+ }
+
+ pBox = nxagentGetOptimizedRegionBoxes(pRegion);
+
+ nBox = REGION_NUM_RECTS(pRegion);
+
+ for (i = 0; i < nBox; i++)
+ {
+ if (pBox[i].x1 == 0 && pBox[i].y1 == 0 &&
+ pBox[i].x2 == 0 && pBox[i].y2 == 0)
+ {
+ continue;
+ }
+
+ XClearArea(nxagentDisplay, nxagentWindow(pWin), pBox[i].x1, pBox[i].y1,
+ pBox[i].x2 - pBox[i].x1, pBox[i].y2 - pBox[i].y1, False);
+
+ #ifdef DEBUG
+ nBoxCleared++;
+ #endif
+ }
+
+ /*
+ * Restore the old state.
+ */
+
+ if (restore == 1)
+ {
+ pWin -> backgroundState = None;
+ pWin -> background.pixel = backupPixel;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClearRegion: Number of cleared boxes is [%d].\n", nBoxCleared);
+ #endif
+}
+
+void nxagentFillRemoteRegion(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ GCPtr pGC;
+ BoxPtr pBox;
+ XRectangle *pRects;
+
+ int nrects;
+ int i;
+
+ if (REGION_NIL(pRegion) == 1)
+ {
+ return;
+ }
+
+ pGC = nxagentGetGraphicContext(pDrawable);
+
+ nrects = REGION_NUM_RECTS(pRegion);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentFillRemoteRegion: Going to fill remote region [%d,%d,%d,%d] rects [%d] with color [%lu].\n",
+ pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2,
+ nrects, pGC -> fgPixel);
+ #endif
+
+ if (nrects == 1)
+ {
+ XFillRectangle(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC),
+ pRegion -> extents.x1, pRegion -> extents.y1,
+ pRegion -> extents.x2 - pRegion -> extents.x1,
+ pRegion -> extents.y2 - pRegion -> extents.y1);
+ }
+ else
+ {
+ pBox = REGION_RECTS(pRegion);
+
+ pRects = xalloc(nrects * sizeof(XRectangle));
+
+ for (i = 0; i < nrects; i++)
+ {
+ pRects[i].x = pBox[i].x1;
+ pRects[i].y = pBox[i].y1;
+ pRects[i].width = pBox[i].x2 - pBox[i].x1;
+ pRects[i].height = pBox[i].y2 - pBox[i].y1;
+ }
+
+ XFillRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC),
+ pRects, nrects);
+
+ xfree(pRects);
+ }
+}
+
+int nxagentDestroyCorruptedWindowResource(pointer p, XID id)
+{
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedWindowResource: Removing corrupted window [%p] from resources.\n",
+ (void *) p);
+ #endif
+
+ nxagentWindowPriv((WindowPtr) p) -> corruptedId = None;
+
+ return 1;
+}
+
+int nxagentDestroyCorruptedPixmapResource(pointer p, XID id)
+{
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedPixmapResource: Removing corrupted pixmap [%p] from resources.\n",
+ (void *) p);
+ #endif
+
+ nxagentPixmapPriv((PixmapPtr) p) -> corruptedId = None;
+
+ return 1;
+}
+
+int nxagentDestroyCorruptedBackgroundResource(pointer p, XID id)
+{
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedBackgroundResource: Removing corrupted pixmap background [%p] from resources.\n",
+ (void *) p);
+ #endif
+
+ nxagentPixmapPriv((PixmapPtr) p) -> corruptedBackgroundId = None;
+
+ return 1;
+}
+
+void nxagentPointsToDirtyRegion(DrawablePtr pDrawable, int mode,
+ int nPoints, xPoint *pPoints)
+{
+ RegionPtr pRegion;
+ RegionRec tmpRegion;
+ BoxRec box, extents;
+
+ xPoint *xp;
+ int np;
+
+ np = nPoints;
+ xp = pPoints;
+
+ pRegion = REGION_CREATE(pDrawable -> pScreen, NullBox, 1);
+
+ while (np--)
+ {
+ if (CoordModePrevious)
+ {
+ box.x1 = box.x2 = (xp-1) -> x + xp -> x;
+ box.y1 = box.y2 = (xp-1) -> y + xp -> y;
+ }
+ else
+ {
+ box.x1 = box.x2 = xp -> x;
+ box.y1 = box.y2 = xp -> y;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentPointsToDirtyRegion: Adding the point (%d,%d) to the dirty region.\n",
+ box.x1, box.y1);
+ #endif
+
+ /*
+ * By using REGION_APPEND() and REGION_VALIDATE()
+ * this loop could become less expensive.
+ */
+
+ REGION_INIT(pDrawable -> pScreen, &tmpRegion, &box, 1);
+
+ REGION_UNION(pDrawable -> pScreen, pRegion, pRegion, &tmpRegion);
+
+ REGION_UNINIT(pDrawable -> pScreen, &tmpRegion);
+
+ xp++;
+ }
+
+ extents = *REGION_EXTENTS(pDrawable -> pScreen, pRegion);
+
+ REGION_RESET(pDrawable -> pScreen, pRegion, &extents);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentPointsToDirtyRegion: The resulting dirty region has [%ld] rects and"
+ " extents (%d,%d,%d,%d).\n", REGION_NUM_RECTS(pRegion), extents.x1,
+ extents.y1, extents.x2, extents.y2);
+ #endif
+
+ nxagentMarkCorruptedRegion(pDrawable, pRegion);
+
+ REGION_DESTROY(pDrawable -> pScreen, pRegion);
+}
+
+#ifdef DUMP
+
+#define USE_MULTIPLE_COLORS
+
+void nxagentCorruptedRegionOnWindow(void *p0, XID x, void *p2)
+{
+ WindowPtr pWin = (WindowPtr) p0;
+ RegionPtr clipRegion;
+ RegionRec visRegion;
+ BoxPtr pBox;
+
+ XlibGC gc;
+ XGCValues value;
+
+ static unsigned long color = 0xff000000;
+ int nrectangles;
+ int i;
+
+ /*
+ * There are no regions to draw.
+ */
+
+ if (nxagentDrawableStatus((DrawablePtr) pWin) == Synchronized)
+ {
+ return;
+ }
+
+ /*
+ * The window is not visible.
+ */
+
+ if (nxagentWindowIsVisible(pWin) == 0)
+ {
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCorruptedRegionOnWindow: Going to draw on window at [%p].\n",
+ (void *) pWin);
+ #endif
+
+ clipRegion = nxagentCreateRegion((DrawablePtr) pWin, NULL, 0, 0,
+ pWin -> drawable.width, pWin -> drawable.height);
+
+ REGION_INIT(pWin -> drawable.pScreen, &visRegion, NullBox, 1);
+
+ REGION_INTERSECT(pWin -> drawable.pScreen, &visRegion, clipRegion, nxagentCorruptedRegion((DrawablePtr) pWin));
+
+ nxagentFreeRegion(pWin -> drawable.pScreen, clipRegion);
+
+ if (REGION_NIL(&visRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentCorruptedRegionOnWindow: The corrupted region of window at [%p] is hidden.\n",
+ (void *) pWin);
+ #endif
+
+ REGION_UNINIT(pWin -> drawable.pScreen, &visRegion);
+
+ return;
+ }
+
+ nxagentClearRegion((DrawablePtr) pWin, &visRegion);
+
+ #ifdef USE_MULTIPLE_COLORS
+
+ color += nxagentWindow(pWin) * 5;
+
+ if (color == 0 || color == 0xffffffff)
+ {
+ color = 0xff000000;
+ }
+
+ #endif
+
+ value.foreground = color;
+ value.subwindow_mode = IncludeInferiors;
+
+ gc = XCreateGC(nxagentDisplay, nxagentWindow(pWin), GCForeground | GCSubwindowMode, &value);
+
+ nrectangles = REGION_NUM_RECTS(&visRegion);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCorruptedRegionOnWindow: Going to draw the region with extents [%d,%d,%d,%d] and [%d] rects.\n",
+ visRegion.extents.x1, visRegion.extents.y1, visRegion.extents.x2, visRegion.extents.y2,
+ nrectangles);
+ #endif
+
+ pBox = nxagentGetOptimizedRegionBoxes(&visRegion);
+
+ for (i = 0; i < nrectangles; i++)
+ {
+ if (pBox[i].x1 == 0 && pBox[i].y1 == 0 &&
+ pBox[i].x2 == 0 && pBox[i].y2 == 0)
+ {
+ continue;
+ }
+
+ XDrawRectangle(nxagentDisplay, nxagentWindow(pWin), gc,
+ pBox[i].x1, pBox[i].y1, pBox[i].x2 - pBox[i].x1 - 1,
+ pBox[i].y2 - pBox[i].y1 - 1);
+ }
+
+ XFreeGC(nxagentDisplay, gc);
+
+ REGION_UNINIT(pWin -> drawable.pScreen, &visRegion);
+}
+
+void nxagentRegionsOnScreen()
+{
+ FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_WINDOW,
+ nxagentCorruptedRegionOnWindow, NULL);
+}
+
+#endif
+
+/*
+ * If the synchronization loop breaks and the
+ * drawable synchronization cannot be completed,
+ * the remaining data is stored in a bitmap.
+ * The synchronization loop is then restarted
+ * using the bitmap as source instead of the
+ * drawable.
+ */
+
+void nxagentCreateDrawableBitmap(DrawablePtr pDrawable)
+{
+ PixmapPtr pBitmap;
+ GCPtr pGC = NULL;
+ RegionPtr pClipRegion = NullRegion;
+
+ int x, y;
+ int w, h;
+ int saveTrap;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateDrawableBitmap: Creating synchronization bitmap for [%s] at [%p].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ /*
+ * The bitmap is created only in the
+ * nxagent.
+ */
+
+ saveTrap = nxagentGCTrap;
+
+ nxagentGCTrap = 1;
+
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateDrawableBitmap: The drawable is already synchronized. Skipping bitmap creation.\n");
+ #endif
+
+ goto nxagentCreateDrawableBitmapEnd;
+ }
+
+ /*
+ * Should create a function to append
+ * a bitmap to another, instead of de-
+ * stroy the old one.
+ */
+
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentCreateDrawableBitmap: WARNING! Going to replace the bitmap at [%p] with corrupted [%d,%d,%d,%d].\n",
+ (void *) nxagentDrawableBitmap(pDrawable),
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2);
+ #endif
+
+ nxagentDestroyDrawableBitmap(pDrawable);
+ }
+
+ /*
+ * Clipping to the visible area.
+ */
+
+ pClipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height);
+
+ REGION_INTERSECT(pDrawable -> pScreen, pClipRegion, pClipRegion, nxagentCorruptedRegion(pDrawable));
+
+ if (REGION_NIL(pClipRegion) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateDrawableBitmap: The corrupted region is not visible. Skipping bitmap creation.\n");
+ #endif
+
+ goto nxagentCreateDrawableBitmapEnd;
+ }
+
+ /*
+ * FIXME: A better way it would be create the bitmap
+ * with the same extents of the clipRegion. This
+ * requires to save the offset with respect to the
+ * drawable origin like in the backing store. This
+ * becomes particularly important when the drawable
+ * is a huge window, because the pixmap creation
+ * would fail.
+ */
+
+ pBitmap = nxagentCreatePixmap(pDrawable -> pScreen, pDrawable -> width, pDrawable -> height, pDrawable -> depth);
+
+ if (pBitmap == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentCreateDrawableBitmap: Cannot create pixmap for the bitmap data.\n");
+ #endif
+
+ goto nxagentCreateDrawableBitmapEnd;
+ }
+
+ pGC = GetScratchGC(pBitmap -> drawable.depth, pBitmap -> drawable.pScreen);
+
+ ValidateGC((DrawablePtr) pBitmap, pGC);
+
+ x = pClipRegion -> extents.x1;
+ y = pClipRegion -> extents.y1;
+ w = pClipRegion -> extents.x2 - pClipRegion -> extents.x1;
+ h = pClipRegion -> extents.y2 - pClipRegion -> extents.y1;
+
+ nxagentCopyArea(pDrawable, (DrawablePtr) pBitmap, pGC, x, y, w, h, x, y);
+
+ REGION_UNION(pDrawable -> pScreen, nxagentCorruptedRegion((DrawablePtr) pBitmap),
+ nxagentCorruptedRegion((DrawablePtr) pBitmap), pClipRegion);
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> synchronizationBitmap = pBitmap;
+
+ if (nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1)
+ {
+ nxagentSynchronization.backgroundBitmaps++;
+ }
+ else
+ {
+ nxagentSynchronization.pixmapBitmaps++;
+ }
+ }
+ else
+ {
+ nxagentWindowPriv((WindowPtr) pDrawable) -> synchronizationBitmap = pBitmap;
+
+ nxagentSynchronization.windowBitmaps++;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateDrawableBitmap: Drawable [%p] has bitmap at [%p] with corrupted [%d,%d,%d,%d].\n",
+ (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable),
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2,
+ nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2);
+ #endif
+
+nxagentCreateDrawableBitmapEnd:
+
+ nxagentGCTrap = saveTrap;
+
+ if (pClipRegion != NullRegion)
+ {
+ nxagentFreeRegion(pDrawable, pClipRegion);
+ }
+
+ if (pGC != NULL)
+ {
+ FreeScratchGC(pGC);
+ }
+}
+
+void nxagentDestroyDrawableBitmap(DrawablePtr pDrawable)
+{
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyDrawableBitmap: Destroying bitmap for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ nxagentDestroyPixmap(nxagentDrawableBitmap(pDrawable));
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> synchronizationBitmap = NullPixmap;
+
+ if (nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1)
+ {
+ nxagentSynchronization.backgroundBitmaps--;
+ }
+ else
+ {
+ nxagentSynchronization.pixmapBitmaps--;
+ }
+ }
+ else
+ {
+ nxagentWindowPriv((WindowPtr) pDrawable) -> synchronizationBitmap = NullPixmap;
+
+ nxagentSynchronization.windowBitmaps--;
+ }
+ }
+}
+
+void nxagentIncreasePixmapUsageCounter(PixmapPtr pPixmap)
+{
+ if (nxagentDrawableStatus((DrawablePtr) pPixmap) == Synchronized)
+ {
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentIncreasePixmapUsageCounter: Pixmap usage counter was [%d].\n",
+ nxagentPixmapUsageCounter(pPixmap));
+ #endif
+
+ nxagentPixmapUsageCounter(pPixmap) += 1;
+
+ nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP);
+}
+
+void nxagentAllocateCorruptedResource(DrawablePtr pDrawable, RESTYPE type)
+{
+ PixmapPtr pRealPixmap;
+
+ if (nxagentSessionState == SESSION_DOWN)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentAllocateCorruptedResource: WARNING! Not allocated corrupted resource "
+ "[%s][%p] with the display down.\n", nxagentDrawableType(pDrawable),
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ if (type == RT_NX_CORR_WINDOW)
+ {
+ if (nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted "
+ "windows counter was [%d].\n", (void *) pDrawable, nxagentCorruptedWindows);
+ #endif
+
+ nxagentCorruptedWindows++;
+
+ nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId = FakeClientID(serverClient -> index);
+
+ AddResource(nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId, RT_NX_CORR_WINDOW,
+ (pointer) pDrawable);
+ }
+ }
+ else if (type == RT_NX_CORR_BACKGROUND)
+ {
+ pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable);
+
+ if (nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId == 0)
+ {
+ /*
+ * When a pixmap is added to the background
+ * corrupted resources, it must be removed
+ * from the pixmap corrupted resources.
+ */
+
+ nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_PIXMAP);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted "
+ "backgrounds counter was [%d].\n", (void *) pDrawable, nxagentCorruptedBackgrounds);
+ #endif
+
+ nxagentCorruptedBackgrounds++;
+
+ nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId = FakeClientID(serverClient -> index);
+
+ AddResource(nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId, RT_NX_CORR_BACKGROUND,
+ (pointer) pRealPixmap);
+ }
+ }
+ else if (type == RT_NX_CORR_PIXMAP)
+ {
+ /*
+ * The shared memory pixmaps are always dirty
+ * and shouldn't be synchronized.
+ */
+
+ if (nxagentPixmapUsageCounter((PixmapPtr) pDrawable) >= MINIMUM_PIXMAP_USAGE_COUNTER &&
+ nxagentIsShmPixmap((PixmapPtr) pDrawable) == 0)
+ {
+ pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable);
+
+ if (nxagentPixmapPriv(pRealPixmap) -> corruptedId == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted "
+ "pixmaps counter was [%d].\n", (void *) pDrawable, nxagentCorruptedPixmaps);
+ #endif
+
+ nxagentCorruptedPixmaps++;
+
+ nxagentPixmapPriv(pRealPixmap) -> corruptedId = FakeClientID(serverClient -> index);
+
+ AddResource(nxagentPixmapPriv(pRealPixmap) -> corruptedId, RT_NX_CORR_PIXMAP,
+ (pointer) pRealPixmap);
+ }
+ }
+ }
+}
+
+void nxagentDestroyCorruptedResource(DrawablePtr pDrawable, RESTYPE type)
+{
+ PixmapPtr pRealPixmap;
+
+ if (type == RT_NX_CORR_WINDOW)
+ {
+ if (nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted "
+ "windows counter was [%d].\n", (void *) pDrawable, nxagentCorruptedWindows);
+ #endif
+
+ if (nxagentCorruptedWindows > 0)
+ {
+ nxagentCorruptedWindows--;
+ }
+
+ FreeResource(nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId, RT_NONE);
+
+ if (nxagentSynchronization.pDrawable == pDrawable)
+ {
+ nxagentSynchronization.pDrawable = NULL;
+ }
+ }
+ }
+ else if (type == RT_NX_CORR_BACKGROUND)
+ {
+ pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable);
+
+ if (nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted "
+ "backgrounds counter was [%d].\n", (void *) pDrawable, nxagentCorruptedBackgrounds);
+ #endif
+
+ if (nxagentCorruptedBackgrounds > 0)
+ {
+ nxagentCorruptedBackgrounds--;
+ }
+
+ FreeResource(nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId, RT_NONE);
+
+ if (nxagentSynchronization.pDrawable == pDrawable)
+ {
+ nxagentSynchronization.pDrawable = NULL;
+ }
+ }
+ }
+ else if (type == RT_NX_CORR_PIXMAP)
+ {
+ pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable);
+
+ if (nxagentPixmapPriv(pRealPixmap) -> corruptedId != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted "
+ "pixmaps counter was [%d].\n", (void *) pDrawable, nxagentCorruptedPixmaps);
+ #endif
+
+ if (nxagentCorruptedPixmaps > 0)
+ {
+ nxagentCorruptedPixmaps--;
+ }
+
+ FreeResource(nxagentPixmapPriv(pRealPixmap) -> corruptedId, RT_NONE);
+
+ if (nxagentSynchronization.pDrawable == pDrawable)
+ {
+ nxagentSynchronization.pDrawable = NULL;
+ }
+ }
+ }
+}
+
+void nxagentCleanCorruptedDrawable(DrawablePtr pDrawable)
+{
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCleanCorruptedDrawable: Clearing out the corrupted drawable [%s][%p].\n",
+ nxagentDrawableType(pDrawable), (void *) pDrawable);
+ #endif
+
+ nxagentUnmarkCorruptedRegion(pDrawable, NullRegion);
+
+ if (nxagentDrawableBitmap(pDrawable) != NullPixmap)
+ {
+ nxagentDestroyDrawableBitmap(pDrawable);
+ }
+}
+
+void nxagentUnmarkExposedRegion(WindowPtr pWin, RegionPtr pRegion, RegionPtr pOther)
+{
+ RegionRec clipRegion;
+
+ if (pRegion != NullRegion && REGION_NIL(pRegion) == 0 &&
+ nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized)
+ {
+ REGION_INIT(pWin -> drawable.pScreen, &clipRegion, NullBox, 1);
+
+ REGION_COPY(pWin -> drawable.pScreen, &clipRegion, pRegion);
+
+ if (pOther != NullRegion && REGION_NIL(pOther) == 0)
+ {
+ REGION_UNION(pWin -> drawable.pScreen, &clipRegion, &clipRegion, pOther);
+ }
+
+ REGION_TRANSLATE(pWin -> drawable.pScreen, &clipRegion, -pWin -> drawable.x, -pWin -> drawable.y);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentUnmarkExposedRegion: Validating expose region [%d,%d,%d,%d] "
+ "on window [%p].\n", clipRegion.extents.x1, clipRegion.extents.y1,
+ clipRegion.extents.x2, clipRegion.extents.y2, (void *) pWin);
+ #endif
+
+ nxagentUnmarkCorruptedRegion((DrawablePtr) pWin, &clipRegion);
+
+ REGION_UNINIT(pWin -> drawable.pScreen, &clipRegion);
+ }
+}
+
+int nxagentSynchronizationPredicate()
+{
+ if (nxagentCorruptedWindows == 0 &&
+ nxagentCorruptedBackgrounds == 0 &&
+ nxagentCorruptedPixmaps == 0)
+ {
+ return NotNeeded;
+ }
+
+ if (nxagentBlocking == 0 &&
+ nxagentCongestion <= 4 &&
+ nxagentReady == 0 &&
+ nxagentUserInput(NULL) == 0)
+ {
+ return Needed;
+ }
+
+ /*
+ * If there are resources to synchronize
+ * but the conditions to start the loop
+ * are not satisfied, a little delay is
+ * requested to check for a new loop as
+ * soon as possible.
+ */
+
+ return Delayed;
+}
+
+void nxagentSendBackgroundExpose(WindowPtr pWin, PixmapPtr pBackground, RegionPtr pExpose)
+{
+ RegionRec expose;
+ miBSWindowPtr pBackingStore;
+
+ REGION_INIT(pWin -> pScreen, &expose, NullBox, 1);
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentSendBackgroundExpose: Original expose region is [%d,%d,%d,%d].\n",
+ pExpose -> extents.x1, pExpose -> extents.y1,
+ pExpose -> extents.x2, pExpose -> extents.y2);
+
+ fprintf(stderr, "nxagentSendBackgroundExpose: Window clipList is [%d,%d,%d,%d].\n",
+ pWin -> clipList.extents.x1, pWin -> clipList.extents.y1,
+ pWin -> clipList.extents.x2, pWin -> clipList.extents.y2);
+ #endif
+
+ if (nxagentDrawableStatus((DrawablePtr) pBackground) == Synchronized &&
+ (pBackground -> drawable.width < pWin -> drawable.width ||
+ pBackground -> drawable.height < pWin -> drawable.height))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSendBackgroundExpose: Pixmap background [%dx%d] is "
+ "smaller than window [%dx%d]. Going to expose the winSize.\n",
+ pBackground -> drawable.width, pBackground -> drawable.height,
+ pWin -> drawable.width, pWin -> drawable.height);
+ #endif
+
+ REGION_COPY(pWin -> pScreen, &expose, &pWin -> winSize);
+ }
+ else
+ {
+ REGION_COPY(pWin -> pScreen, &expose, pExpose);
+
+ REGION_TRANSLATE(pWin -> pScreen, &expose, pWin -> drawable.x, pWin -> drawable.y);
+ }
+
+ REGION_SUBTRACT(pWin -> pScreen, &expose, &expose, nxagentCorruptedRegion((DrawablePtr) pWin));
+
+ if (REGION_NIL(&pWin -> clipList) != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSendBackgroundExpose: Exposures deferred because the window "
+ "is hidden.\n");
+ #endif
+
+ REGION_UNION(pWin -> pScreen, nxagentDeferredBackgroundExposures,
+ nxagentDeferredBackgroundExposures, &expose);
+
+ nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 1;
+
+ goto nxagentSendBackgroundExposeEnd;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSendBackgroundExpose: Sending expose [%d,%d,%d,%d].\n",
+ expose.extents.x1, expose.extents.y1, expose.extents.x2, expose.extents.y2);
+ #endif
+
+ /*
+ * This prevents hidden region to be exposed.
+ */
+
+ pBackingStore = (miBSWindowPtr)pWin->backStorage;
+
+ if ((pBackingStore != NULL) && (REGION_NIL(&pBackingStore->SavedRegion) == 0))
+ {
+ REGION_TRANSLATE(pWin -> pScreen, &expose, -pWin -> drawable.x, -pWin -> drawable.y);
+
+ REGION_SUBTRACT(pWin -> pScreen, &expose, &expose, &pBackingStore -> SavedRegion);
+
+ REGION_TRANSLATE(pWin -> pScreen, &expose, pWin -> drawable.x, pWin -> drawable.y);
+ }
+
+ REGION_INTERSECT(pWin -> pScreen, &expose, &expose, &pWin -> clipList);
+
+ /*
+ * Reduce the overall region to expose.
+ */
+
+ REGION_TRANSLATE(pWin -> pScreen, &expose, -pWin -> drawable.x, -pWin -> drawable.y);
+
+ REGION_SUBTRACT(pWin -> pScreen, pExpose, pExpose, &expose);
+
+ REGION_TRANSLATE(pWin -> pScreen, &expose, pWin -> drawable.x, pWin -> drawable.y);
+
+ miWindowExposures(pWin, &expose, &expose);
+
+nxagentSendBackgroundExposeEnd:
+
+ REGION_UNINIT(pWin -> pScreen, &expose);
+}
+
+void nxagentExposeBackgroundPredicate(void *p0, XID x1, void *p2)
+{
+ WindowPtr pWin = (WindowPtr) p0;
+ WindowPtr pParent;
+
+ struct nxagentExposeBackground *pPair = p2;
+
+ if (REGION_NIL(pPair -> pExpose) != 0)
+ {
+ return;
+ }
+
+ if (pWin -> backgroundState == BackgroundPixmap &&
+ pWin -> background.pixmap == pPair -> pBackground)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentExposeBackgroundPredicate: Window at [%p] uses pixmap [%p] "
+ "as background.\n", (void *) pWin, (void *) pPair -> pBackground);
+ #endif
+
+ nxagentSendBackgroundExpose(pWin, pPair -> pBackground, pPair -> pExpose);
+ }
+ else if (pWin -> backgroundState == ParentRelative)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentExposeBackgroundPredicate: Window [%p] uses parent's background.\n",
+ (void *) pWin);
+ #endif
+
+ pParent = pWin -> parent;
+
+ while (pParent != NULL)
+ {
+ if (pParent -> backgroundState == BackgroundPixmap &&
+ pParent -> background.pixmap == pPair -> pBackground)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentExposeBackgroundPredicate: Parent window at [%p] uses pixmap [%p] "
+ "as background.\n", (void *) pParent, (void *) pPair -> pBackground);
+ #endif
+
+ nxagentSendBackgroundExpose(pWin, pPair -> pBackground, pPair -> pExpose);
+
+ break;
+ }
+
+ pParent = pParent -> parent;
+ }
+ }
+}
+
+/*
+ * This function is similar to nxagentClipAndSendExpose().
+ */
+
+int nxagentClipAndSendClearExpose(WindowPtr pWin, pointer ptr)
+{
+ RegionPtr exposeRgn;
+ RegionPtr remoteExposeRgn;
+
+ #ifdef DEBUG
+ BoxRec box;
+ #endif
+
+ remoteExposeRgn = (RegionRec *) ptr;
+
+ if (nxagentWindowPriv(pWin) -> deferredBackgroundExpose == 1)
+ {
+ exposeRgn = REGION_CREATE(pWin -> drawable.pScreen, NULL, 1);
+
+ #ifdef DEBUG
+ box = *REGION_EXTENTS(pWin->drawable.pScreen, remoteExposeRgn);
+
+ fprintf(stderr, "nxagentClipAndSendClearExpose: Background expose extents: [%d,%d,%d,%d].\n",
+ box.x1, box.y1, box.x2, box.y2);
+
+ box = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin -> clipList);
+
+ fprintf(stderr, "nxagentClipAndSendClearExpose: Clip list extents for window at [%p]: [%d,%d,%d,%d].\n",
+ (void *) pWin, box.x1, box.y1, box.x2, box.y2);
+ #endif
+
+ REGION_INTERSECT(pWin -> drawable.pScreen, exposeRgn, remoteExposeRgn, &pWin -> clipList);
+
+ /*
+ * If the region will be synchronized,
+ * the expose on corrupted regions can
+ * be ignored.
+ */
+
+ REGION_SUBTRACT(pWin -> drawable.pScreen, exposeRgn, exposeRgn, nxagentCorruptedRegion((DrawablePtr) pWin));
+
+ if (REGION_NOTEMPTY(pWin -> drawable.pScreen, exposeRgn))
+ {
+ #ifdef DEBUG
+ box = *REGION_EXTENTS(pWin->drawable.pScreen, exposeRgn);
+
+ fprintf(stderr, "nxagentClipAndSendClearExpose: Forwarding expose [%d,%d,%d,%d] to window at [%p] pWin.\n",
+ box.x1, box.y1, box.x2, box.y2, (void *) pWin);
+ #endif
+
+ REGION_SUBTRACT(pWin -> drawable.pScreen, remoteExposeRgn, remoteExposeRgn, exposeRgn);
+
+ miWindowExposures(pWin, exposeRgn, exposeRgn);
+ }
+
+ REGION_DESTROY(pWin -> drawable.pScreen, exposeRgn);
+
+ nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 0;
+ }
+
+ if (REGION_NOTEMPTY(pWin -> drawable.pScreen, remoteExposeRgn))
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendClearExpose: Region not empty. Walk children.\n");
+ #endif
+
+
+ return WT_WALKCHILDREN;
+ }
+ else
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendClearExpose: Region empty. Stop walking.\n");
+ #endif
+
+ return WT_STOPWALKING;
+ }
+}
+
+void nxagentSendDeferredBackgroundExposures(void)
+{
+ if (nxagentDeferredBackgroundExposures == NullRegion)
+ {
+ nxagentDeferredBackgroundExposures = REGION_CREATE(WindowTable[0] -> drawable.pScreen, NullBox, 1);
+ }
+
+ if (REGION_NOTEMPTY(WindowTable[0] -> drawable.pScreen, nxagentDeferredBackgroundExposures) != 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSendDeferredBackgroundExposures: Going to send deferred exposures to the root window.\n");
+ #endif
+
+ TraverseTree(WindowTable[0], nxagentClipAndSendClearExpose, (void *) nxagentDeferredBackgroundExposures);
+
+ REGION_EMPTY(WindowTable[0] -> drawable.pScreen, nxagentDeferredBackgroundExposures);
+ }
+}
+