Logo Search packages:      
Sourcecode: xorg-server version File versions  Download package

mioverlay.c

/* $XFree86: xc/programs/Xserver/mi/mioverlay.c,v 3.15tsi Exp $ */

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include <X11/X.h>
#include "scrnintstr.h"
#include "validate.h"
#include "windowstr.h"
#include "mi.h"
#include "gcstruct.h"
#include "regionstr.h"
#include "mivalidate.h"
#include "mioverlay.h"
#include "migc.h"

#include "globals.h"


typedef struct {
   RegionRec      exposed;
   RegionRec      borderExposed;
   RegionPtr      borderVisible;
   DDXPointRec    oldAbsCorner;
} miOverlayValDataRec, *miOverlayValDataPtr;

typedef struct _TreeRec {
   WindowPtr            pWin;
   struct _TreeRec      *parent;
   struct _TreeRec      *firstChild; 
   struct _TreeRec      *lastChild; 
   struct _TreeRec      *prevSib; 
   struct _TreeRec      *nextSib;
   RegionRec            borderClip;
   RegionRec            clipList;
   unsigned       visibility;
   miOverlayValDataPtr  valdata;
} miOverlayTreeRec, *miOverlayTreePtr;

typedef struct {
   miOverlayTreePtr     tree;
} miOverlayWindowRec, *miOverlayWindowPtr;

typedef struct {
   CloseScreenProcPtr         CloseScreen;
   CreateWindowProcPtr        CreateWindow;
   DestroyWindowProcPtr       DestroyWindow;
   UnrealizeWindowProcPtr     UnrealizeWindow;
   RealizeWindowProcPtr       RealizeWindow;
   miOverlayTransFunc         MakeTransparent;
   miOverlayInOverlayFunc     InOverlay;
   Bool                       underlayMarked;
   Bool                       copyUnderlay;
} miOverlayScreenRec, *miOverlayScreenPtr;

static unsigned long miOverlayGeneration = 0;
int miOverlayWindowIndex = -1;
int miOverlayScreenIndex = -1;

static void RebuildTree(WindowPtr);
static Bool HasUnderlayChildren(WindowPtr);
static void MarkUnderlayWindow(WindowPtr);
static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr);

static Bool miOverlayCloseScreen(int, ScreenPtr);
static Bool miOverlayCreateWindow(WindowPtr);
static Bool miOverlayDestroyWindow(WindowPtr);
static Bool miOverlayUnrealizeWindow(WindowPtr);
static Bool miOverlayRealizeWindow(WindowPtr);
static void miOverlayMarkWindow(WindowPtr);
static void miOverlayReparentWindow(WindowPtr, WindowPtr);
static void miOverlayRestackWindow(WindowPtr, WindowPtr);
static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*);
static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool);
static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind);
static void miOverlayHandleExposures(WindowPtr);
static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind);
static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr);
static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int,
                              unsigned int, WindowPtr);
static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool);

#ifdef SHAPE
static void miOverlaySetShape(WindowPtr);
#endif
static void miOverlayChangeBorderWidth(WindowPtr, unsigned int);

#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) \
      ((miOverlayScreenPtr)((pScreen)->devPrivates[miOverlayScreenIndex].ptr))
#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) \
      ((miOverlayWindowPtr)((pWin)->devPrivates[miOverlayWindowIndex].ptr))
#define MIOVERLAY_GET_WINDOW_TREE(pWin) \
      (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree)

#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w)
#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w)

#define MARK_OVERLAY(w) miMarkWindow(w)
#define MARK_UNDERLAY(w) MarkUnderlayWindow(w)

#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
                                    HasBorder(w) && \
                                    (w)->backgroundState == ParentRelative)

Bool
miInitOverlay(
    ScreenPtr pScreen, 
    miOverlayInOverlayFunc inOverlayFunc,
    miOverlayTransFunc transFunc
){
    miOverlayScreenPtr  pScreenPriv;

    if(!inOverlayFunc || !transFunc) return FALSE;

    if(miOverlayGeneration != serverGeneration) {
      if(((miOverlayScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
         ((miOverlayWindowIndex = AllocateWindowPrivateIndex()) < 0))
          return FALSE;
      
      miOverlayGeneration = serverGeneration;
    }

    if(!AllocateWindowPrivate(pScreen, miOverlayWindowIndex,
                        sizeof(miOverlayWindowRec)))
      return FALSE;

    if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec))))
      return FALSE;

    pScreen->devPrivates[miOverlayScreenIndex].ptr = (pointer)pScreenPriv;

    pScreenPriv->InOverlay = inOverlayFunc;
    pScreenPriv->MakeTransparent = transFunc;
    pScreenPriv->underlayMarked = FALSE;


    pScreenPriv->CloseScreen = pScreen->CloseScreen;
    pScreenPriv->CreateWindow = pScreen->CreateWindow;
    pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
    pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
    pScreenPriv->RealizeWindow = pScreen->RealizeWindow;

    pScreen->CloseScreen = miOverlayCloseScreen;
    pScreen->CreateWindow = miOverlayCreateWindow;
    pScreen->DestroyWindow = miOverlayDestroyWindow;
    pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
    pScreen->RealizeWindow = miOverlayRealizeWindow;

    pScreen->ReparentWindow = miOverlayReparentWindow;
    pScreen->RestackWindow = miOverlayRestackWindow;
    pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows;
    pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow;
    pScreen->ValidateTree = miOverlayValidateTree;
    pScreen->HandleExposures = miOverlayHandleExposures;
    pScreen->MoveWindow = miOverlayMoveWindow;
    pScreen->WindowExposures = miOverlayWindowExposures;
    pScreen->ResizeWindow = miOverlayResizeWindow;
    pScreen->MarkWindow = miOverlayMarkWindow;
    pScreen->ClearToBackground = miOverlayClearToBackground;
#ifdef SHAPE
    pScreen->SetShape = miOverlaySetShape;
#endif
    pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth;

    return TRUE;
}


static Bool 
miOverlayCloseScreen(int i, ScreenPtr pScreen)
{
   miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);

   pScreen->CloseScreen = pScreenPriv->CloseScreen; 
   pScreen->CreateWindow = pScreenPriv->CreateWindow;
   pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
   pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
   pScreen->RealizeWindow = pScreenPriv->RealizeWindow;

   xfree(pScreenPriv);

   return (*pScreen->CloseScreen)(i, pScreen);
}


static Bool 
miOverlayCreateWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin);
    miOverlayTreePtr pTree = NULL;
    Bool result = TRUE;

    pWinPriv->tree = NULL;

    if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) {
      if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec))))
         return FALSE;
    }

    if(pScreenPriv->CreateWindow) {
      pScreen->CreateWindow = pScreenPriv->CreateWindow;
      result = (*pScreen->CreateWindow)(pWin);
      pScreen->CreateWindow = miOverlayCreateWindow;
    }
      
    if (pTree) {
      if(result) {
          pTree->pWin = pWin;
          pTree->visibility = VisibilityNotViewable;
          pWinPriv->tree = pTree;
          if(pWin->parent) {
            REGION_NULL(pScreen, &(pTree->borderClip));
            REGION_NULL(pScreen, &(pTree->clipList));
            RebuildTree(pWin);
          } else {
            BoxRec fullBox;
            fullBox.x1 = 0;
            fullBox.y1 = 0;
            fullBox.x2 = pScreen->width;
            fullBox.y2 = pScreen->height;
            REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1);
            REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1);
          }
      } else xfree(pTree);
    }

    return TRUE;
}


