3069 lines
87 KiB
C
3069 lines
87 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 "dixstruct.h"
|
|
#include "../../fb/fb.h"
|
|
#include "misc.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 "Utils.h"
|
|
|
|
#include "compext/Compext.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 RegionRects().
|
|
*/
|
|
|
|
#define USE_OPTIMIZED_BOXES
|
|
|
|
/*
|
|
* The rectangles composing a region are de- fragmented to reduce the
|
|
* number of synchronizing 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
|
|
* split but the user will see more updates together.
|
|
*/
|
|
|
|
#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;
|
|
|
|
/*
|
|
* Number of windows which need synchronization.
|
|
*/
|
|
|
|
int nxagentCorruptedWindows = 0;
|
|
int nxagentCorruptedBackgrounds = 0;
|
|
|
|
Bool nxagentForceSynchronization = False;
|
|
|
|
_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, void *);
|
|
|
|
unsigned long nxagentGetColor(DrawablePtr pDrawable, int xPixel, int yPixel);
|
|
unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable);
|
|
unsigned long nxagentGetRegionColor(DrawablePtr pDrawable, RegionPtr pRegion);
|
|
|
|
Bool nxagentSkipImage = False;
|
|
|
|
static int nxagentTooManyImageData(void)
|
|
{
|
|
unsigned int limit = nxagentOption(ImageRateLimit);
|
|
unsigned int r = nxagentGetDataRate() / 1000;
|
|
|
|
#ifdef TEST
|
|
if (r > limit)
|
|
{
|
|
fprintf(stderr, "Warning: Current bit rate is: %u kB/s.\n", r);
|
|
}
|
|
#endif
|
|
|
|
return (r > limit);
|
|
}
|
|
|
|
int nxagentSynchronizeDrawable(DrawablePtr pDrawable, int wait, unsigned int breakMask, WindowPtr owner)
|
|
{
|
|
pDrawable = nxagentSplitDrawable(pDrawable);
|
|
|
|
if (!nxagentLosslessTrap)
|
|
{
|
|
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 = True;
|
|
|
|
nxagentSplitTrap = True;
|
|
|
|
int result = nxagentSynchronizeDrawableData(pDrawable, breakMask, owner);
|
|
|
|
nxagentSplitTrap = False;
|
|
|
|
nxagentFBTrap = False;
|
|
|
|
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;
|
|
}
|
|
|
|
static int reallySynchronizeDrawableData(DrawablePtr pDrawable)
|
|
{
|
|
GCPtr pGC = nxagentGetGraphicContext(pDrawable);
|
|
|
|
if (pGC == NULL)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "%s: WARNING! Failed to get the temporary GC.\n", __func__);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
DrawablePtr pSrcDrawable = (pDrawable -> type == DRAWABLE_PIXMAP ?
|
|
((DrawablePtr) nxagentVirtualPixmap((PixmapPtr) pDrawable)) :
|
|
pDrawable);
|
|
|
|
int width = pDrawable -> width;
|
|
int height = pDrawable -> height;
|
|
int depth = pDrawable -> depth;
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Synchronizing drawable (%s) with geometry [%d][%d][%d].\n",
|
|
__func__, nxagentDrawableType(pDrawable), width, height, depth);
|
|
#endif
|
|
|
|
unsigned int format = (depth == 1) ? XYPixmap : ZPixmap;
|
|
|
|
int length = nxagentImageLength(width, height, format, 0, depth);
|
|
|
|
char *data = malloc(length);
|
|
if (data == NULL)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "%s: WARNING! Failed to allocate memory for the operation.\n", __func__);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
ValidateGC(pDrawable, pGC);
|
|
|
|
fbGetImage(pSrcDrawable, 0, 0, width, height, format, AllPlanes, data);
|
|
|
|
nxagentPutImage(pDrawable, pGC, depth, 0, 0,
|
|
width, height, 0, format, data);
|
|
|
|
SAFE_free(data);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int nxagentSynchronizeDrawableData(DrawablePtr pDrawable, unsigned int breakMask, WindowPtr owner)
|
|
{
|
|
if (pDrawable -> type == DRAWABLE_PIXMAP)
|
|
{
|
|
/*
|
|
* Synchronize the whole pixmap if we need to download a fresh
|
|
* copy with lossless compression turned off.
|
|
*/
|
|
|
|
if (nxagentLosslessTrap)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Forcing synchronization of pixmap at [%p] with lossless compression.\n",
|
|
__func__, (void *) pDrawable);
|
|
#endif
|
|
|
|
return reallySynchronizeDrawableData(pDrawable);
|
|
}
|
|
else if (nxagentReconnectTrap)
|
|
{
|
|
/*
|
|
* 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)
|
|
{
|
|
static int totalLength;
|
|
static int totalReconnectedPixmaps;
|
|
|
|
totalLength += length;
|
|
totalReconnectedPixmaps++;
|
|
|
|
fprintf(stderr, "%s: Reconnecting pixmap at [%p] [%dx%d] "
|
|
"Depth [%d] Size [%d]. Total size [%d]. Total reconnected pixmaps [%d].\n",
|
|
__func__, (void *) pDrawable, width, height, depth, length,
|
|
totalLength, totalReconnectedPixmaps);
|
|
}
|
|
#endif
|
|
|
|
return reallySynchronizeDrawableData(pDrawable);
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Skipping synchronization of pixmap at [%p][%p] during reconnection.\n",
|
|
__func__, (void *) pDrawable, (void*) nxagentVirtualPixmap((PixmapPtr)pDrawable));
|
|
#endif
|
|
|
|
nxagentMarkCorruptedRegion(pDrawable, NullRegion);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* By calling this function with the NullRegion as parameter we are
|
|
* requesting to synchronize the full visible corrupted region of
|
|
* the drawable.
|
|
*/
|
|
|
|
return nxagentSynchronizeRegion(pDrawable, NullRegion, breakMask, owner);
|
|
}
|
|
|
|
/*
|
|
* If pRegion is NullRegion, all the viewable corrupted region will be
|
|
* synchronized.
|
|
*/
|
|
|
|
int nxagentSynchronizeRegion(DrawablePtr pDrawable, RegionPtr pRegion, unsigned int breakMask, WindowPtr owner)
|
|
{
|
|
DrawablePtr pSrcDrawable;
|
|
|
|
int leftPad = 0;
|
|
int success = 0;
|
|
char *data = NULL;
|
|
GCPtr pGC = NULL;
|
|
RegionPtr clipRegion = NullRegion;
|
|
|
|
#ifdef COLLECTED_UPDATES
|
|
RegionRec collectedUpdates;
|
|
RegionInit(&collectedUpdates, NullBox, 1);
|
|
#endif
|
|
|
|
RegionRec exposeRegion;
|
|
RegionInit(&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.
|
|
*/
|
|
|
|
Bool useStoredBitmap = (nxagentDrawableBitmap(pDrawable) != NullPixmap && pRegion == NullRegion);
|
|
|
|
if (useStoredBitmap)
|
|
{
|
|
#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,
|
|
RegionNumRects(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.
|
|
*/
|
|
|
|
RegionIntersect(clipRegion, clipRegion,
|
|
nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)));
|
|
|
|
/*
|
|
* The bitmap regions used in the synchronizations 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 synchronization will fix the error.
|
|
*/
|
|
|
|
RegionIntersect(clipRegion, clipRegion,
|
|
nxagentCorruptedRegion(pDrawable));
|
|
|
|
/*
|
|
* The bitmap to synchronize is clipped.
|
|
*/
|
|
|
|
if (RegionNil(clipRegion))
|
|
{
|
|
#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 && RegionNil(pRegion))
|
|
{
|
|
#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.
|
|
*/
|
|
|
|
RegionIntersect(clipRegion, clipRegion, nxagentCorruptedRegion(pDrawable));
|
|
|
|
if (RegionNil(clipRegion))
|
|
{
|
|
#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 requested region is not
|
|
* corrupted. Specifying a NullRegion as parameter, all the
|
|
* viewable corrupted region will be synchronized.
|
|
*/
|
|
|
|
if (pRegion != NullRegion)
|
|
{
|
|
RegionIntersect(clipRegion, clipRegion, pRegion);
|
|
|
|
if (RegionNil(clipRegion))
|
|
{
|
|
#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
|
|
|
|
int saveTrap = nxagentGCTrap;
|
|
|
|
nxagentGCTrap = False;
|
|
|
|
nxagentFBTrap = True;
|
|
|
|
nxagentSplitTrap = True;
|
|
|
|
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",
|
|
RegionNumRects(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
|
|
* important to avoid using the drawable size, because in case of a
|
|
* huge window it had to result in a failed data memory allocation.
|
|
*/
|
|
|
|
int w, h, extentWidth, extentHeight, tileWidth, tileHeight;
|
|
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
|
|
|
|
int length, format;
|
|
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 information if the image length is zero.
|
|
*/
|
|
|
|
if (length == 0)
|
|
{
|
|
fprintf(stderr, "nxagentSynchronizeRegion: Drawable [%s] at [%p] with region geometry [%d][%d,%d,%d,%d].\n",
|
|
nxagentDrawableType(pDrawable), (void *) pDrawable, RegionNumRects(clipRegion),
|
|
clipRegion -> extents.x1, clipRegion -> extents.y1,
|
|
clipRegion -> extents.x2, clipRegion -> extents.y2);
|
|
}
|
|
|
|
#endif
|
|
|
|
goto nxagentSynchronizeRegionFree;
|
|
}
|
|
|
|
#ifndef USE_OPTIMIZED_BOXES
|
|
|
|
BoxPtr pBox = RegionRects(clipRegion);
|
|
|
|
#else
|
|
|
|
BoxPtr pBox = nxagentGetOptimizedRegionBoxes(clipRegion);
|
|
|
|
#endif /* USE_OPTIMIZED_BOXES */
|
|
|
|
int nBox = RegionNumRects(clipRegion);
|
|
|
|
unsigned long now = GetTimeInMillis();
|
|
|
|
nxagentSynchronization.abort = False;
|
|
|
|
/*
|
|
* Going to split the updated region into small blocks.
|
|
*/
|
|
|
|
for (int 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
|
|
|
|
BoxRec box = pBox[i];
|
|
|
|
for (int y = box.y1; y < box.y2; y += h)
|
|
{
|
|
h = min(box.y2 - y, tileHeight);
|
|
|
|
for (int 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.
|
|
*/
|
|
|
|
unsigned long elapsedTime = GetTimeInMillis() - now;
|
|
|
|
if (elapsedTime > nxagentOption(DeferTimeout))
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with "
|
|
"[%lu] ms elapsed.\n", elapsedTime);
|
|
#endif
|
|
|
|
nxagentSynchronization.abort = True;
|
|
|
|
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 = True;
|
|
|
|
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 = True;
|
|
|
|
goto nxagentSynchronizeRegionStop;
|
|
}
|
|
|
|
BoxRec tileBox = {.x1 = x, .y1 = y, .x2 = x + w, .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.
|
|
*/
|
|
|
|
RegionRec tileRegion;
|
|
RegionInit(&tileRegion, &tileBox, 1);
|
|
|
|
RegionUnion(&exposeRegion, &exposeRegion, &tileRegion);
|
|
|
|
#ifdef COLLECTED_UPDATES
|
|
RegionAppend(&collectedUpdates, &tileRegion);
|
|
#endif
|
|
|
|
if (useStoredBitmap != 0)
|
|
{
|
|
/*
|
|
* When a bitmap's tile is synchronized, we can clear the
|
|
* corresponding region. We can't use the
|
|
* nxagentUnmarkCorruptedRegion because we have not a
|
|
* resource associated to this pixmap.
|
|
*/
|
|
|
|
RegionSubtract(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)
|
|
{
|
|
int cmpLength, cmpFormat;
|
|
|
|
char *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
|
|
}
|
|
|
|
SAFE_free(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
|
|
|
|
RegionSubtract(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);
|
|
|
|
RegionUninit(&tileRegion);
|
|
|
|
#if !defined(COLLECTED_UPDATES)
|
|
|
|
if (owner != NULL)
|
|
{
|
|
if (nxagentOption(Shadow) &&
|
|
(nxagentOption(XRatio) != DONT_SCALE ||
|
|
nxagentOption(YRatio) != DONT_SCALE))
|
|
{
|
|
int scaledx = nxagentScale(x, nxagentOption(XRatio));
|
|
int scaledy = nxagentScale(y, nxagentOption(YRatio));
|
|
|
|
int scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx;
|
|
int 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 = True;
|
|
|
|
goto nxagentSynchronizeRegionStop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nxagentSynchronizeRegionStop:
|
|
|
|
nxagentSplitTrap = False;
|
|
|
|
nxagentFBTrap = False;
|
|
|
|
nxagentGCTrap = saveTrap;
|
|
|
|
success = 1;
|
|
|
|
if (!nxagentOption(Shadow))
|
|
{
|
|
if (nxagentSynchronization.abort)
|
|
{
|
|
/*
|
|
* Storing the pointer to the drawable we were synchronizing
|
|
* when the loop aborted. It is used in
|
|
* nxagentSynchronizeDrawablePredicate.
|
|
*/
|
|
|
|
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 &&
|
|
!RegionNil(&exposeRegion))
|
|
{
|
|
struct nxagentExposeBackground eb = {
|
|
.pBackground = (PixmapPtr) pDrawable,
|
|
.pExpose = &exposeRegion,
|
|
};
|
|
|
|
for (int 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;
|
|
|
|
RegionValidate(&collectedUpdates, &overlap);
|
|
|
|
for (int i = 0; i < RegionNumRects(&collectedUpdates); i++)
|
|
{
|
|
int x = RegionRects(&collectedUpdates)[i].x1;
|
|
int y = RegionRects(&collectedUpdates)[i].y1;
|
|
int w = RegionRects(&collectedUpdates)[i].x2 - RegionRects(&collectedUpdates)[i].x1;
|
|
int h = RegionRects(&collectedUpdates)[i].y2 - RegionRects(&collectedUpdates)[i].y1;
|
|
|
|
if (nxagentOption(Shadow) &&
|
|
(nxagentOption(XRatio) != DONT_SCALE ||
|
|
nxagentOption(YRatio) != DONT_SCALE))
|
|
{
|
|
int scaledx = nxagentScale(x, nxagentOption(XRatio));
|
|
int scaledy = nxagentScale(y, nxagentOption(YRatio));
|
|
|
|
int scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx;
|
|
int 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(clipRegion);
|
|
}
|
|
|
|
SAFE_free(data);
|
|
|
|
RegionUninit(&exposeRegion);
|
|
|
|
#ifdef COLLECTED_UPDATES
|
|
|
|
RegionUninit(&collectedUpdates);
|
|
|
|
#endif /* #ifdef COLLECTED_UPDATES */
|
|
|
|
return success;
|
|
}
|
|
|
|
void nxagentSynchronizeBox(DrawablePtr pDrawable, BoxPtr pBox, unsigned int breakMask)
|
|
{
|
|
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
|
|
|
|
RegionPtr pRegion = nxagentCreateRegion(pDrawable, NULL, pBox -> x1, pBox -> y1,
|
|
pBox -> x2 - pBox -> x1, pBox -> y2 - pBox -> y1);
|
|
|
|
|
|
if (RegionNil(pRegion))
|
|
{
|
|
#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(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(pRegion);
|
|
}
|
|
}
|
|
|
|
void nxagentSynchronizeDrawablePredicate(void *p0, XID x1, void *p2)
|
|
{
|
|
DrawablePtr pDrawable = (DrawablePtr) p0;
|
|
unsigned int *breakMask = (unsigned int *) p2;
|
|
|
|
Bool shouldClearHiddenRegion = True;
|
|
|
|
/*
|
|
* The nxagentSynchronization.abort propagates a break condition
|
|
* across the resources loop, in order to block also the subsequent
|
|
* synchronizations.
|
|
*/
|
|
|
|
if (nxagentSynchronization.abort ||
|
|
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)
|
|
{
|
|
#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 synchronizing 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 = True;
|
|
|
|
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,
|
|
RegionNumRects(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 &&
|
|
shouldClearHiddenRegion)
|
|
{
|
|
#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)
|
|
{
|
|
/*
|
|
FIXME: All drawables should be set as synchronized and never marked as
|
|
corrupted while the display is down.
|
|
*/
|
|
|
|
nxagentSkipImage = nxagentTooManyImageData();
|
|
|
|
if (nxagentOption(ImageRateLimit) && nxagentSkipImage)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentSynchronizeDrawable: Skipping due to bit rate limit reached.\n");
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
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
|
|
|
|
unsigned int 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.
|
|
*/
|
|
|
|
Bool doRoundRobin = (nxagentSynchronization.pDrawable != NULL);
|
|
|
|
nxagentSynchronization.abort = False;
|
|
|
|
/*
|
|
* 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 &&
|
|
nxagentSynchronization.windowBitmaps == 0 &&
|
|
!doRoundRobin)
|
|
{
|
|
if (nxagentCorruptedWindows > 0)
|
|
{
|
|
fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] "
|
|
"corrupted windows.\n", nxagentCorruptedWindows);
|
|
}
|
|
|
|
nxagentCorruptedWindows = 0;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Synchronize the backgrounds.
|
|
*/
|
|
|
|
if (!nxagentSynchronization.abort &&
|
|
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 &&
|
|
nxagentSynchronization.backgroundBitmaps == 0 &&
|
|
!doRoundRobin)
|
|
{
|
|
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 &&
|
|
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 &&
|
|
nxagentSynchronization.pixmapBitmaps == 0 &&
|
|
!doRoundRobin)
|
|
{
|
|
#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)
|
|
{
|
|
BoxRec box = {.x1 = x, .y1 = y, .x2 = x + width, .y2 = y + height};
|
|
RegionPtr pRegion = RegionCreate(&box, 1);
|
|
|
|
/*
|
|
* Clipping the region.
|
|
*/
|
|
|
|
if (pDrawable -> type == DRAWABLE_PIXMAP)
|
|
{
|
|
/*
|
|
* 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)
|
|
{
|
|
BoxRec tmpBox = {.x1 = 0, .y1 = 0, .x2 = pDrawable -> width, .y2 = pDrawable -> height};
|
|
RegionRec tmpRegion;
|
|
|
|
RegionInit(&tmpRegion, &tmpBox, 1);
|
|
|
|
RegionIntersect(pRegion, &tmpRegion, pRegion);
|
|
|
|
RegionUninit(&tmpRegion);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We use the clipList because the borderClip contains also parts
|
|
* of the window covered by its children.
|
|
*/
|
|
|
|
RegionTranslate(pRegion,
|
|
pDrawable -> x, pDrawable -> y);
|
|
|
|
if (nxagentWindowPriv((WindowPtr) pDrawable) -> hasTransparentChildren == 1)
|
|
{
|
|
RegionIntersect(pRegion, pRegion, &((WindowPtr) pDrawable) -> borderClip);
|
|
}
|
|
else
|
|
{
|
|
RegionIntersect(pRegion, pRegion, &((WindowPtr) pDrawable) -> clipList);
|
|
}
|
|
|
|
RegionTranslate(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 (!RegionNil(pRegion) &&
|
|
pGC != NULL && pGC -> clientClip != NULL &&
|
|
pGC -> clientClipType == CT_REGION)
|
|
{
|
|
RegionRec clipRegion;
|
|
|
|
RegionInit(&clipRegion, NullBox, 1);
|
|
|
|
RegionCopy(&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)
|
|
{
|
|
RegionTranslate(&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
|
|
|
|
RegionIntersect(pRegion, pRegion, &clipRegion);
|
|
|
|
RegionUninit(&clipRegion);
|
|
}
|
|
|
|
return pRegion;
|
|
}
|
|
|
|
void nxagentMarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion)
|
|
{
|
|
if (pRegion != NullRegion && RegionNil(pRegion))
|
|
{
|
|
#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)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
|
|
int width = pDrawable -> width;
|
|
int 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);
|
|
|
|
RegionUnion(nxagentCorruptedRegion(pDrawable),
|
|
nxagentCorruptedRegion(pDrawable), pRegion);
|
|
|
|
nxagentFreeRegion(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);
|
|
|
|
RegionUnion(nxagentCorruptedRegion(pDrawable),
|
|
nxagentCorruptedRegion(pDrawable), pRegion);
|
|
}
|
|
}
|
|
|
|
void nxagentUnmarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion)
|
|
{
|
|
if (pRegion != NullRegion && RegionNil(pRegion))
|
|
{
|
|
#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;
|
|
}
|
|
|
|
int 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);
|
|
|
|
RegionEmpty(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);
|
|
|
|
RegionSubtract(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.
|
|
* Note: oldstatus has been checked above and is always
|
|
* "NotSynchronized" here.
|
|
*/
|
|
|
|
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
|
|
|
|
RegionTranslate(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; moreover it organizes the
|
|
* rectangles in 'bands' sharing the same y-dimension. This
|
|
* representation does not minimize the number of rectangles. For
|
|
* example, the following region has 4 rectangles:
|
|
*
|
|
* +-----------+
|
|
* | | +---+
|
|
* | A | | B |
|
|
* | | +---+
|
|
* +-----------+
|
|
*
|
|
* The rectangle 'B' creates a band which splits the rectangle A in 3
|
|
* parts, for a total of 3 bands. The number 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 boxes 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)
|
|
{
|
|
BoxRec boxExtents;
|
|
|
|
BoxPtr pBox = RegionRects(pRegion);
|
|
|
|
int nBox = RegionNumRects(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
|
|
int nBoxOptim = nBox;
|
|
#endif
|
|
|
|
/*
|
|
* The boxes are now grouped to grown as much as possible, using
|
|
* their overlapping vertex as rule.
|
|
*/
|
|
|
|
for (int 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 (int 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 (int 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 (int 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)
|
|
{
|
|
int leftPad = 0;
|
|
|
|
int depth = pDrawable -> depth;
|
|
int format = (depth == 1) ? XYPixmap : ZPixmap;
|
|
int length = nxagentImageLength(1, 1, format, leftPad, depth);
|
|
|
|
char * data = malloc(length);
|
|
if (data == NULL)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentGetColor: WARNING! Failed to allocate memory for the operation.\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
Visual *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 *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
|
|
|
|
SAFE_free(data);
|
|
|
|
return -1;
|
|
}
|
|
|
|
unsigned long 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)
|
|
{
|
|
if (RegionNil(pRegion))
|
|
{
|
|
return nxagentGetDrawableColor(pDrawable);
|
|
}
|
|
|
|
/*
|
|
* The pixel used as reference is the first outer pixel at the
|
|
* bottom right corner of corrupted region extents.
|
|
*/
|
|
|
|
int xPicker = pRegion -> extents.x2 + 1;
|
|
|
|
if (xPicker > pDrawable -> width)
|
|
{
|
|
xPicker = pDrawable -> width;
|
|
}
|
|
|
|
int yPicker = pRegion -> extents.y2 + 1;
|
|
|
|
if (yPicker > pDrawable -> height)
|
|
{
|
|
yPicker = pDrawable -> height;
|
|
}
|
|
|
|
return nxagentGetColor(pDrawable, xPicker, yPicker);
|
|
}
|
|
|
|
unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable)
|
|
{
|
|
/*
|
|
* The pixel used to determine the color of a drawable is at
|
|
* coordinates (x + width - 4, y + 4).
|
|
*/
|
|
|
|
return nxagentGetColor(pDrawable, pDrawable -> width - 4, 4);
|
|
}
|
|
|
|
void nxagentClearRegion(DrawablePtr pDrawable, RegionPtr pRegion)
|
|
{
|
|
unsigned long backupPixel = 0;
|
|
|
|
#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 || RegionNil(pRegion))
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentClearRegion: The region is empty. Exiting.\n");
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
WindowPtr pWin = (WindowPtr) pDrawable;
|
|
|
|
int 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;
|
|
|
|
unsigned long 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;
|
|
}
|
|
|
|
BoxPtr pBox = nxagentGetOptimizedRegionBoxes(pRegion);
|
|
|
|
int nBox = RegionNumRects(pRegion);
|
|
|
|
for (int 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)
|
|
{
|
|
if (RegionNil(pRegion))
|
|
{
|
|
return;
|
|
}
|
|
|
|
GCPtr pGC = nxagentGetGraphicContext(pDrawable);
|
|
|
|
int nrects = RegionNumRects(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
|
|
{
|
|
BoxPtr pBox = RegionRects(pRegion);
|
|
XRectangle *pRects = malloc(nrects * sizeof(XRectangle));
|
|
|
|
for (int 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);
|
|
|
|
SAFE_free(pRects);
|
|
}
|
|
}
|
|
|
|
int nxagentDestroyCorruptedWindowResource(void * 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(void * 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(void * 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 = RegionCreate(NullBox, 1);
|
|
|
|
xPoint *xp = pPoints;
|
|
|
|
for (int np = nPoints; np--; xp++)
|
|
{
|
|
BoxRec box;
|
|
|
|
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.
|
|
*/
|
|
|
|
RegionRec tmpRegion;
|
|
RegionInit(&tmpRegion, &box, 1);
|
|
|
|
RegionUnion(pRegion, pRegion, &tmpRegion);
|
|
|
|
RegionUninit(&tmpRegion);
|
|
}
|
|
|
|
BoxRec extents = *RegionExtents(pRegion);
|
|
|
|
RegionReset(pRegion, &extents);
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentPointsToDirtyRegion: The resulting dirty region has [%ld] rects and"
|
|
" extents (%d,%d,%d,%d).\n", RegionNumRects(pRegion), extents.x1,
|
|
extents.y1, extents.x2, extents.y2);
|
|
#endif
|
|
|
|
nxagentMarkCorruptedRegion(pDrawable, pRegion);
|
|
|
|
RegionDestroy(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))
|
|
{
|
|
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);
|
|
|
|
RegionInit(&visRegion, NullBox, 1);
|
|
|
|
RegionIntersect(&visRegion, clipRegion, nxagentCorruptedRegion((DrawablePtr) pWin));
|
|
|
|
nxagentFreeRegion(clipRegion);
|
|
|
|
if (RegionNil(&visRegion))
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentCorruptedRegionOnWindow: The corrupted region of window at [%p] is hidden.\n",
|
|
(void *) pWin);
|
|
#endif
|
|
|
|
RegionUninit(&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 = RegionNumRects(&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);
|
|
|
|
RegionUninit(&visRegion);
|
|
}
|
|
|
|
void nxagentRegionsOnScreen(void)
|
|
{
|
|
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)
|
|
{
|
|
GCPtr pGC = NULL;
|
|
RegionPtr pClipRegion = NullRegion;
|
|
|
|
#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.
|
|
*/
|
|
|
|
int saveTrap = nxagentGCTrap;
|
|
|
|
nxagentGCTrap = True;
|
|
|
|
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 destroying 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);
|
|
|
|
RegionIntersect(pClipRegion, pClipRegion, nxagentCorruptedRegion(pDrawable));
|
|
|
|
if (RegionNil(pClipRegion))
|
|
{
|
|
#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.
|
|
*/
|
|
|
|
PixmapPtr pBitmap;
|
|
pBitmap = nxagentCreatePixmap(pDrawable -> pScreen, pDrawable -> width, pDrawable -> height, pDrawable -> depth, 0);
|
|
|
|
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);
|
|
|
|
int x = pClipRegion -> extents.x1;
|
|
int y = pClipRegion -> extents.y1;
|
|
int w = pClipRegion -> extents.x2 - pClipRegion -> extents.x1;
|
|
int h = pClipRegion -> extents.y2 - pClipRegion -> extents.y1;
|
|
|
|
nxagentCopyArea(pDrawable, (DrawablePtr) pBitmap, pGC, x, y, w, h, x, y);
|
|
|
|
RegionUnion(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(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,
|
|
(void *) 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,
|
|
(void *) 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))
|
|
{
|
|
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,
|
|
(void *) 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 && !RegionNil(pRegion) &&
|
|
nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized)
|
|
{
|
|
RegionInit(&clipRegion, NullBox, 1);
|
|
|
|
RegionCopy(&clipRegion, pRegion);
|
|
|
|
if (pOther != NullRegion && !RegionNil(pOther))
|
|
{
|
|
RegionUnion(&clipRegion, &clipRegion, pOther);
|
|
}
|
|
|
|
RegionTranslate(&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);
|
|
|
|
RegionUninit(&clipRegion);
|
|
}
|
|
}
|
|
|
|
int nxagentSynchronizationPredicate(void)
|
|
{
|
|
if (nxagentCorruptedWindows == 0 &&
|
|
nxagentCorruptedBackgrounds == 0 &&
|
|
nxagentCorruptedPixmaps == 0)
|
|
{
|
|
return NotNeeded;
|
|
}
|
|
|
|
if (!nxagentBlocking &&
|
|
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;
|
|
|
|
RegionInit(&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
|
|
|
|
RegionCopy(&expose, &pWin -> winSize);
|
|
}
|
|
else
|
|
{
|
|
RegionCopy(&expose, pExpose);
|
|
|
|
RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y);
|
|
}
|
|
|
|
RegionSubtract(&expose, &expose, nxagentCorruptedRegion((DrawablePtr) pWin));
|
|
|
|
if (RegionNil(&pWin -> clipList))
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentSendBackgroundExpose: Exposures deferred because the window "
|
|
"is hidden.\n");
|
|
#endif
|
|
|
|
RegionUnion(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) && !RegionNil(&pBackingStore->SavedRegion))
|
|
{
|
|
RegionTranslate(&expose, -pWin -> drawable.x, -pWin -> drawable.y);
|
|
|
|
RegionSubtract(&expose, &expose, &pBackingStore -> SavedRegion);
|
|
|
|
RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y);
|
|
}
|
|
|
|
RegionIntersect(&expose, &expose, &pWin -> clipList);
|
|
|
|
/*
|
|
* Reduce the overall region to expose.
|
|
*/
|
|
|
|
RegionTranslate(&expose, -pWin -> drawable.x, -pWin -> drawable.y);
|
|
|
|
RegionSubtract(pExpose, pExpose, &expose);
|
|
|
|
RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y);
|
|
|
|
miWindowExposures(pWin, &expose, &expose);
|
|
|
|
nxagentSendBackgroundExposeEnd:
|
|
|
|
RegionUninit(&expose);
|
|
}
|
|
|
|
void nxagentExposeBackgroundPredicate(void *p0, XID x1, void *p2)
|
|
{
|
|
WindowPtr pWin = (WindowPtr) p0;
|
|
|
|
struct nxagentExposeBackground *pPair = p2;
|
|
|
|
if (RegionNil(pPair -> pExpose))
|
|
{
|
|
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
|
|
|
|
WindowPtr 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, void * ptr)
|
|
{
|
|
RegionPtr remoteExposeRgn = (RegionRec *) ptr;
|
|
|
|
if (nxagentWindowPriv(pWin) -> deferredBackgroundExpose == 1)
|
|
{
|
|
RegionPtr exposeRgn = RegionCreate(NULL, 1);
|
|
|
|
#ifdef DEBUG
|
|
BoxRec box = *RegionExtents(remoteExposeRgn);
|
|
|
|
fprintf(stderr, "nxagentClipAndSendClearExpose: Background expose extents: [%d,%d,%d,%d].\n",
|
|
box.x1, box.y1, box.x2, box.y2);
|
|
|
|
box = *RegionExtents(&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
|
|
|
|
RegionIntersect(exposeRgn, remoteExposeRgn, &pWin -> clipList);
|
|
|
|
/*
|
|
* If the region will be synchronized, the expose on corrupted
|
|
* regions can be ignored.
|
|
*/
|
|
|
|
RegionSubtract(exposeRgn, exposeRgn, nxagentCorruptedRegion((DrawablePtr) pWin));
|
|
|
|
if (RegionNotEmpty(exposeRgn))
|
|
{
|
|
#ifdef DEBUG
|
|
box = *RegionExtents(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
|
|
|
|
RegionSubtract(remoteExposeRgn, remoteExposeRgn, exposeRgn);
|
|
|
|
miWindowExposures(pWin, exposeRgn, exposeRgn);
|
|
}
|
|
|
|
RegionDestroy(exposeRgn);
|
|
|
|
nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 0;
|
|
}
|
|
|
|
if (RegionNotEmpty(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 = RegionCreate(NullBox, 1);
|
|
}
|
|
|
|
if (RegionNotEmpty(nxagentDeferredBackgroundExposures) != 0)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentSendDeferredBackgroundExposures: Going to send deferred exposures to the root window.\n");
|
|
#endif
|
|
|
|
TraverseTree(screenInfo.screens[0]->root, nxagentClipAndSendClearExpose, (void *) nxagentDeferredBackgroundExposures);
|
|
|
|
RegionEmpty(nxagentDeferredBackgroundExposures);
|
|
}
|
|
}
|