/**************************************************************************/
/*                                                                        */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)          */
/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>  */
/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de>                */
/* Copyright (c) 2014-2016 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);
  }
}
