/* Copyright 1986, 1989, 1990, 1995 by Abacus Research and
 * Development, Inc.  All rights reserved.
 */

#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_windSize[] =
	    "$Id: windSize.c 63 2004-12-24 18:19:43Z ctm $";
#endif

/* Forward declarations in WindowMgr.h (DO NOT DELETE THIS LINE) */

#include "rsys/common.h"
#include "QuickDraw.h"
#include "CQuickDraw.h"
#include "WindowMgr.h"
#include "EventMgr.h"
#include "OSEvent.h"
#include "ToolboxUtil.h"
#include "MemoryMgr.h"

#include "rsys/cquick.h"
#include "rsys/wind.h"
#include "rsys/screen.h"

/*
 * Note, the code below probably be rewritten to use XorRgn as much
 *	 as possible and probably have only one CalcVisBehind
 */

P4(PUBLIC pascal trap, void, MoveWindow, WindowPtr, wp, INTEGER, h, INTEGER, v,
								BOOLEAN, front)
{
    GrafPtr gp;
    RgnHandle movepart, updatepart, behindpart;
    Rect r;
    register WindowPeek w;

    TRAPBEGIN();
    w = (WindowPeek) wp;
    gp = thePort;
    if (WINDOW_VISIBLE_X (w))
      {
	SetPort (MR (wmgr_port));
	ClipRect (&GD_BOUNDS (MR (TheGDevice)));
	ClipAbove(w);
	movepart = NewRgn();
	updatepart = NewRgn();
	behindpart = NewRgn();
	SectRgn(PORT_CLIP_REGION (MR (wmgr_port)),
		WINDOW_STRUCT_REGION (w), movepart);

#if 1
	/* 
	 * CopyBits does unaligned 32-bit reads from the source, which can
	 * cause it to read beyond the framebuffer in certain circumstances.
	 * This is a cheesy way to prevent that from happening here.  A
	 * better fix would be either in CopyBits or to force an extra page
	 * after the framebuffer.
	 */
	{
	  Rect tmpr;
	  RgnHandle last_three_pixels;

	  tmpr = GD_BOUNDS (MR (TheGDevice));
	  tmpr.top = CW (CW (tmpr.bottom) - 1);
	  tmpr.left = CW (CW (tmpr.right) - 3);
	  last_three_pixels = NewRgn ();
	  RectRgn (last_three_pixels, &tmpr);
	  DiffRgn (movepart, last_three_pixels, movepart);
	  DisposeRgn (last_three_pixels);
	}
#endif

	CopyRgn(movepart, behindpart);
	r = HxX (WINDOW_STRUCT_REGION (w), rgnBBox);
      }
#if !defined(LETGCCWAIL)
    else 
      {
	movepart = 0;
	updatepart = 0;
	behindpart = 0;
      }
#endif

#if 1
/*
 * NOTE: the use of portRect below was introduced by Bill, without comment
 *       either here or in the rcslog.  But taking it out made the MSW5.1
 *	 Picture editting window come up in the wrong place.
 *	 (That could be due to other inconsistencies though, like the
 */
    h += CW (PORT_BOUNDS (w).left) - CW (PORT_RECT (w).left);
    v += CW (PORT_BOUNDS (w).top)  - CW (PORT_RECT (w).top);
#else
    h += CW (PORT_BOUNDS (w).left);
    v += CW (PORT_BOUNDS (w).top);
#endif
    if (WINDOW_VISIBLE_X (w))
      {
	WRAPPER_PIXMAP_FOR_COPY (wrapper);
	
	OffsetRect (&r, h, v);
	OffsetRgn (movepart, h, v);
	SectRgn (movepart, PORT_CLIP_REGION (MR (wmgr_port)), movepart);
	ClipRect (&GD_BOUNDS (MR (TheGDevice)));

	WRAPPER_SET_PIXMAP_X (wrapper, GD_PMAP_X (MR (TheGDevice)));

#define NEW_CLIP_HACK
#if defined(NEW_CLIP_HACK)
	/* 
	 * This hack appears to be necessary because clipping via the
	 * clip-region isn't enough to prevent us from reading bits that
	 * are outside the framebuffer.  If there is unmapped memory on
	 * either side of the framebuffer we can eat flaming death for
	 * just looking at it.  This appears to happen under NT4.0.
	 */
	{
	  Rect srcr, dstr;
	  
	  SectRect (&HxX (WINDOW_STRUCT_REGION (w), rgnBBox),
		    &GD_BOUNDS (MR (TheGDevice)), &srcr);

	  dstr = GD_BOUNDS (MR (TheGDevice));
	  OffsetRect (&dstr, h, v);
	  SectRect (&dstr, &r, &dstr);
	  CopyBits (wrapper, wrapper, &srcr, &dstr, srcCopy, movepart);
	}
#else
	CopyBits (wrapper, wrapper,
		  &HxX (WINDOW_STRUCT_REGION (w), rgnBBox), &r,
		  srcCopy, movepart);
#endif
      }
    OffsetRgn (WINDOW_STRUCT_REGION (w), h, v);
    OffsetRgn (WINDOW_CONT_REGION (w), h, v);
    OffsetRgn (WINDOW_UPDATE_REGION (w), h, v);
    OffsetRect (&PORT_BOUNDS (w), -h, -v);
    if (WINDOW_VISIBLE_X (w))
      {
	ClipRect (&GD_BOUNDS (MR (TheGDevice)));
	ClipAbove(w);
	DiffRgn (WINDOW_STRUCT_REGION (w), movepart, updatepart);
	SectRgn (PORT_CLIP_REGION (MR (wmgr_port)), updatepart, updatepart);
	DiffRgn(behindpart, movepart, behindpart);
	DiffRgn(behindpart, updatepart, behindpart);
	PaintOne(w, updatepart);
	PaintBehind (WINDOW_NEXT_WINDOW (w), behindpart);
	CalcVisBehind(w, updatepart);
	CalcVisBehind (WINDOW_NEXT_WINDOW (w), behindpart);
	CalcVisBehind (WINDOW_NEXT_WINDOW (w), movepart);

	DisposeRgn(movepart);
	DisposeRgn(updatepart);
	DisposeRgn(behindpart);
      }
    if (front)
	SelectWindow((WindowPtr) w);   
    SetPort(gp);
    TRAPEND();
}