static Bool 
miOverlayDestroyWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    Bool result = TRUE;

    if (pTree) {
      if(pTree->prevSib)
         pTree->prevSib->nextSib = pTree->nextSib;
      else if(pTree->parent)
         pTree->parent->firstChild = pTree->nextSib;

      if(pTree->nextSib)
         pTree->nextSib->prevSib = pTree->prevSib;
      else if(pTree->parent)
         pTree->parent->lastChild = pTree->prevSib;

      REGION_UNINIT(pScreen, &(pTree->borderClip));
      REGION_UNINIT(pScreen, &(pTree->clipList));
      xfree(pTree);
    }

    if(pScreenPriv->DestroyWindow) {
      pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
      result = (*pScreen->DestroyWindow)(pWin);
      pScreen->DestroyWindow = miOverlayDestroyWindow;
    }

    return result;
}

static Bool 
miOverlayUnrealizeWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    Bool result = TRUE;

    if(pTree) pTree->visibility = VisibilityNotViewable;

    if(pScreenPriv->UnrealizeWindow) {
      pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
      result = (*pScreen->UnrealizeWindow)(pWin);
      pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
    }

    return result;
}


static Bool 
miOverlayRealizeWindow(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    Bool result = TRUE;

    if(pScreenPriv->RealizeWindow) {
      pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
      result = (*pScreen->RealizeWindow)(pWin);
      pScreen->RealizeWindow = miOverlayRealizeWindow;
    }

    /* we only need to catch the root window realization */

    if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin)))
    {
      BoxRec box;
      box.x1 = box.y1 = 0;
      box.x2 = pWin->drawable.width;
      box.y2 = pWin->drawable.height;
      (*pScreenPriv->MakeTransparent)(pScreen, 1, &box);
    }

    return result;
}


static void 
miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
{
    if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
      /* This could probably be more optimal */
      RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild);
    } 
}

static void 
miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib)
{
    if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
      /* This could probably be more optimal */
      RebuildTree(pWin);
    } 
}


static Bool
miOverlayMarkOverlappedWindows(
    WindowPtr pWin,
    WindowPtr pFirst,
    WindowPtr *pLayerWin
){
    ScreenPtr pScreen = pWin->drawable.pScreen;
    WindowPtr pChild, pLast;
    Bool overMarked, underMarked, doUnderlay, markAll;
    miOverlayTreePtr pTree = NULL, tLast, tChild;
    BoxPtr box;
    
    overMarked = underMarked = markAll = FALSE;

    if(pLayerWin) *pLayerWin = pWin; /* hah! */

    doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin));

    box = REGION_EXTENTS(pScreen, &pWin->borderSize);

    if((pChild = pFirst)) {
      pLast = pChild->parent->lastChild;
      while (1) {
          if (pChild == pWin) markAll = TRUE;

          if(doUnderlay && IN_UNDERLAY(pChild))
            pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);

          if(pChild->viewable) {
                if (REGION_BROKEN (pScreen, &pChild->winSize))
                    SetWinSize (pChild);
                if (REGION_BROKEN (pScreen, &pChild->borderSize))
                SetBorderSize (pChild);

            if (markAll || 
                RECT_IN_REGION(pScreen, &pChild->borderSize, box))
            {
                MARK_OVERLAY(pChild);
                overMarked = TRUE;
                if(doUnderlay && IN_UNDERLAY(pChild)) {
                  MARK_UNDERLAY(pChild);
                  underMarked = TRUE;
                }
                if (pChild->firstChild) {
                  pChild = pChild->firstChild;
                  continue;
                }
            }
          }
          while (!pChild->nextSib && (pChild != pLast)) {
            pChild = pChild->parent;
            if(doUnderlay && IN_UNDERLAY(pChild))
                pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
          }

          if(pChild == pWin) markAll = FALSE;

          if (pChild == pLast) break;

          pChild = pChild->nextSib;
      }
      if(overMarked)
          MARK_OVERLAY(pWin->parent);
    } 

    if(doUnderlay && !pTree) {
      if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) {
          pChild = pWin->lastChild;
          while(1) {
            if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild)))
                break;

            if(pChild->lastChild) {
                pChild = pChild->lastChild;
                continue;
            }

            while(!pChild->prevSib) pChild = pChild->parent;

            pChild = pChild->prevSib;
          }
      }
    }
   
    if(pTree && pTree->nextSib) {
      tChild = pTree->parent->lastChild;
      tLast = pTree->nextSib; 

      while(1) {
          if(tChild->pWin->viewable) { 
                if (REGION_BROKEN (pScreen, &tChild->pWin->winSize))
                    SetWinSize (tChild->pWin);
                if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize))
                SetBorderSize (tChild->pWin);

            if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box)) 
              {
                MARK_UNDERLAY(tChild->pWin);
                underMarked = TRUE;
              }
          }

          if(tChild->lastChild) {
            tChild = tChild->lastChild;
            continue;
          }

          while(!tChild->prevSib && (tChild != tLast))
            tChild = tChild->parent;

          if(tChild == tLast) break;

          tChild = tChild->prevSib;
      }
    }

    if(underMarked) {
      MARK_UNDERLAY(pTree->parent->pWin);
      MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE;     
    }

    return (underMarked || overMarked);
}


