aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/nxagent/Split.c
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2011-10-10 18:02:52 +0200
committerReinhard Tartler <siretart@tauware.de>2011-10-10 18:02:52 +0200
commit5b4ca0f93c44d7bbc8d6a3eebdd5c458e3a84c14 (patch)
treeb6f59ec830436134aaccf47aa71a070aa2ad2992 /nx-X11/programs/Xserver/hw/nxagent/Split.c
parente29a112097fa74b520ba619eb07e2e0e0a7f2f3e (diff)
parente01b9177b41f7d27a934d41fa38d550fa0026b45 (diff)
downloadnx-libs-5b4ca0f93c44d7bbc8d6a3eebdd5c458e3a84c14.tar.gz
nx-libs-5b4ca0f93c44d7bbc8d6a3eebdd5c458e3a84c14.tar.bz2
nx-libs-5b4ca0f93c44d7bbc8d6a3eebdd5c458e3a84c14.zip
Merge branch 'nxagent'
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/Split.c')
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Split.c1248
1 files changed, 1248 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Split.c b/nx-X11/programs/Xserver/hw/nxagent/Split.c
new file mode 100644
index 000000000..4cc2ea607
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/nxagent/Split.c
@@ -0,0 +1,1248 @@
+/**************************************************************************/
+/* */
+/* 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 "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "gcstruct.h"
+
+#include "Agent.h"
+#include "Display.h"
+#include "Drawable.h"
+#include "Events.h"
+#include "GCs.h"
+
+#include "NXlib.h"
+
+
+/*
+ * Set here the required log level.
+ */
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+/*
+ * This should be a macro but for now
+ * we make it a real function to log
+ * a warning in the logs.
+ */
+
+DrawablePtr nxagentSplitDrawable(DrawablePtr pDrawable)
+{
+ if (pDrawable -> type == DRAWABLE_PIXMAP &&
+ nxagentPixmapIsVirtual((PixmapPtr) pDrawable))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSplitDrawable: WARNING! The drawable at [%p] is "
+ "virtual. Assuming real at [%p].\n", (void *) pDrawable,
+ (void *) nxagentRealPixmap((PixmapPtr) pDrawable));
+ #endif
+
+ return (DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable);
+ }
+ else
+ {
+ return pDrawable;
+ }
+}
+
+void nxagentInitSplitResources()
+{
+ int resource;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentInitSplitResources: Initializing the split resources.\n");
+ #endif
+
+ for (resource = 0; resource < NXNumberOfResources; resource++)
+ {
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ pResource -> pending = 0;
+ pResource -> commit = 0;
+ pResource -> split = NXNoResource;
+ pResource -> unpack = NXNoResource;
+ pResource -> drawable = NULL;
+ pResource -> region = NullRegion;
+ pResource -> gc = NULL;
+ }
+}
+
+SplitResourcePtr nxagentAllocSplitResource()
+{
+ int resource;
+
+ SplitResourcePtr pResource;
+
+ for (;;)
+ {
+ resource = NXAllocSplit(nxagentDisplay, NXAnyResource);
+
+ if (resource != NXNoResource)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentAllocSplitResource: Reserving resource [%d] for the next split.\n",
+ resource);
+ #endif
+
+ break;
+ }
+ else
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentAllocSplitResource: PANIC! No more resources for the next split.\n");
+ #endif
+/*
+FIXME: Must deal with the case all resources are exausted.
+*/
+ FatalError("nxagentAllocSplitResource: PANIC! No more resources for the next split.\n");
+ }
+ }
+
+ pResource = &nxagentSplitResources[resource];
+
+ if (pResource -> pending != 0 || pResource -> split != NXNoResource ||
+ pResource -> unpack != NXNoResource || pResource -> drawable != NULL ||
+ pResource -> region != NullRegion || pResource -> commit != 0 ||
+ pResource -> gc != NULL)
+ {
+ /*
+ * This is really an unrecoverable error.
+ */
+
+ #ifdef PANIC
+ fprintf(stderr, "nxagentAllocSplitResource: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ #endif
+
+ FatalError("nxagentAllocSplitResource: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ }
+
+ pResource -> pending = 1;
+ pResource -> split = resource;
+
+ return pResource;
+}
+
+void nxagentFreeSplitResource(SplitResourcePtr pResource)
+{
+ if (pResource -> pending == 0 || pResource -> split == NXNoResource ||
+ pResource -> drawable != NULL || pResource -> region != NullRegion ||
+ pResource -> gc != NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentFreeSplitResource: PANIC! Invalid record provided with values "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ #endif
+
+ FatalError("nxagentFreeSplitResource: PANIC! Invalid record provided with values "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentFreeSplitResource: Clearing the record for resource [%d].\n",
+ pResource -> split);
+ #endif
+
+ NXFreeSplit(nxagentDisplay, pResource -> split);
+
+ pResource -> pending = 0;
+ pResource -> commit = 0;
+ pResource -> split = NXNoResource;
+ pResource -> unpack = NXNoResource;
+ pResource -> drawable = NULL;
+ pResource -> region = NullRegion;
+ pResource -> gc = NULL;
+}
+
+void nxagentInitUnpackResources()
+{
+/*
+FIXME: This must be implemented.
+*/
+}
+
+UnpackResourcePtr nxagentAllocUnpackResource()
+{
+/*
+FIXME: This must be implemented.
+*/
+ return NULL;
+}
+
+void nxagentFreeUnpackResource(UnpackResourcePtr pResource)
+{
+/*
+FIXME: This must be implemented.
+*/
+}
+
+void nxagentReleaseAllSplits(void)
+{
+ int resource;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseAllSplits: Going to release all the split resources.\n");
+ #endif
+
+ for (resource = 0; resource < NXNumberOfResources; resource++)
+ {
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ if (pResource != NULL && pResource -> pending == 1)
+ {
+ DrawablePtr pDrawable = pResource -> drawable;
+
+ if (pDrawable != NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseAllSplits: Releasing the drawable at [%p] for "
+ "resource [%d].\n", (void *) pDrawable, pResource -> split);
+ #endif
+
+ nxagentReleaseSplit(pDrawable);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseAllSplits: Freeing the resource [%d].\n",
+ resource);
+ #endif
+
+ nxagentFreeSplitResource(pResource);
+ }
+ }
+}
+
+/*
+ * Check the coherency of the split record.
+ */
+
+#ifdef TEST
+
+static void nxagentCheckSplit(DrawablePtr pDrawable, SplitResourcePtr pResource)
+{
+ if (pResource == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCheckSplit: PANIC! No record associated to drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ FatalError("nxagentCheckSplit: PANIC! No record associated to drawable at [%p].\n",
+ (void *) pDrawable);
+ }
+ else if (pResource -> drawable != pDrawable ||
+ pResource -> split == NXNoResource)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCheckSplit: PANIC! The record [%d] doesn't match the drawable at [%p].\n",
+ pResource -> split, (void *) pDrawable);
+ #endif
+
+ FatalError("nxagentCheckSplit: PANIC! The record [%d] doesn't match the drawable at [%p].\n",
+ pResource -> split, (void *) pDrawable);
+ }
+ else if (pResource -> commit == 1 &&
+ pResource -> gc == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCheckSplit: PANIC! The record [%d] doesn't have a valid GC.\n",
+ pResource -> split);
+ #endif
+
+ FatalError("nxagentCheckSplit: PANIC! The record [%d] doesn't have a valid GC.\n",
+ pResource -> split);
+ }
+}
+
+static void nxagentCheckResource(SplitResourcePtr pResource, int resource)
+{
+ if (pResource == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCheckResource: PANIC! No record associated to resource [%d].\n",
+ resource);
+ #endif
+
+ FatalError("nxagentCheckResource: PANIC! No record associated to resource [%d].\n",
+ resource);
+ }
+ else if ((pResource -> split != resource || pResource -> pending != 1) ||
+ (pResource -> commit == 1 && (pResource -> drawable == NULL ||
+ pResource -> gc == NULL)))
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCheckResource: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ #endif
+
+ FatalError("nxagentCheckResource: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ }
+}
+
+#endif
+
+int nxagentCreateSplit(DrawablePtr pDrawable, GCPtr *pGC)
+{
+ SplitResourcePtr pResource;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ pResource = nxagentAllocSplitResource();
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ nxagentPixmapPriv((PixmapPtr) pDrawable) -> splitResource = pResource;
+ }
+ else
+ {
+ nxagentWindowPriv((WindowPtr) pDrawable) -> splitResource = pResource;
+ }
+
+ pResource -> drawable = pDrawable;
+ pResource -> commit = 1;
+
+ /*
+ * Make a copy of the GC so the client
+ * can safely remove it.
+ */
+
+ pResource -> gc = CreateScratchGC(pDrawable -> pScreen, pDrawable -> depth);
+
+/*
+FIXME: What do we do here?
+*/
+ if (pResource -> gc == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCreateSplit: PANIC! Failed to create split GC for resource [%d].\n",
+ pResource -> split);
+ #endif
+
+ FatalError("nxagentCreateSplit: PANIC! Failed to create split GC for resource [%d].\n",
+ pResource -> split);
+ }
+ else if (CopyGC(*pGC, pResource -> gc, GCFunction | GCPlaneMask |
+ GCSubwindowMode | GCClipXOrigin | GCClipYOrigin |
+ GCClipMask | GCForeground | GCBackground) != Success)
+ {
+/*
+FIXME: What do we do here?
+*/
+ #ifdef PANIC
+ fprintf(stderr, "nxagentCreateSplit: PANIC! Failed to copy split GC for resource [%d].\n",
+ pResource -> split);
+ #endif
+
+ FatalError("nxagentCreateSplit: PANIC! Failed to copy split GC for resource [%d].\n",
+ pResource -> split);
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateSplit: Associated GC at [%p] to resource [%d] "
+ "with id [%lu].\n", (void *) pResource -> gc, pResource -> split,
+ (unsigned long) nxagentGC(pResource -> gc));
+ #endif
+
+ *pGC = pResource -> gc;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentCreateSplit: Associated resource [%d] to drawable at [%p].\n",
+ pResource -> split, (void *) pResource -> drawable);
+ #endif
+
+ return pResource -> split;
+}
+
+/*
+ * Set the region to be the current
+ * streaming region.
+ */
+
+void nxagentRegionSplit(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ SplitResourcePtr pResource;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ pResource = nxagentSplitResource(pDrawable);
+
+ #ifdef TEST
+
+ fprintf(stderr, "nxagentRegionSplit: Associating region to resource [%d] drawable at [%p].\n",
+ pResource -> split, (void *) pDrawable);
+
+ nxagentCheckSplit(pDrawable, pResource);
+
+ #endif
+
+ if (pResource == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentRegionSplit: PANIC! No valid split record for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentRegionSplit: Associated region [%d,%d,%d,%d] to drawable at [%p] "
+ "with resource [%d].\n", pRegion -> extents.x1, pRegion -> extents.y1,
+ pRegion -> extents.x2, pRegion -> extents.y2, (void *) pDrawable,
+ pResource -> split);
+ #endif
+
+ pResource -> region = pRegion;
+}
+
+/*
+ * Remove the association between the drawable
+ * and the split resource. The resource is not
+ * deallocated until the end of the split.
+ */
+
+void nxagentReleaseSplit(DrawablePtr pDrawable)
+{
+ SplitResourcePtr pResource;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ pResource = nxagentSplitResource(pDrawable);
+
+ if (pResource == NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseSplit: No split resources for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+
+ fprintf(stderr, "nxagentReleaseSplit: Going to release resource [%d] for drawable at [%p].\n",
+ pResource -> split, (void *) pDrawable);
+
+ nxagentCheckSplit(pDrawable, pResource);
+
+ #endif
+
+ if (pResource -> region != NullRegion)
+ {
+ /*
+ * If we have a region the commits
+ * had to be still valid. In this
+ * case tell the proxy to abort the
+ * data transfer.
+ */
+
+ #ifdef TEST
+
+ if (pResource -> commit == 0)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentReleaseSplit: PANIC! Found a region for resource [%d] but the "
+ "commits are invalid.\n", pResource -> split);
+ #endif
+
+ FatalError("nxagentCheckSplit: PANIC! Found a region for resource [%d] but the "
+ "commits are invalid.\n", pResource -> split);
+ }
+
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: Aborting the data transfer for resource [%d].\n",
+ pResource -> split);
+ #endif
+
+ NXAbortSplit(nxagentDisplay, pResource -> split);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseSplit: Freeing the region for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ REGION_DESTROY(pDrawable -> pScreen, pResource -> region);
+
+ pResource -> region = NullRegion;
+ }
+
+ if (pResource -> gc != NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseSplit: Freeing the split GC for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ FreeScratchGC(pResource -> gc);
+
+ pResource -> gc = NULL;
+ }
+
+ /*
+ * Remove the association between the
+ * drawable and the resource record.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentReleaseSplit: Removing association to drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ nxagentPixmapPriv((PixmapPtr) pDrawable) -> splitResource = NULL;
+ }
+ else
+ {
+ nxagentWindowPriv((WindowPtr) pDrawable) -> splitResource = NULL;
+ }
+
+ /*
+ * Invalidate the commits and remove the
+ * association between the resource and
+ * the drawable.
+ */
+
+ pResource -> drawable = NULL;
+ pResource -> commit = 0;
+}
+
+void nxagentValidateSplit(DrawablePtr pDrawable, RegionPtr pRegion)
+{
+ SplitResourcePtr pResource;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ pResource = nxagentSplitResource(pDrawable);
+
+ if (pResource == NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: No split resource for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+ else if (pResource -> region == NullRegion)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: No split region yet for drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+ else if (pResource -> commit == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: WARNING! Split for drawable at [%p] was "
+ "already invalidated.\n", (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+
+ fprintf(stderr, "nxagentValidateSplit: Going to validate resource [%d] drawable at [%p].\n",
+ pResource -> split, (void *) pDrawable);
+
+ nxagentCheckSplit(pDrawable, pResource);
+
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: Checking the region for resource [%d] "
+ "and drawable at [%p].\n", pResource -> split, (void *) pDrawable);
+ #endif
+
+ /*
+ * If a null region is passed as parameter,
+ * we assume that all the commits have to
+ * be discarded.
+ */
+
+ if (pRegion == NullRegion)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: Forcing all commits as invalid for "
+ "drawable at [%p].\n", (void *) pDrawable);
+ #endif
+
+ nxagentReleaseSplit(pDrawable);
+ }
+ else
+ {
+ RegionRec tmpRegion;
+
+ /*
+ * Check if the provided region overlaps
+ * the area covered by the image being
+ * streamed.
+ */
+
+ REGION_INIT(pDrawable -> pScreen, &tmpRegion, NullBox, 1);
+
+ REGION_INTERSECT(pDrawable -> pScreen, &tmpRegion, pResource -> region, pRegion);
+
+ if (REGION_NIL(&tmpRegion) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentValidateSplit: Marking the overlapping commits as invalid "
+ "for drawable at [%p].\n", (void *) pDrawable);
+ #endif
+
+ nxagentReleaseSplit(pDrawable);
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentValidateSplit: Leaving the commits as valid for "
+ "drawable at [%p].\n", (void *) pDrawable);
+ }
+ #endif
+
+ REGION_UNINIT(pDrawable -> pScreen, &tmpRegion);
+ }
+}
+
+void nxagentFreeSplit(int resource)
+{
+ DrawablePtr pDrawable;
+
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ if (pResource == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentFreeSplit: PANIC! No valid split record for resource [%d].\n",
+ resource);
+ #endif
+
+ FatalError("nxagentFreeSplit: PANIC! No valid split record for resource [%d].\n",
+ resource);
+ }
+ else if (pResource -> split != resource)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentFreeSplit: PANIC! The record [%d] doesn't match the resource [%d].\n",
+ pResource -> split, resource);
+ #endif
+
+ FatalError("nxagentFreeSplit: PANIC! The record [%d] doesn't match the resource [%d].\n",
+ pResource -> split, resource);
+ }
+
+ pDrawable = pResource -> drawable;
+
+ if (pDrawable != NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentFreeSplit: Removing association to drawable at [%p].\n",
+ (void *) pDrawable);
+ #endif
+
+ nxagentReleaseSplit(pDrawable);
+ }
+ #ifdef TEST
+ else
+ {
+ /*
+ * The end of the split has come after we have
+ * invalidated the operation and removed the
+ * association to the drawable. This happens,
+ * for example, if the drawable is destroyed.
+ */
+
+ fprintf(stderr, "nxagentFreeSplit: WARNING! Releasing invalidated resource [%d].\n",
+ pResource -> split);
+ }
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentFreeSplit: Freeing the record for resource [%d].\n",
+ pResource -> split);
+ #endif
+
+ nxagentFreeSplitResource(pResource);
+}
+
+/*
+FIXME: This must be enabled when the vanilla
+ synchronization procedure is working.
+*/
+#define USE_FINISH_SPLIT
+
+void nxagentWaitDrawable(DrawablePtr pDrawable)
+{
+ SplitResourcePtr pResource;
+
+ pDrawable = nxagentSplitDrawable(pDrawable);
+
+ pResource = nxagentSplitResource(pDrawable);
+
+ if (pResource == NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "++++++nxagentWaitDrawable: WARNING! The drawable at [%p] is already awake.\n",
+ (void *) pDrawable);
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "++++++nxagentWaitDrawable: Waiting drawable at [%p] with resource [%d].\n",
+ (void *) pDrawable, pResource -> split);
+ #endif
+
+ /*
+ * Be sure we intercept an I/O error
+ * as well as an interrupt.
+ */
+
+ #ifdef USE_FINISH_SPLIT
+
+ NXFinishSplit(nxagentDisplay, pResource -> split);
+
+ #endif
+
+ NXFlushDisplay(nxagentDisplay, NXFlushBuffer);
+
+ for (;;)
+ {
+ /*
+ * Handling all the possible events here
+ * preempts the queue and makes a better
+ * use of the link.
+ *
+ * We should better use XIfEvent() instead
+ * of looping again and again through the
+ * event queue.
+ */
+
+ nxagentDispatchEvents(NULL);
+
+ /*
+ * Wait indefinitely until the resource
+ * is released or the display is shut
+ * down.
+ */
+
+ if (nxagentSplitResource(pDrawable) == NULL ||
+ NXDisplayError(nxagentDisplay) == 1)
+ {
+ #ifdef TEST
+
+ if (NXDisplayError(nxagentDisplay) == 1)
+ {
+ fprintf(stderr, "++++++nxagentWaitDrawable: WARNING! Display error detected while "
+ "waiting for the drawable.\n");
+ }
+ else
+ {
+ fprintf(stderr, "++++++nxagentWaitDrawable: Drawable at [%p] can now be restarted.\n",
+ (void *) pDrawable);
+ }
+
+ #endif
+
+ return;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "++++++nxagentWaitDrawable: Yielding control to the NX transport.\n");
+ #endif
+
+ nxagentWaitEvents(nxagentDisplay, NULL);
+ }
+}
+
+static Bool nxagentCommitSplitPredicate(Display *display, XEvent *event, XPointer ptr)
+{
+ return (event -> type == ClientMessage &&
+ event -> xclient.data.l[0] == NXCommitSplitNotify &&
+ event -> xclient.window == 0 && event -> xclient.message_type == 0 &&
+ event -> xclient.format == 32);
+}
+
+void nxagentWaitCommitEvent(int resource)
+{
+ XEvent event;
+
+ /*
+ * Check if there is any commit pending. As
+ * we are at it, handle any commit, even those
+ * commits pertaining to other resources.
+ *
+ * We can receive some commits even if we'll
+ * later receive a no-split event. The proxy,
+ * in fact, may have missed to find the image
+ * in the memory cache and could have loaded it
+ * from disk (so requiring a commit) before we
+ * marked the end of the split sequence.
+ */
+
+ while (nxagentCheckEvents(nxagentDisplay, &event,
+ nxagentCommitSplitPredicate, NULL) == 1)
+ {
+ int client = event.xclient.data.l[1];
+ int request = event.xclient.data.l[2];
+ int position = event.xclient.data.l[3];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentWaitCommitEvent: Commit event received with "
+ "client [%d] request [%d] and position [%d].\n",
+ client, request, position);
+ #endif
+
+ nxagentHandleCommitSplitEvent(client, request, position);
+ }
+}
+
+static Bool nxagentWaitSplitPredicate(Display *display, XEvent *event, XPointer ptr)
+{
+ return (event -> type == ClientMessage &&
+ (event -> xclient.data.l[0] == NXNoSplitNotify ||
+ event -> xclient.data.l[0] == NXStartSplitNotify) &&
+ event -> xclient.window == 0 && event -> xclient.message_type == 0 &&
+ event -> xclient.format == 32);
+}
+
+int nxagentWaitSplitEvent(int resource)
+{
+ XEvent event;
+
+ int split = 0;
+
+ /*
+ * Don't flush the link. We only want to
+ * query the NX transport to check whether
+ * the operation caused a split.
+ */
+
+ NXFlushDisplay(nxagentDisplay, NXFlushBuffer);
+
+ for (;;)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentWaitSplitEvent: Waiting for the split event for resource [%d].\n",
+ resource);
+ #endif
+
+ XIfEvent(nxagentDisplay, &event, nxagentWaitSplitPredicate, NULL);
+
+ if (NXDisplayError(nxagentDisplay) == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentWaitSplitEvent: WARNING! Error detected reading the event.\n");
+ #endif
+
+ nxagentHandleNoSplitEvent(resource);
+
+ break;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentWaitSplitEvent: Going to process the split event.\n");
+ #endif
+
+ if (resource != (int) event.xclient.data.l[1])
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentWaitSplitEvent: PANIC! Got event for resource [%d] while "
+ "waiting for resource [%d].\n", (int) event.xclient.data.l[1], resource);
+
+ fprintf(stderr, "nxagentWaitSplitEvent: PANIC! Restarting resource [%d] due to the "
+ "missing split event.\n", resource);
+ #endif
+
+ nxagentHandleNoSplitEvent(resource);
+
+ break;
+ }
+ else if (event.xclient.data.l[0] == NXNoSplitNotify)
+ {
+ nxagentHandleNoSplitEvent(resource);
+
+ break;
+ }
+ else
+ {
+ nxagentHandleStartSplitEvent(resource);
+
+ split = 1;
+
+ break;
+ }
+ }
+
+ return split;
+}
+
+void nxagentHandleNoSplitEvent(int resource)
+{
+ if (resource >= 0 && resource < NXNumberOfResources)
+ {
+ #ifdef TEST
+
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ fprintf(stderr, "nxagentHandleNoSplitEvent: Received event for resource [%d].\n",
+ resource);
+
+ nxagentCheckResource(pResource, resource);
+
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleNoSplitEvent: Checking if there is any commit pending.\n");
+ #endif
+
+ nxagentWaitCommitEvent(resource);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleNoSplitEvent: No streaming was required with resource [%d] "
+ "and drawable at [%p].\n", resource, (void *) pResource -> drawable);
+ #endif
+
+ /*
+ * Release the resource.
+ */
+
+ nxagentFreeSplit(resource);
+ }
+ #ifdef PANIC
+ else
+ {
+ fprintf(stderr, "nxagentHandleNoSplitEvent: PANIC! Invalid resource identifier [%d] "
+ " received in event.\n", resource);
+ }
+ #endif
+}
+
+void nxagentHandleStartSplitEvent(int resource)
+{
+ if (resource >= 0 && resource < NXNumberOfResources)
+ {
+ #ifdef TEST
+
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ fprintf(stderr, "nxagentHandleStartSplitEvent: Received event for resource [%d].\n",
+ resource);
+
+ nxagentCheckResource(pResource, resource);
+
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleStartSplitEvent: Checking if there is any commit pending.\n");
+ #endif
+
+ nxagentWaitCommitEvent(resource);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleStartSplitEvent: Streaming started with resource [%d] "
+ "and drawable at [%p].\n", resource, (void *) pResource -> drawable);
+ #endif
+ }
+ #ifdef PANIC
+ else
+ {
+ fprintf(stderr, "nxagentHandleStartSplitEvent: PANIC! Invalid resource identifier [%d] "
+ " received in event.\n", resource);
+ }
+ #endif
+}
+
+void nxagentHandleCommitSplitEvent(int resource, int request, int position)
+{
+ if (resource >= 0 && resource < NXNumberOfResources &&
+ request >= 0 && position >= 0)
+ {
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleCommitSplitEvent: Received event for resource [%d].\n",
+ resource);
+ #endif
+
+ if (pResource != NULL && pResource -> commit == 1)
+ {
+ #ifdef TEST
+
+ nxagentCheckResource(pResource, resource);
+
+ fprintf(stderr, "nxagentHandleCommitSplitEvent: Committing request [%d] with "
+ "position [%d] for resource [%d].\n", request, position, resource);
+
+ #endif
+
+ NXCommitSplit(nxagentDisplay, resource, 1, request, position);
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleCommitSplitEvent: Discarding request [%d] for "
+ "resource [%d] with position [%d].\n", request, resource, position);
+ #endif
+
+ NXCommitSplit(nxagentDisplay, resource, 0, request, position);
+ }
+ }
+ #ifdef PANIC
+ else
+ {
+ fprintf(stderr, "nxagentHandleCommitSplitEvent: PANIC! Invalid commit event with "
+ "request [%d] and position [%d] for resource [%d].\n", request,
+ position, resource);
+ }
+ #endif
+}
+
+void nxagentHandleEndSplitEvent(int resource)
+{
+ if (resource >= 0 && resource < NXNumberOfResources)
+ {
+ SplitResourcePtr pResource = &nxagentSplitResources[resource];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleEndSplitEvent: Received event for resource [%d].\n",
+ resource);
+
+ nxagentCheckResource(pResource, resource);
+
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleEndSplitEvent: Checking if there is any commit pending.\n");
+ #endif
+
+ nxagentWaitCommitEvent(resource);
+
+ if (pResource != NULL && pResource -> commit == 1)
+ {
+ #ifdef TEST
+
+ fprintf(stderr, "nxagentHandleEndSplitEvent: Checking the split region at [%p] "
+ "for drawable at [%p].\n", (void *) pResource -> drawable,
+ (void *) pResource -> region);
+
+ if (pResource -> region == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid region [%p] for drawable at [%p].\n",
+ (void *) pResource -> region, (void *) pResource -> drawable);
+ #endif
+
+ FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid region [%p] for drawable at [%p].\n",
+ (void *) pResource -> region, (void *) pResource -> drawable);
+ }
+ else if (pResource -> gc == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid GC [%p] for drawable at [%p].\n",
+ (void *) pResource -> gc, (void *) pResource -> drawable);
+ #endif
+
+ FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid GC [%p] for drawable at [%p].\n",
+ (void *) pResource -> gc, (void *) pResource -> drawable);
+ }
+
+ #endif
+
+ if (pResource -> drawable != NULL &&
+ pResource -> region != NullRegion)
+ {
+ if (REGION_NIL(pResource -> region) == 0)
+ {
+ REGION_SUBTRACT(pResource -> drawable -> pScreen,
+ nxagentCorruptedRegion(pResource -> drawable),
+ nxagentCorruptedRegion(pResource -> drawable),
+ pResource -> region);
+
+/*
+FIXME: Implementing the valid region policy
+
+ nxagentExpandValidRegion(pResource -> drawable, pResource -> region);
+*/
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleEndSplitEvent: Synchronized region [%d,%d,%d,%d] "
+ "for drawable at [%p].\n", pResource -> region -> extents.x1,
+ pResource -> region -> extents.y1, pResource -> region -> extents.x2,
+ pResource -> region -> extents.y2, (void *) pResource -> drawable);
+ #endif
+ }
+ else
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! The region [%d,%d,%d,%d] for drawable "
+ "at [%p] is empty.\n", pResource -> region -> extents.x1,
+ pResource -> region -> extents.y1, pResource -> region -> extents.x2,
+ pResource -> region -> extents.y2, (void *) pResource -> drawable);
+ #endif
+
+ FatalError("nxagentHandleEndSplitEvent: PANIC! The region [%d,%d,%d,%d] for drawable "
+ "at [%p] is empty.\n", pResource -> region -> extents.x1,
+ pResource -> region -> extents.y1, pResource -> region -> extents.x2,
+ pResource -> region -> extents.y2, (void *) pResource -> drawable);
+ }
+ }
+ else
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ #endif
+
+ FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid record for resource [%d] with "
+ "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n",
+ resource, pResource -> pending, pResource -> split, pResource -> unpack,
+ (void *) pResource -> drawable, (void *) pResource -> region,
+ pResource -> commit, (void *) pResource -> gc);
+ }
+ }
+
+ /*
+ * Release the resource.
+ */
+
+ nxagentFreeSplit(resource);
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentHandleEndSplitEvent: WARNING! Ignoring split event "
+ "for resource [%d].\n", resource);
+ }
+ #endif
+}
+
+void nxagentHandleEmptySplitEvent()
+{
+/*
+FIXME: Should run a consistency check here.
+*/
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleEmptySplitEvent: No more split event to handle.\n");
+ #endif
+}
+
+/*
+ * The drawable is going to become corrupted.
+ */
+
+void nxagentSetCorruptedTimestamp(DrawablePtr pDrawable)
+{
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSetCorruptedTimestamp: Corruption timestamp for pixmap at [%p] was [%lu].\n",
+ (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+
+ nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp = GetTimeInMillis();
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSetCorruptedTimestamp: New corruption timestamp for pixmap at [%p] is [%lu].\n",
+ (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSetCorruptedTimestamp: Corruption timestamp for window at [%p] was [%lu].\n",
+ (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+
+ nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp = GetTimeInMillis();
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentSetCorruptedTimestamp: New corruption timestamp for window at [%p] is [%lu].\n",
+ (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+ }
+ }
+}
+
+/*
+ * Reset the timestamp taken when the drawable
+ * became initially corrupted. The timestamp is
+ * reset only after the drawable has been fully
+ * synchronized.
+ */
+
+void nxagentResetCorruptedTimestamp(DrawablePtr pDrawable)
+{
+ if (nxagentDrawableStatus(pDrawable) == Synchronized)
+ {
+ if (pDrawable -> type == DRAWABLE_PIXMAP)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentResetCorruptedTimestamp: Corruption timestamp for pixmap at [%p] was [%lu].\n",
+ (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+
+ nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp = 0;
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentResetCorruptedTimestamp: Corruption timestamp for window at [%p] was [%lu].\n",
+ (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp);
+ #endif
+
+ nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp = 0;
+ }
+ }
+}
+