P3 (PUBLIC pascal trap, void, DragWindow, WindowPtr, wp, Point, p, Rect *, rp)
{
  RgnHandle rh;
  LONGINT l;
  EventRecord ev;
  int cmddown;
  Rect r;
    
  THEPORT_SAVE_EXCURSION
    (MR (wmgr_port),
     {
       GetOSEvent (0, &ev);
       SetClip (MR (GrayRgn));
       cmddown = ev.modifiers & CWC (cmdKey);
       if (cmddown)
	 ClipAbove ((WindowPeek) wp);
       rh = NewRgn ();
       CopyRgn (WINDOW_STRUCT_REGION (wp), rh);
       r = *rp;
       if (CW (r.top) < 24)
	 r.top = CWC (24);
       l = DragGrayRgn (rh, p, &r, &r, noConstraint, (ProcPtr) 0);
       if ((uint32) l != 0x80008000)
	 MoveWindow(wp,
		    (- CW (PORT_BOUNDS (wp).left)
		     + LoWord (l) + CW (PORT_RECT (wp).left)),
		    (- CW (PORT_BOUNDS (wp).top)
		     + HiWord (l) + CW (PORT_RECT (wp).top)),
		    !cmddown);
    
       DisposeRgn (rh);
     });
}

#define SETUP_PORT(p)				\
do						\
{						\
  SetPort (p);					\
  PenPat(gray);					\
  PenMode(notPatXor);				\
}						\
while (FALSE)

#define RESTORE_PORT(p)				\
do						\
{						\
  PenPat(black);				\
  PenMode(patCopy);				\
  SetPort (p);					\
}						\
while (FALSE)