static void
miOverlayComputeClips(
    WindowPtr pParent, 
    RegionPtr universe,
    VTKind kind,
    RegionPtr exposed
){
    ScreenPtr pScreen = pParent->drawable.pScreen;
    int oldVis, newVis, dx, dy;
    BoxRec borderSize;
    RegionPtr borderVisible;
    RegionRec childUniverse, childUnion;
    miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent);
    miOverlayTreePtr tChild;
    Bool overlap;

    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + 
                                    wBorderWidth(pParent);
    if (dx > 32767) dx = 32767;
    borderSize.x2 = dx;
    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + 
                                    wBorderWidth(pParent);
    if (dy > 32767) dy = 32767;
    borderSize.y2 = dy;
  
    oldVis = tParent->visibility;
    switch (RECT_IN_REGION( pScreen, universe, &borderSize)) {
      case rgnIN:
          newVis = VisibilityUnobscured;
          break;
      case rgnPART:
          newVis = VisibilityPartiallyObscured;
#ifdef SHAPE
          {
            RegionPtr   pBounding;

            if ((pBounding = wBoundingShape (pParent))) {
                switch (miShapedWindowIn (pScreen, universe, pBounding,
                                    &borderSize,
                                    pParent->drawable.x,
                                    pParent->drawable.y))
                {
                case rgnIN:
                  newVis = VisibilityUnobscured;
                  break;
                case rgnOUT:
                  newVis = VisibilityFullyObscured;
                  break;
                }
            }
          }
#endif
          break;
      default:
          newVis = VisibilityFullyObscured;
          break;
    }
    tParent->visibility = newVis;

    dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x;
    dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y;

    switch (kind) {
    case VTMap:
    case VTStack:
    case VTUnmap:
      break;
    case VTMove:
      if ((oldVis == newVis) &&
          ((oldVis == VisibilityFullyObscured) ||
           (oldVis == VisibilityUnobscured)))
      {
          tChild = tParent;
          while (1) {
            if (tChild->pWin->viewable) {
                if (tChild->visibility != VisibilityFullyObscured) {
                  REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy);
                  REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy);
            
                  tChild->pWin->drawable.serialNumber = 
                                           NEXT_SERIAL_NUMBER;
                        if (pScreen->ClipNotify)
                            (* pScreen->ClipNotify) (tChild->pWin, dx, dy);
                }
                if (tChild->valdata) {
                  REGION_NULL(pScreen, &tChild->valdata->borderExposed);
                  if (HasParentRelativeBorder(tChild->pWin)){
                      REGION_SUBTRACT(pScreen,
                               &tChild->valdata->borderExposed,
                               &tChild->borderClip,
                               &tChild->pWin->winSize);
                  }
                  REGION_NULL(pScreen, &tChild->valdata->exposed);
                }
                if (tChild->firstChild) {
                  tChild = tChild->firstChild;
                  continue;
                }
            }
            while (!tChild->nextSib && (tChild != tParent))
                tChild = tChild->parent;
            if (tChild == tParent)
                break;
            tChild = tChild->nextSib;
          }
          return;
      }
      /* fall through */
    default:
      if (dx || dy)  {
          REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy);
          REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy);
      } 
      break;
    case VTBroken:
      REGION_EMPTY (pScreen, &tParent->borderClip);
      REGION_EMPTY (pScreen, &tParent->clipList);
      break;
    }

    borderVisible = tParent->valdata->borderVisible;
    REGION_NULL(pScreen, &tParent->valdata->borderExposed);
    REGION_NULL(pScreen, &tParent->valdata->exposed);

    if (HasBorder (pParent)) {
      if (borderVisible) {
          REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
          REGION_DESTROY( pScreen, borderVisible);
      } else
          REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip);

      if (HasParentRelativeBorder(pParent) && (dx || dy))
          REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
                          universe, &pParent->winSize);
      else
          REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
                         exposed, &pParent->winSize);

      REGION_COPY( pScreen, &tParent->borderClip, universe);    
      REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
    }
    else
      REGION_COPY( pScreen, &tParent->borderClip, universe);

    if ((tChild = tParent->firstChild) && pParent->mapped) {
      REGION_NULL(pScreen, &childUniverse);
      REGION_NULL(pScreen, &childUnion);

      for (; tChild; tChild = tChild->nextSib) {
          if (tChild->pWin->viewable)
            REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize);
      }

      REGION_VALIDATE( pScreen, &childUnion, &overlap);

      for (tChild = tParent->firstChild;
           tChild;
           tChild = tChild->nextSib)
      {
          if (tChild->pWin->viewable) {
            if (tChild->valdata) {
                REGION_INTERSECT( pScreen, &childUniverse, universe,
                                  &tChild->pWin->borderSize);
                miOverlayComputeClips (tChild->pWin, &childUniverse, 
                                    kind, exposed);
            }
            if (overlap)
                REGION_SUBTRACT( pScreen, universe, universe,
                                &tChild->pWin->borderSize);
          }
      }
      if (!overlap)
          REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
      REGION_UNINIT( pScreen, &childUnion);
      REGION_UNINIT( pScreen, &childUniverse);
    } 

    if (oldVis == VisibilityFullyObscured ||
      oldVis == VisibilityNotViewable)
    {
      REGION_COPY( pScreen, &tParent->valdata->exposed, universe);
    }
    else if (newVis != VisibilityFullyObscured &&
           newVis != VisibilityNotViewable)
    {
      REGION_SUBTRACT( pScreen, &tParent->valdata->exposed,
                         universe, &tParent->clipList);
    }
    
    /* HACK ALERT - copying contents of regions, instead of regions */
    {
      RegionRec   tmp;

      tmp = tParent->clipList;
      tParent->clipList = *universe;
      *universe = tmp;
    }

    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;

    if (pScreen->ClipNotify)
        (* pScreen->ClipNotify) (pParent, dx, dy);
}


static void 
miOverlayMarkWindow(WindowPtr pWin)
{
    miOverlayTreePtr pTree = NULL;
    WindowPtr pChild, pGrandChild;
   
    miMarkWindow(pWin);

    /* look for UnmapValdata among immediate children */

    if(!(pChild = pWin->firstChild)) return;

    for( ; pChild; pChild = pChild->nextSib) {
      if(pChild->valdata == UnmapValData) {
          if(IN_UNDERLAY(pChild)) {
            pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
            pTree->valdata = (miOverlayValDataPtr)UnmapValData; 
            continue;
          } else {      
              if(!(pGrandChild = pChild->firstChild))
               continue;

            while(1) {
                if(IN_UNDERLAY(pGrandChild)) {
                  pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild);
                  pTree->valdata = (miOverlayValDataPtr)UnmapValData; 
                } else if(pGrandChild->firstChild) {  
                  pGrandChild = pGrandChild->firstChild;
                  continue;
                }

                while(!pGrandChild->nextSib && (pGrandChild != pChild))
                  pGrandChild = pGrandChild->parent;

                if(pChild == pGrandChild) break;
            
                pGrandChild = pGrandChild->nextSib;
            }
          }
        }
    }

    if(pTree) {
      MARK_UNDERLAY(pTree->parent->pWin);
      MIOVERLAY_GET_SCREEN_PRIVATE(
            pWin->drawable.pScreen)->underlayMarked = TRUE;
    }
}

static void
miOverlayMarkUnrealizedWindow(
    WindowPtr pChild,
    WindowPtr pWin,
    Bool fromConfigure
){
    if ((pChild != pWin) || fromConfigure) {
      miOverlayTreePtr pTree;

        REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList);
        if (pChild->drawable.pScreen->ClipNotify)
            (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0);
        REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip);
      if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
          if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) {
            REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList);
            REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip);
          }
      }
    }
}


static int 
miOverlayValidateTree(
    WindowPtr pParent,
    WindowPtr pChild,   /* first child effected */
    VTKind    kind
){
    ScreenPtr pScreen = pParent->drawable.pScreen;
    miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    RegionRec totalClip, childClip, exposed;
    miOverlayTreePtr tParent, tChild, tWin;
    Bool overlap;
    WindowPtr newParent;

    if(!pPriv->underlayMarked)
      goto SKIP_UNDERLAY;

    if (!pChild) pChild = pParent->firstChild;

    REGION_NULL(pScreen, &totalClip);
    REGION_NULL(pScreen, &childClip);
    REGION_NULL(pScreen, &exposed);

    newParent = pParent;

    while(IN_OVERLAY(newParent))
      newParent = newParent->parent;

    tParent = MIOVERLAY_GET_WINDOW_TREE(newParent);

    if(IN_UNDERLAY(pChild))
      tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
    else
      tChild = tParent->firstChild;

    if (REGION_BROKEN (pScreen, &tParent->clipList) &&
        !REGION_BROKEN (pScreen, &tParent->borderClip))
    {
      kind = VTBroken;
      REGION_COPY (pScreen, &totalClip, &tParent->borderClip);
      REGION_INTERSECT (pScreen, &totalClip, &totalClip,
                                     &tParent->pWin->winSize);
        
        for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) {
            if (tWin->pWin->viewable)
                REGION_SUBTRACT (pScreen, &totalClip, &totalClip, 
                              &tWin->pWin->borderSize);
        }        
        REGION_EMPTY (pScreen, &tParent->clipList);
    } else {
      for(tWin = tChild; tWin; tWin = tWin->nextSib) {
          if(tWin->valdata)
            REGION_APPEND(pScreen, &totalClip, &tWin->borderClip);
      }
      REGION_VALIDATE(pScreen, &totalClip, &overlap);
    }

    if(kind != VTStack)
      REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList);
      
    for(tWin = tChild; tWin; tWin = tWin->nextSib) {
      if(tWin->valdata) {
          if(tWin->pWin->viewable) {
            REGION_INTERSECT(pScreen, &childClip, &totalClip,
                              &tWin->pWin->borderSize);
            miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed);
            REGION_SUBTRACT(pScreen, &totalClip, &totalClip,
                              &tWin->pWin->borderSize);
          } else {  /* Means we are unmapping */
                REGION_EMPTY(pScreen, &tWin->clipList);
                REGION_EMPTY( pScreen, &tWin->borderClip);
            tWin->valdata = NULL;
          }
      }
    }

    REGION_UNINIT(pScreen, &childClip);

    if(!((*pPriv->InOverlay)(newParent))) {
      REGION_NULL(pScreen, &tParent->valdata->exposed);
      REGION_NULL(pScreen, &tParent->valdata->borderExposed);
    }

    switch (kind) {
    case VTStack:
      break;
    default:
      if(!((*pPriv->InOverlay)(newParent))) 
          REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip, 
                                    &tParent->clipList);
      /* fall through */
    case VTMap:
      REGION_COPY( pScreen, &tParent->clipList, &totalClip);
      if(!((*pPriv->InOverlay)(newParent))) 
          newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
      break;
    }

    REGION_UNINIT( pScreen, &totalClip);
    REGION_UNINIT( pScreen, &exposed);

