1224 lines
36 KiB
C
1224 lines
36 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
|
|
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
|
|
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
|
|
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
|
|
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
|
|
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
|
|
/* */
|
|
/* NXAGENT, NX protocol compression and NX extensions to this software */
|
|
/* are copyright of the aforementioned persons and companies. */
|
|
/* */
|
|
/* Redistribution and use of the present software is allowed according */
|
|
/* to terms specified in the file LICENSE which comes in the source */
|
|
/* distribution. */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* NOTE: This software has received contributions from various other */
|
|
/* contributors, only the core maintainers and supporters are listed as */
|
|
/* copyright holders. Please contact us, if you feel you should be listed */
|
|
/* as copyright holder, as well. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#include "scrnintstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "windowstr.h"
|
|
#include "gcstruct.h"
|
|
|
|
#include "Agent.h"
|
|
#include "Display.h"
|
|
#include "Drawable.h"
|
|
#include "Events.h"
|
|
#include "GCs.h"
|
|
|
|
#include "compext/Compext.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(void)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentInitSplitResources: Initializing the split resources.\n");
|
|
#endif
|
|
|
|
for (int 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(void)
|
|
{
|
|
int resource;
|
|
|
|
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 exhausted.
|
|
*/
|
|
FatalError("nxagentAllocSplitResource: PANIC! No more resources for the next split.\n");
|
|
}
|
|
}
|
|
|
|
SplitResourcePtr 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(void)
|
|
{
|
|
/*
|
|
FIXME: This must be implemented.
|
|
*/
|
|
}
|
|
|
|
UnpackResourcePtr nxagentAllocUnpackResource(void)
|
|
{
|
|
/*
|
|
FIXME: This must be implemented.
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
void nxagentFreeUnpackResource(UnpackResourcePtr pResource)
|
|
{
|
|
/*
|
|
FIXME: This must be implemented.
|
|
*/
|
|
}
|
|
|
|
void nxagentReleaseAllSplits(void)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReleaseAllSplits: Going to release all the split resources.\n");
|
|
#endif
|
|
|
|
for (int 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)
|
|
{
|
|
pDrawable = nxagentSplitDrawable(pDrawable);
|
|
|
|
SplitResourcePtr 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)
|
|
{
|
|
pDrawable = nxagentSplitDrawable(pDrawable);
|
|
|
|
SplitResourcePtr 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)
|
|
{
|
|
pDrawable = nxagentSplitDrawable(pDrawable);
|
|
|
|
SplitResourcePtr 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("nxagentReleaseSplit: PANIC! Found a region for resource [%d] but the "
|
|
"commits are invalid.\n", pResource -> split);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentReleaseSplit: 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
|
|
|
|
RegionDestroy(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)
|
|
{
|
|
pDrawable = nxagentSplitDrawable(pDrawable);
|
|
|
|
SplitResourcePtr 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.
|
|
*/
|
|
|
|
RegionInit(&tmpRegion, NullBox, 1);
|
|
|
|
RegionIntersect(&tmpRegion, pResource -> region, pRegion);
|
|
|
|
if (!RegionNil(&tmpRegion))
|
|
{
|
|
#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
|
|
|
|
RegionUninit(&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, 0);
|
|
}
|
|
}
|
|
|
|
static Bool nxagentCommitSplitPredicate(Display *disp, 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 *disp, 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);
|
|
}
|
|
|
|
Bool nxagentWaitSplitEvent(int resource)
|
|
{
|
|
XEvent event;
|
|
|
|
Bool 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 = True;
|
|
|
|
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 (!RegionNil(pResource -> region))
|
|
{
|
|
RegionSubtract(
|
|
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(void)
|
|
{
|
|
/*
|
|
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;
|
|
}
|
|
}
|
|
}
|