P3(PUBLIC pascal trap, LONGINT, GrowWindow, WindowPtr, w, Point, startp,
								    Rect *, rp)
{
    EventRecord ev;
    GrafPtr gp;
    Point p;
    Rect r;
    Rect pinr;
    LONGINT l;

    p.h = startp.h;
    p.v = startp.v;
#if 0
    r.left   = CW (- CW (PORT_BOUNDS (w).left));
    r.top    = CW (- CW (PORT_BOUNDS (w).top));
    r.right  = CW (CW (r.left) + RECT_WIDTH (&PORT_RECT (w)));
    r.bottom = CW (CW (r.top)  + RECT_HEIGHT (&PORT_RECT (w)));
#else
    r.left   = CW (CW (PORT_RECT (w).left)   - CW (PORT_BOUNDS (w).left));
    r.top    = CW (CW (PORT_RECT (w).top)    - CW (PORT_BOUNDS (w).top));
    r.right  = CW (CW (PORT_RECT (w).right)  - CW (PORT_BOUNDS (w).left));
    r.bottom = CW (CW (PORT_RECT (w).bottom) - CW (PORT_BOUNDS (w).top));
#endif

    pinr.left = CW(CW(r.left) + CW(rp->left));
    if (CW(pinr.left) <= CW(r.left) && CW(rp->left) > 0)
      pinr.left = CWC(32767);

    pinr.top = CW(CW(r.top) + CW(rp->top));
    if (CW(pinr.top) <= CW(r.top) && CW(rp->top) > 0)
      pinr.top = CWC(32767);

    pinr.right = CW(CW(r.left) + CW(rp->right));
    if (CW(pinr.right) <= CW(r.left) && CW(rp->right) > 0)
      pinr.right = CWC(32767);

    pinr.bottom = CW(CW(r.top) + CW(rp->bottom));
    if (CW(pinr.bottom) <= CW(r.top) && CW(rp->bottom) > 0)
      pinr.bottom = CWC(32767);

    gp = thePort;
    SETUP_PORT (MR ((GrafPtr) WMgrPort));
    SETUP_PORT (MR (wmgr_port));
    ClipRect (&GD_BOUNDS (MR (TheGDevice)));
    ClipAbove((WindowPeek) w);
    WINDCALL((WindowPtr) w, wGrow, (LONGINT) (long) &r);
    while (!GetOSEvent(mUpMask, &ev))
      {
	ev.where.h = CW(ev.where.h);
	ev.where.v = CW(ev.where.v);
        l = PinRect (&pinr, ev.where);
	ev.where.v = HiWord(l);
	ev.where.h = LoWord(l);
        if (p.h != ev.where.h || p.v != ev.where.v)
	  {
            WINDCALL((WindowPtr) w, wGrow, (LONGINT) (long) &r);
            r.right = CW(CW(r.right) + (ev.where.h - p.h));
            r.bottom = CW(CW(r.bottom) + (ev.where.v - p.v));
            WINDCALL((WindowPtr) w, wGrow, (LONGINT) (long) &r);
            p.h = ev.where.h;
            p.v = ev.where.v;
	  }
	CALLDRAGHOOK();
      }
    WINDCALL ((WindowPtr) w, wGrow, (LONGINT) (long) &r);
    RESTORE_PORT (MR ((GrafPtr) WMgrPort));
    RESTORE_PORT (gp);
    if (p.h != startp.h || p.v != startp.v)
/*-->*/ return(((LONGINT)(CW(r.bottom) - CW(r.top)) << 16)|
	        (unsigned short)(CW(r.right) - CW(r.left)));
    else
        return(0L);
}

/* #### speedup? bag saveold, drawnew */

P4 (PUBLIC pascal trap, void, SizeWindow, WindowPtr, w,
    INTEGER, width, INTEGER, height, BOOLEAN, flag)
{
  if (width || height)
    {
      if (WINDOW_VISIBLE_X (w))
	SaveOld ((WindowPeek) w);
      
      PORT_RECT (w).right  = CW (CW (PORT_RECT (w).left) + width);
      PORT_RECT (w).bottom = CW (CW (PORT_RECT (w).top)  + height);
      
      THEPORT_SAVE_EXCURSION
	(MR (wmgr_port),
	 {
	   WINDCALL (w, wCalcRgns, 0);
	   if (WINDOW_VISIBLE_X (w))
	     DrawNew ((WindowPeek) w, flag);
	 });
    }
}