SKIP_UNDERLAY:

    miValidateTree(pParent, pChild, kind);

    return 1;
}


static void
miOverlayHandleExposures(WindowPtr pWin)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    WindowPtr pChild;
    ValidatePtr val;
    void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr);

    WindowExposures = pWin->drawable.pScreen->WindowExposures;
    if(pPriv->underlayMarked) {
      miOverlayTreePtr pTree;
      miOverlayValDataPtr mival;

      pChild = pWin;
      while(IN_OVERLAY(pChild))
          pChild = pChild->parent;

      pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);

      while (1) {
          if((mival = pTree->valdata)) {
            if(!((*pPriv->InOverlay)(pTree->pWin))) {
                if (REGION_NOTEMPTY(pScreen, &mival->borderExposed))
                  (*pWin->drawable.pScreen->PaintWindowBorder)(
                        pTree->pWin, &mival->borderExposed, PW_BORDER);
                REGION_UNINIT(pScreen, &mival->borderExposed);

                (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion);
                REGION_UNINIT(pScreen, &mival->exposed);
            }
            xfree(mival);
            pTree->valdata = NULL;
            if (pTree->firstChild) {
                pTree = pTree->firstChild;
                continue;
            }
          }
          while (!pTree->nextSib && (pTree->pWin != pChild))
            pTree = pTree->parent;
          if (pTree->pWin == pChild)
            break;
          pTree = pTree->nextSib;
        }
      pPriv->underlayMarked = FALSE;
    }

    pChild = pWin;
    while (1) {
      if ( (val = pChild->valdata) ) {
          if(!((*pPriv->InOverlay)(pChild))) {
            REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed,
                  &val->after.borderExposed);

            if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) {
               (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))(
                        pScreen, 
                        REGION_NUM_RECTS(&val->after.exposed),
                        REGION_RECTS(&val->after.exposed));
            }
          } else {
            if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed))
                (*pChild->drawable.pScreen->PaintWindowBorder)(pChild,
                                        &val->after.borderExposed,
                                        PW_BORDER);
            (*WindowExposures)(pChild, &val->after.exposed, NullRegion);
          }
          REGION_UNINIT(pScreen, &val->after.borderExposed);
          REGION_UNINIT(pScreen, &val->after.exposed);
          xfree(val);
          pChild->valdata = (ValidatePtr)NULL;
          if (pChild->firstChild)
          {
            pChild = pChild->firstChild;
            continue;
          }
      }
      while (!pChild->nextSib && (pChild != pWin))
          pChild = pChild->parent;
      if (pChild == pWin)
          break;
      pChild = pChild->nextSib;
    }
}


static void
miOverlayMoveWindow(
    WindowPtr pWin,
    int x,
    int y,
    WindowPtr pNextSib,
    VTKind kind
){
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    WindowPtr pParent, windowToValidate;
    Bool WasViewable = (Bool)(pWin->viewable);
    short bw;
    RegionRec overReg, underReg;
    DDXPointRec oldpt;
#ifdef DO_SAVE_UNDERS
    Bool dosave = FALSE;
#endif

    if (!(pParent = pWin->parent))
       return ;
    bw = wBorderWidth (pWin);

    oldpt.x = pWin->drawable.x;
    oldpt.y = pWin->drawable.y;
    if (WasViewable) {
      REGION_NULL(pScreen, &overReg);
      REGION_NULL(pScreen, &underReg);
      if(pTree) {
          REGION_COPY(pScreen, &overReg, &pWin->borderClip);
          REGION_COPY(pScreen, &underReg, &pTree->borderClip);
        } else {
          REGION_COPY(pScreen, &overReg, &pWin->borderClip);
          CollectUnderlayChildrenRegions(pWin, &underReg);
      }
      (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
    }
    pWin->origin.x = x + (int)bw;
    pWin->origin.y = y + (int)bw;
    x = pWin->drawable.x = pParent->drawable.x + x + (int)bw;
    y = pWin->drawable.y = pParent->drawable.y + y + (int)bw;

    SetWinSize (pWin);
    SetBorderSize (pWin);

    (*pScreen->PositionWindow)(pWin, x, y);

    windowToValidate = MoveWindowInStack(pWin, pNextSib);

    ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);

    if (WasViewable) {
      miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
      (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL);

#ifdef DO_SAVE_UNDERS
      if (DO_SAVE_UNDERS(pWin))
          dosave = (*pScreen->ChangeSaveUnder)(pWin, windowToValidate);
#endif /* DO_SAVE_UNDERS */

      (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind);
      if(REGION_NOTEMPTY(pScreen, &underReg)) {
          pPriv->copyUnderlay = TRUE;
          (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg);
      }
      REGION_UNINIT(pScreen, &underReg);
      if(REGION_NOTEMPTY(pScreen, &overReg)) {
          pPriv->copyUnderlay = FALSE;
          (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg);
      }
      REGION_UNINIT(pScreen, &overReg);
      (*pScreen->HandleExposures)(pWin->parent);

#ifdef DO_SAVE_UNDERS
      if (dosave)
          (*pScreen->PostChangeSaveUnder)(pWin, windowToValidate);
#endif /* DO_SAVE_UNDERS */
      if (pScreen->PostValidateTree)
          (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind);
    }
    if (pWin->realized)
      WindowsRestructured ();
}

#ifndef RECTLIMIT
#define RECTLIMIT 25
#endif

static void 
miOverlayWindowExposures(
    WindowPtr pWin,
    register RegionPtr prgn,
    RegionPtr other_exposed
){
    RegionPtr   exposures = prgn;
    ScreenPtr pScreen = pWin->drawable.pScreen;

    if (pWin->backStorage && prgn)
      exposures = (*pScreen->RestoreAreas)(pWin, prgn);
    if ((prgn && !REGION_NIL(prgn)) || 
      (exposures && !REGION_NIL(exposures)) || other_exposed)
    {
      RegionRec   expRec;
      int       clientInterested;

      clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) &
                      ExposureMask;
      if (other_exposed) {
          if (exposures) {
            REGION_UNION(pScreen, other_exposed, exposures, other_exposed);
            if (exposures != prgn)
                REGION_DESTROY(pScreen, exposures);
          }
          exposures = other_exposed;
      }
      if (clientInterested && exposures && 
         (REGION_NUM_RECTS(exposures) > RECTLIMIT))
      {
            miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
          BoxRec box;

          box = *REGION_EXTENTS(pScreen, exposures);
          if (exposures == prgn) {
            exposures = &expRec;
            REGION_INIT(pScreen, exposures, &box, 1);
            REGION_RESET(pScreen, prgn, &box);
          } else {
            REGION_RESET(pScreen, exposures, &box);
            REGION_UNION(pScreen, prgn, prgn, exposures);
          }
          /* This is the only reason why we are replacing mi's version
               of this file */
          
          if(!((*pPriv->InOverlay)(pWin))) {
            miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
            REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList);
          } else
            REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList);

          /* need to clear out new areas of backing store, too */
          if (pWin->backStorage)
            (void) (*pScreen->ClearBackingStore)(
                                   pWin,
                                   box.x1 - pWin->drawable.x,
                                   box.y1 - pWin->drawable.y,
                                   box.x2 - box.x1,
                                   box.y2 - box.y1,
                                   FALSE);
      }
      if (prgn && !REGION_NIL(prgn))
          (*pScreen->PaintWindowBackground)(
                  pWin, prgn, PW_BACKGROUND);
      if (clientInterested && exposures && !REGION_NIL(exposures))
          miSendExposures(pWin, exposures,
                      pWin->drawable.x, pWin->drawable.y);
      if (exposures == &expRec) {
          REGION_UNINIT(pScreen, exposures);
      } 
      else if (exposures && exposures != prgn && exposures != other_exposed)
          REGION_DESTROY(pScreen, exposures);
      if (prgn)
          REGION_EMPTY(pScreen, prgn);
    }
    else if (exposures && exposures != prgn)
      REGION_DESTROY(pScreen, exposures);
}


typedef struct {
   RegionPtr over;
   RegionPtr under;
} miOverlayTwoRegions; 

static int
miOverlayRecomputeExposures (
    WindowPtr     pWin,
    pointer value 
){
    register ScreenPtr pScreen;
    miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value;
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);

    /* This prevents warning about pScreen not being used. */
    pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen;

    if (pWin->valdata) {
      /*
       * compute exposed regions of this window
       */
      REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
                  &pWin->clipList, pValid->over);
      /*
       * compute exposed regions of the border
       */
      REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
                       &pWin->borderClip, &pWin->winSize);
      REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
                       &pWin->valdata->after.borderExposed, pValid->over);
    } 

    if(pTree && pTree->valdata) {
      REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
                  &pTree->clipList, pValid->under);
      REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
                       &pTree->borderClip, &pWin->winSize);
      REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
                       &pTree->valdata->borderExposed, pValid->under);    
    } else if (!pWin->valdata)
      return WT_NOMATCH;

    return WT_WALKCHILDREN;
}

static void
miOverlayResizeWindow(
    WindowPtr pWin,
    int x, int y,
    unsigned int w, unsigned int h,
    WindowPtr pSib
){
    ScreenPtr pScreen = pWin->drawable.pScreen;
    WindowPtr pParent;
    miOverlayTreePtr tChild, pTree;
    Bool WasViewable = (Bool)(pWin->viewable);
    unsigned short width = pWin->drawable.width;
    unsigned short height = pWin->drawable.height;
    short oldx = pWin->drawable.x;
    short oldy = pWin->drawable.y;
    int bw = wBorderWidth (pWin);
    short dw, dh;
    DDXPointRec oldpt;
    RegionPtr oldRegion = NULL, oldRegion2 = NULL;
    WindowPtr pFirstChange;
    register WindowPtr pChild;
    RegionPtr     gravitate[StaticGravity + 1];
    RegionPtr     gravitate2[StaticGravity + 1];
    register unsigned g;
    int           nx, ny;           /* destination x,y */
    int           newx, newy; /* new inner window position */
    RegionPtr     pRegion = NULL;
    RegionPtr     destClip, destClip2;
    RegionPtr     oldWinClip = NULL, oldWinClip2 = NULL;    
    RegionPtr     borderVisible = NullRegion; 
    RegionPtr     borderVisible2 = NullRegion; 
    RegionPtr     bsExposed = NullRegion;     /* backing store exposures */
    Bool    shrunk = FALSE; /* shrunk in an inner dimension */
    Bool    moved = FALSE;    /* window position changed */
#ifdef DO_SAVE_UNDERS
    Bool    dosave = FALSE;
#endif
    Bool    doUnderlay;

    /* if this is a root window, can't be resized */
    if (!(pParent = pWin->parent))
      return ;

    pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    doUnderlay = ((pTree) || HasUnderlayChildren(pWin));
    newx = pParent->drawable.x + x + bw;
    newy = pParent->drawable.y + y + bw;
    if (WasViewable)
    {
      /*
       * save the visible region of the window
       */
      oldRegion = REGION_CREATE(pScreen, NullBox, 1);
      REGION_COPY(pScreen, oldRegion, &pWin->winSize);
      if(doUnderlay) {
          oldRegion2 = REGION_CREATE(pScreen, NullBox, 1);
          REGION_COPY(pScreen, oldRegion2, &pWin->winSize);
      }

      /*
       * categorize child windows into regions to be moved
       */
      for (g = 0; g <= StaticGravity; g++)
          gravitate[g] = gravitate2[g] = NULL;
      for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
          g = pChild->winGravity;
          if (g != UnmapGravity) {
            if (!gravitate[g])
                gravitate[g] = REGION_CREATE(pScreen, NullBox, 1);
            REGION_UNION(pScreen, gravitate[g],
                           gravitate[g], &pChild->borderClip);
            
            if(doUnderlay) {
                if (!gravitate2[g])
                  gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0);
            
                if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
                    REGION_UNION(pScreen, gravitate2[g],
                           gravitate2[g], &tChild->borderClip);
                } else 
                  CollectUnderlayChildrenRegions(pChild, gravitate2[g]);
            }
          } else {
            UnmapWindow(pChild, TRUE);
          }
      }
      (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);


      oldWinClip = oldWinClip2 = NULL;
      if (pWin->bitGravity != ForgetGravity) {
          oldWinClip = REGION_CREATE(pScreen, NullBox, 1);
          REGION_COPY(pScreen, oldWinClip, &pWin->clipList);
          if(pTree) {
            oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1);
            REGION_COPY(pScreen, oldWinClip2, &pTree->clipList);
          }
      }
      /*
       * if the window is changing size, borderExposed
       * can't be computed correctly without some help.
       */
      if (pWin->drawable.height > h || pWin->drawable.width > w)
          shrunk = TRUE;

      if (newx != oldx || newy != oldy)
          moved = TRUE;

      if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
          HasBorder (pWin))
      {
          borderVisible = REGION_CREATE(pScreen, NullBox, 1);
          if(pTree)
            borderVisible2 = REGION_CREATE(pScreen, NullBox, 1);
          /* for tiled borders, we punt and draw the whole thing */
          if (pWin->borderIsPixel || !moved)
          {
            if (shrunk || moved)
                REGION_SUBTRACT(pScreen, borderVisible,
                                &pWin->borderClip,
                                &pWin->winSize);
            else
                REGION_COPY(pScreen, borderVisible,
                                  &pWin->borderClip);
            if(pTree) {
                if (shrunk || moved)
                  REGION_SUBTRACT(pScreen, borderVisible,
                                &pTree->borderClip,
                                &pWin->winSize);
                else
                  REGION_COPY(pScreen, borderVisible,
                                  &pTree->borderClip);
            }
          }
      }
    }
    pWin->origin.x = x + bw;
    pWin->origin.y = y + bw;
    pWin->drawable.height = h;
    pWin->drawable.width = w;

    x = pWin->drawable.x = newx;
    y = pWin->drawable.y = newy;

    SetWinSize (pWin);
    SetBorderSize (pWin);

    dw = (int)w - (int)width;
    dh = (int)h - (int)height;
    ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);

    /* let the hardware adjust background and border pixmaps, if any */
    (*pScreen->PositionWindow)(pWin, x, y);

    pFirstChange = MoveWindowInStack(pWin, pSib);

    if (WasViewable) {
      pRegion = REGION_CREATE(pScreen, NullBox, 1);
      if (pWin->backStorage)
          REGION_COPY(pScreen, pRegion, &pWin->clipList);

      (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL);

      pWin->valdata->before.resized = TRUE;
      pWin->valdata->before.borderVisible = borderVisible;
      if(pTree)
          pTree->valdata->borderVisible = borderVisible2;

#ifdef DO_SAVE_UNDERS
      if (DO_SAVE_UNDERS(pWin))
          dosave = (*pScreen->ChangeSaveUnder)(pWin, pFirstChange);
#endif /* DO_SAVE_UNDERS */

      (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther);
      /*
       * the entire window is trashed unless bitGravity
       * recovers portions of it
       */
      REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList);
      if(pTree)
          REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList);
    }

    GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);

    if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
      if (!WasViewable)
          pRegion = &pWin->clipList; /* a convenient empty region */
      if (pWin->bitGravity == ForgetGravity)
          bsExposed = (*pScreen->TranslateBackingStore)
                        (pWin, 0, 0, NullRegion, oldx, oldy);
      else
          bsExposed = (*pScreen->TranslateBackingStore)
                       (pWin, nx - x, ny - y, pRegion, oldx, oldy);
    }

    if (WasViewable) {
      miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
      miOverlayTwoRegions TwoRegions;

      /* avoid the border */
      if (HasBorder (pWin)) {
          int     offx, offy, dx, dy;

          /* kruft to avoid double translates for each gravity */
          offx = 0;
          offy = 0;
          for (g = 0; g <= StaticGravity; g++) {
            if (!gravitate[g] && !gravitate2[g])
                continue;

            /* align winSize to gravitate[g].
             * winSize is in new coordinates,
             * gravitate[g] is still in old coordinates */
            GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
            
            dx = (oldx - nx) - offx;
            dy = (oldy - ny) - offy;
            if (dx || dy) {
                REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy);
                offx += dx;
                offy += dy;
            }
            if(gravitate[g])
                REGION_INTERSECT(pScreen, gravitate[g], gravitate[g],
                         &pWin->winSize);
            if(gravitate2[g])
                REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g],
                         &pWin->winSize);
          }
          /* get winSize back where it belongs */
          if (offx || offy)
            REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy);
      }
      /*
       * add screen bits to the appropriate bucket
       */

      if (oldWinClip2)
      {
          REGION_COPY(pScreen, pRegion, oldWinClip2);
          REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
          REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList);

          for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
            if (gravitate2[g])
                REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2,
                              gravitate2[g]);
          }
          REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny);
          g = pWin->bitGravity;
          if (!gravitate2[g])
            gravitate2[g] = oldWinClip2;
          else {
            REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2);
            REGION_DESTROY(pScreen, oldWinClip2);
          }
      }

      if (oldWinClip)
      {
          /*
           * clip to new clipList
           */
          REGION_COPY(pScreen, pRegion, oldWinClip);
          REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
          REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList);
          /*
           * don't step on any gravity bits which will be copied after this
           * region.    Note -- this assumes that the regions will be copied
           * in gravity order.
           */
          for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
            if (gravitate[g])
                REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip,
                              gravitate[g]);
          }
          REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny);
          g = pWin->bitGravity;
          if (!gravitate[g])
            gravitate[g] = oldWinClip;
          else {
            REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip);
            REGION_DESTROY(pScreen, oldWinClip);
          }
      }

      /*
       * move the bits on the screen
       */

      destClip = destClip2 = NULL;

      for (g = 0; g <= StaticGravity; g++) {
          if (!gravitate[g] && !gravitate2[g])
            continue;

          GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);

          oldpt.x = oldx + (x - nx);
          oldpt.y = oldy + (y - ny);

          /* Note that gravitate[g] is *translated* by CopyWindow */

          /* only copy the remaining useful bits */

          if(gravitate[g])
            REGION_INTERSECT(pScreen, gravitate[g], 
                         gravitate[g], oldRegion);
          if(gravitate2[g])
            REGION_INTERSECT(pScreen, gravitate2[g], 
                         gravitate2[g], oldRegion2);

          /* clip to not overwrite already copied areas */

          if (destClip && gravitate[g]) {
            REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y);
            REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip);
            REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y);
          }
          if (destClip2 && gravitate2[g]) {
            REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y);
            REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2);
            REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y);
          }

          /* and move those bits */

          if (oldpt.x != x || oldpt.y != y) {
            if(gravitate2[g]) {
                pPriv->copyUnderlay = TRUE;
                (*pWin->drawable.pScreen->CopyWindow)(
                                    pWin, oldpt, gravitate2[g]);
            }
            if(gravitate[g]) {
                pPriv->copyUnderlay = FALSE;
                (*pWin->drawable.pScreen->CopyWindow)(
                                    pWin, oldpt, gravitate[g]);
            }
          }

          /* remove any overwritten bits from the remaining useful bits */

          if(gravitate[g])
            REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]);
          if(gravitate2[g])
            REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]);

          /*
           * recompute exposed regions of child windows
           */
      

          for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
            if (pChild->winGravity != g)
                continue;

            TwoRegions.over = gravitate[g];
            TwoRegions.under = gravitate2[g];

            TraverseTree (pChild, miOverlayRecomputeExposures, 
                              (pointer)(&TwoRegions));
          }

          /*
           * remove the successfully copied regions of the
           * window from its exposed region
           */

          if (g == pWin->bitGravity) {
            if(gravitate[g])
                REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
                        &pWin->valdata->after.exposed, gravitate[g]);
            if(gravitate2[g] && pTree) 
                REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
                        &pTree->valdata->exposed, gravitate2[g]);
          }
          if(gravitate[g]) {
            if (!destClip)
                destClip = gravitate[g];
            else {
                REGION_UNION(pScreen, destClip, destClip, gravitate[g]);
                REGION_DESTROY(pScreen, gravitate[g]);
            }
          }
          if(gravitate2[g]) {
            if (!destClip2)
                destClip2 = gravitate2[g];
            else {
                REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]);
                REGION_DESTROY(pScreen, gravitate2[g]);
            }
          }
      }

      REGION_DESTROY(pScreen, pRegion);
      REGION_DESTROY(pScreen, oldRegion);
      if(doUnderlay)
          REGION_DESTROY(pScreen, oldRegion2);
      if (destClip)
          REGION_DESTROY(pScreen, destClip);
      if (destClip2)
          REGION_DESTROY(pScreen, destClip2);
      if (bsExposed) {
          RegionPtr     valExposed = NullRegion;

          if (pWin->valdata)
            valExposed = &pWin->valdata->after.exposed;
          (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
          if (valExposed)
            REGION_EMPTY(pScreen, valExposed);
          REGION_DESTROY(pScreen, bsExposed);
      }
      (*pScreen->HandleExposures)(pWin->parent);
#ifdef DO_SAVE_UNDERS
      if (dosave)
          (*pScreen->PostChangeSaveUnder)(pWin, pFirstChange);
#endif /* DO_SAVE_UNDERS */
      if (pScreen->PostValidateTree)
          (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther);
    }
    else if (bsExposed) {
      (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed);
      REGION_DESTROY(pScreen, bsExposed);
    }
    if (pWin->realized)
      WindowsRestructured ();
}


#ifdef SHAPE
static void
miOverlaySetShape(WindowPtr pWin)
{
    Bool    WasViewable = (Bool)(pWin->viewable);
    ScreenPtr     pScreen = pWin->drawable.pScreen;
    RegionPtr     pOldClip = NULL, bsExposed;
#ifdef DO_SAVE_UNDERS
    Bool    dosave = FALSE;
#endif

    if (WasViewable) {
      (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);

      if (HasBorder (pWin)) {
          RegionPtr borderVisible;

          borderVisible = REGION_CREATE(pScreen, NullBox, 1);
          REGION_SUBTRACT(pScreen, borderVisible,
                              &pWin->borderClip, &pWin->winSize);
          pWin->valdata->before.borderVisible = borderVisible;
          pWin->valdata->before.resized = TRUE;
          if(IN_UNDERLAY(pWin)) {
            miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
            RegionPtr borderVisible2;

            borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
            REGION_SUBTRACT(pScreen, borderVisible2,
                              &pTree->borderClip, &pWin->winSize);
            pTree->valdata->borderVisible = borderVisible2;
          }
      }
    }

    SetWinSize (pWin);
    SetBorderSize (pWin);

    ResizeChildrenWinSize(pWin, 0, 0, 0, 0);

    if (WasViewable) {
      if (pWin->backStorage) {
          pOldClip = REGION_CREATE(pScreen, NullBox, 1);
          REGION_COPY(pScreen, pOldClip, &pWin->clipList);
      }

      (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);

#ifdef DO_SAVE_UNDERS
      if (DO_SAVE_UNDERS(pWin))
          dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin);
#endif /* DO_SAVE_UNDERS */

      (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther);
    }

    if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
      if (!WasViewable)
          pOldClip = &pWin->clipList; /* a convenient empty region */
      bsExposed = (*pScreen->TranslateBackingStore)
                       (pWin, 0, 0, pOldClip,
                        pWin->drawable.x, pWin->drawable.y);
      if (WasViewable)
          REGION_DESTROY(pScreen, pOldClip);
      if (bsExposed)
      {
          RegionPtr     valExposed = NullRegion;
    
          if (pWin->valdata)
            valExposed = &pWin->valdata->after.exposed;
          (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
          if (valExposed)
            REGION_EMPTY(pScreen, valExposed);
          REGION_DESTROY(pScreen, bsExposed);
      }
    }
    if (WasViewable) {
      (*pScreen->HandleExposures)(pWin->parent);
#ifdef DO_SAVE_UNDERS
      if (dosave)
          (*pScreen->PostChangeSaveUnder)(pWin, pWin);
#endif /* DO_SAVE_UNDERS */
      if (pScreen->PostValidateTree)
          (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther);
    }
    if (pWin->realized)
      WindowsRestructured ();
    CheckCursorConfinement(pWin);
}
#endif



static void
miOverlayChangeBorderWidth(
    WindowPtr pWin,
    unsigned int width
){
    int oldwidth;
    register ScreenPtr pScreen;
    Bool WasViewable = (Bool)(pWin->viewable);
    Bool HadBorder;
#ifdef DO_SAVE_UNDERS
    Bool    dosave = FALSE;
#endif

    oldwidth = wBorderWidth (pWin);
    if (oldwidth == width)
      return;
    HadBorder = HasBorder(pWin);
    pScreen = pWin->drawable.pScreen;
    if (WasViewable && (width < oldwidth))
      (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);

    pWin->borderWidth = width;
    SetBorderSize (pWin);

    if (WasViewable) {
      if (width > oldwidth) {
          (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);

          if (HadBorder) {
            RegionPtr   borderVisible;
            borderVisible = REGION_CREATE(pScreen, NULL, 1);
            REGION_SUBTRACT(pScreen, borderVisible,
                              &pWin->borderClip, &pWin->winSize);
            pWin->valdata->before.borderVisible = borderVisible;
            if(IN_UNDERLAY(pWin)) {
                miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
                RegionPtr borderVisible2;

                borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
                REGION_SUBTRACT(pScreen, borderVisible2,
                              &pTree->borderClip, &pWin->winSize);
                pTree->valdata->borderVisible = borderVisible2;
            }
          }
      }
#ifdef DO_SAVE_UNDERS
      if (DO_SAVE_UNDERS(pWin))
          dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib);
#endif /* DO_SAVE_UNDERS */
      (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther);
      (*pScreen->HandleExposures)(pWin->parent);

#ifdef DO_SAVE_UNDERS
      if (dosave)
          (*pScreen->PostChangeSaveUnder)(pWin, pWin->nextSib);
#endif /* DO_SAVE_UNDERS */
      if (pScreen->PostValidateTree)
          (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther);
    }
    if (pWin->realized)
      WindowsRestructured ();
}

/*  We need this as an addition since the xf86 common code doesn't
    know about the second tree which is static to this file.  */

void
miOverlaySetRootClip(ScreenPtr pScreen, Bool enable)
{
    WindowPtr pRoot = WindowTable[pScreen->myNum];
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot);

    MARK_UNDERLAY(pRoot);

    if(enable) {
      BoxRec box;
      
      box.x1 = 0;
      box.y1 = 0;
      box.x2 = pScreen->width;
      box.y2 = pScreen->height;

      REGION_RESET(pScreen, &pTree->borderClip, &box);
    } else 
      REGION_EMPTY(pScreen, &pTree->borderClip);

    REGION_BREAK(pScreen, &pTree->clipList);
}

static void 
miOverlayClearToBackground(
    WindowPtr pWin,
    int x, int y,
    int w, int h,
    Bool generateExposures
)
{
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    BoxRec box;
    RegionRec reg;
    RegionPtr pBSReg = NullRegion;
    ScreenPtr pScreen = pWin->drawable.pScreen;
    miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
    RegionPtr clipList;
    BoxPtr  extents;
    int     x1, y1, x2, y2;

    x1 = pWin->drawable.x + x;
    y1 = pWin->drawable.y + y;
    if (w)
        x2 = x1 + (int) w;
    else
        x2 = x1 + (int) pWin->drawable.width - (int) x;
    if (h)
        y2 = y1 + h;    
    else
        y2 = y1 + (int) pWin->drawable.height - (int) y;

    clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList :
                                                 &pTree->clipList;

    extents = REGION_EXTENTS(pScreen, clipList);
    
    if (x1 < extents->x1) x1 = extents->x1;
    if (x2 > extents->x2) x2 = extents->x2;
    if (y1 < extents->y1) y1 = extents->y1;
    if (y2 > extents->y2) y2 = extents->y2;

    if (x2 <= x1 || y2 <= y1) 
        x2 = x1 = y2 = y1 = 0;

    box.x1 = x1; box.x2 = x2;
    box.y1 = y1; box.y2 = y2;

    REGION_INIT(pScreen, &reg, &box, 1);
    if (pWin->backStorage) {
        pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h,
                                                 generateExposures);
    }

    REGION_INTERSECT(pScreen, &reg, &reg, clipList);
    if (generateExposures)
        (*pScreen->WindowExposures)(pWin, &reg, pBSReg);
    else if (pWin->backgroundState != None)
        (*pScreen->PaintWindowBackground)(pWin, &reg, PW_BACKGROUND);
    REGION_UNINIT(pScreen, &reg);
    if (pBSReg)
        REGION_DESTROY(pScreen, pBSReg);
}


/****************************************************************/

/* not used */
Bool
miOverlayGetPrivateClips(
    WindowPtr pWin,
    RegionPtr *borderClip,
    RegionPtr *clipList
){
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
      
    if(pTree) {
      *borderClip = &(pTree->borderClip);
      *clipList = &(pTree->clipList);
      return TRUE;
    }

    *borderClip = *clipList = NULL;

    return FALSE;
}

void 
miOverlaySetTransFunction (
   ScreenPtr pScreen, 
   miOverlayTransFunc transFunc
){
    MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc;
}

Bool 
miOverlayCopyUnderlay(ScreenPtr pScreen)
{
    return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay;
}

void
miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin)
{
    ScreenPtr       pScreen = pGC->pScreen;
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    RegionPtr       pregWin;
    Bool            freeTmpClip, freeCompClip;

    if(!pTree) {
      miComputeCompositeClip(pGC, &pWin->drawable);
      return;
    }

    if (pGC->subWindowMode == IncludeInferiors) {
      pregWin = REGION_CREATE(pScreen, NullBox, 1);
      freeTmpClip = TRUE;
      if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) ||
            !HasSaverWindow (pScreen->myNum))
      {
            REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize);
      }
    } else {
      pregWin = &pTree->clipList;
      freeTmpClip = FALSE;
    }
    freeCompClip = pGC->freeCompClip;
    if (pGC->clientClipType == CT_NONE) {
      if (freeCompClip) 
          REGION_DESTROY(pScreen, pGC->pCompositeClip);
      pGC->pCompositeClip = pregWin;
      pGC->freeCompClip = freeTmpClip;
    } else {
      REGION_TRANSLATE(pScreen, pGC->clientClip,
                        pWin->drawable.x + pGC->clipOrg.x,
                        pWin->drawable.y + pGC->clipOrg.y);

      if (freeCompClip) {
          REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
                                  pregWin, pGC->clientClip);
          if (freeTmpClip)
            REGION_DESTROY(pScreen, pregWin);
      } else if (freeTmpClip) {
          REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip);
          pGC->pCompositeClip = pregWin;
      } else {
          pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0);
          REGION_INTERSECT(pScreen, pGC->pCompositeClip,
                               pregWin, pGC->clientClip);
      }
      pGC->freeCompClip = TRUE;
      REGION_TRANSLATE(pScreen, pGC->clientClip,
                        -(pWin->drawable.x + pGC->clipOrg.x),
                        -(pWin->drawable.y + pGC->clipOrg.y));
    }
}

Bool
miOverlayCollectUnderlayRegions(
    WindowPtr pWin,
    RegionPtr *region
){
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);

    if(pTree) {
      *region = &pTree->borderClip;
      return FALSE;
    }

    *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0);
    
    CollectUnderlayChildrenRegions(pWin, *region);

    return TRUE;
}


static miOverlayTreePtr
DoLeaf(
    WindowPtr pWin, 
    miOverlayTreePtr parent, 
    miOverlayTreePtr prevSib
){
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
    
    pTree->parent = parent;
    pTree->firstChild = NULL;
    pTree->lastChild = NULL;
    pTree->prevSib = prevSib;
    pTree->nextSib = NULL;

    if(prevSib)
      prevSib->nextSib = pTree;

    if(!parent->firstChild)
      parent->firstChild = parent->lastChild = pTree;
    else if(parent->lastChild == prevSib)
      parent->lastChild = pTree;
   
    return pTree;
}

static void 
RebuildTree(WindowPtr pWin)
{
    miOverlayTreePtr parent, prevSib, tChild;
    WindowPtr pChild;

    prevSib = tChild = NULL;

    pWin = pWin->parent;

    while(IN_OVERLAY(pWin))
      pWin = pWin->parent;

    parent = MIOVERLAY_GET_WINDOW_TREE(pWin);

    pChild = pWin->firstChild;
    parent->firstChild = parent->lastChild = NULL;

    while(1) {
      if(IN_UNDERLAY(pChild))
         prevSib = tChild = DoLeaf(pChild, parent, prevSib);

      if(pChild->firstChild) {
          if(IN_UNDERLAY(pChild)) {
            parent = tChild;
            prevSib = NULL;
          }
          pChild = pChild->firstChild;
          continue;
      }

      while(!pChild->nextSib) {
          pChild = pChild->parent;
          if(pChild == pWin) return;
          if(IN_UNDERLAY(pChild)) {
            prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
            parent = tChild->parent;
          }
      }

      pChild = pChild->nextSib;
    }
}


static Bool
HasUnderlayChildren(WindowPtr pWin)
{
    WindowPtr pChild;

    if(!(pChild = pWin->firstChild)) 
      return FALSE;

    while(1) {
      if(IN_UNDERLAY(pChild))
         return TRUE;

      if(pChild->firstChild) {
          pChild = pChild->firstChild;
          continue;
      }

      while(!pChild->nextSib && (pWin != pChild))
          pChild = pChild->parent;

      if(pChild == pWin) break;

      pChild = pChild->nextSib;
    }

    return FALSE;
}


static Bool
CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    WindowPtr pChild;
    miOverlayTreePtr pTree;
    Bool hasUnderlay;

    if(!(pChild = pWin->firstChild)) 
      return FALSE;

    hasUnderlay = FALSE;

    while(1) {
      if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
          REGION_APPEND(pScreen, pReg, &pTree->borderClip);
          hasUnderlay = TRUE;
      } else
      if(pChild->firstChild) {
          pChild = pChild->firstChild;
          continue;
      }

      while(!pChild->nextSib && (pWin != pChild))
          pChild = pChild->parent;

      if(pChild == pWin) break;

      pChild = pChild->nextSib;
    }

    if(hasUnderlay) {
      Bool overlap;
      REGION_VALIDATE(pScreen, pReg, &overlap);
    } 

    return hasUnderlay;
}


static void 
MarkUnderlayWindow(WindowPtr pWin)
{
    miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);

    if(pTree->valdata) return;
    pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec));
    pTree->valdata->oldAbsCorner.x = pWin->drawable.x;
    pTree->valdata->oldAbsCorner.y = pWin->drawable.y;
    pTree->valdata->borderVisible = NullRegion;
}

Generated by  Doxygen 1.6.0   Back to index