/* Implementation of View class
 *
 * Copyright (C)  1993, 1994, 1995  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Authors: Scott Francis, Paul Kunz, Tom Pavel, 
 *	    Imran Qureshi, and Libing Wang
 *	    Adam Fedor (U Colorado)
 *          Mike Kienenberger (Alaska)
 *
 * This file is part of an Objective-C class library for a window system
 *
 * View.m,v 1.133 1995/12/13 22:33:24 fedor Exp
 */

// In this file, comments that start with '//' are normal, permanent comments.
// Those that start with '/*' mark bugs or inconsistencies with the way
// things should be, or comment out code that doesn't yet work or exist, or
// is likely to change in the near future.
 
#include "View.h"

/* Required for implementation: */
#include  <objc/List.h>
#include "Application.h"
#include "CustomView.h"
#include <stdlib.h>
#include <stdio.h>
#include <objc/typedstream2.h>
#include "dpsclient/dpsclient.h"
#include "dpsclient/CGTMatrix.h"
#include "appkit/FocusStack.h"

extern char *ViewInstanceName(void);

/* Are we drawing, printing, or copying PostScript to the scrap? */
short NXDrawingStatus = NX_DRAWING;

/* Keep track of focused views */
static FocusStack *focusStack;
static BOOL lockInProgress;

@interface View(WidgetSet)
- _init;
- _setAsBulletinBoard;
- _displayPreLockFocus;
- _displayLockFocus;
- _displayUnlockFocus;
- _flushView;
- _getFrame;
- _addCallback;
- _managedBy:parent wid:(void*)widget;
- _unManage;
- _destroy;
- _moveTo:(NXCoord)x :(NXCoord)y;
- _setFrame:(const NXRect *)aFrame;
- _setNeedsDisplay:(BOOL)flag;
- _setResize:(void *)policy;
- _setOffsets:(NXSize *)offsets;
- _setBorderShadow:(void *)shadow andThickness:(void *)thickness;
- _sizeTo:(NXCoord)width :(NXCoord)height;
- _displayFreeGState;
@end

@implementation View:Responder

// Private methods not declared in interface file

- _setSuperview:(View *)aView
{
  superview = aView;
  [self setNextResponder:superview];
  [self windowChanged:window];
  window = [superview window];
//  [self update];  /* don't need to display */
  return self;
}

- _removeSubview:(View *)subview
{
  [subviews removeObject:subview];
  /* For each object below removed object, we need to calculate rectangle
     overlap with this subview, and send -update messages. -km */
  return self;
}

// A modified -findViewWithTag: that returns how deep the tag was found.
- _searchForTag:(int)aTag deep:(unsigned int *)deepret
{
  unsigned int i;
  unsigned int numchildren = [subviews count];
  unsigned int deepness[numchildren];
  unsigned int shallowest;
  id  deepobj[numchildren];
  id  shallowobj;
  
  if ([self tag] == aTag) {
    *deepret = 0;
    return self;
  }
  
  for (i = 0; i < numchildren; i++) {
    deepobj[i] = [[subviews objectAt:i] _searchForTag:aTag deep:&(deepness[i])];
    if (deepness[i] == 0)
      return deepobj[i];
  }
  shallowest = ~0;
  shallowobj = nil;
  for (i = 0; i < numchildren; i++)
    if (deepness[i] < shallowest) {
      shallowest = deepness[i];
      shallowobj = deepobj[i];
    }
  *deepret = shallowest;
  return shallowobj;
}

// Public methods

//
// Initializing and freeing View objects
//
- initFrame:(const NXRect *)frameRect
{
    [super init];
    instancename = ViewInstanceName();
    frame = *frameRect;
    bounds.origin.x = 0;
    bounds.origin.y = 0;
    bounds.size     = frame.size;
    _vFlags.autosizing = NX_NOTSIZABLE;
    _vFlags.autoresizeSubviews = NO;
#ifdef	RESIZE_DEBUG
    fprintf(stderr, "View: autosizing = NX_NOTSIZABLE in initFrame:\n");
#endif	/* RESIZE_DEBUG */
    return self;
}

- init
{
  NXRect rect = { {0,0}, {0,0} };
  
  [self initFrame:&rect];
  return self;
}

- free
{
  if (subviews) {
    [subviews freeObjects];
    subviews = [subviews free];
    subviews = nil;
  }
  [self removeFromSuperview];
  [_drawMatrix free];
  [_frameMatrix free];
  [self freeGState];
  [self _destroy];
  return [super free];
}

//
// Managing the View hierarchy
//
- addSubview:aView
{
  return [self addSubview:aView :NX_ABOVE relativeTo:nil];
}

- addSubview:aView :(int)place relativeTo:otherView;
{
  unsigned int index;
  
  if (aView == nil)
    return nil;
  
  if ([aView isKindOf:[View class]] == NO)
    fprintf(stderr, "Adding subview that's not a view\n");
  
  if (!subviews)
    subviews = [[List alloc] init];
  [aView removeFromSuperview];
  index = [subviews indexOf:otherView];
  if (index == NX_NOT_IN_LIST)
    if (place == NX_ABOVE)
      index = 0;
    else
      index = [subviews count];
  [subviews insertObject:aView at:index];
  [aView _setSuperview:self];
  
  if (widgetid)
    [aView _managedBy:self];
  
  return aView;
}

- findAncestorSharedWith:aView
{
  // This method isn't very efficient; it's too brute-force.
  if (aView == self)
    return self;
  if (aView == nil || [aView isKindOf:[View class]] == NO)
    return nil;
  
  if ([aView isDescendantOf:self] == YES)
    return self;
  if (superview == nil)
    return nil;
  return [superview findAncestorSharedWith:aView];
}

- (BOOL)isDescendantOf:aView
{
  unsigned int index, count;
  id object;
  
  if (aView == self)
    return YES;
  if (aView == nil || [aView isKindOf:[View class]] == NO)
    return NO;
  if (subviews == nil)
    return NO;
  count = [subviews count];
  for (index = 0; index < count; index++) {
    object = [subviews objectAt:index];
    if ([object isDescendantOf:aView] == YES)
      return YES;
  }
  return NO;
}

- opaqueAncestor
{
  if (vFlags.opaque || superview == nil)
    return self;
  return [superview opaqueAncestor];
}

- removeFromSuperview
{
  if (superview == nil)
    return self;
  [self setNextResponder:nil];
  [superview _removeSubview:self];
  [self windowChanged:nil];
  superview = nil;
  window = nil;
  [self _unManage];
  return self;
}

- replaceSubview:oldView with:newView
{
  int index;
  
  if (newView == nil || [newView isKindOf:[View class]] == NO ||
      subviews == nil)
    return nil;
  index = [subviews indexOf:oldView];
  if (index == NX_NOT_IN_LIST)
    return nil;
  [oldView removeFromSuperview];
  [subviews insertObject:newView at:index];
  [newView _setSuperview:self];
  [newView _managedBy:self];
  return oldView;
}

- subviews
{
  return subviews;
}

- superview
{
  return superview;
}

- window
{
  return window;
}

- windowChanged:newWindow
{
  /* Is this method supposed to do anything in this class?  The NS GenRef
     doesn't really say. -km */
  return self;
}

//
// Modifying the frame rectangle
//
- (float)frameAngle
{
  if (!vFlags.rotatedFromBase || !_frameMatrix)
    return 0;
    
  return [_frameMatrix rotation];
}

- getFrame:(NXRect *)theRect
{
  if (!theRect)
    return nil;
  *theRect = frame;
  return self;
}

- moveBy:(NXCoord)deltaX :(NXCoord)deltaY
{
  NXPoint point;
  
  point.x = frame.origin.x + deltaX;
  point.y = frame.origin.y + deltaY;
  return [self moveTo:point.x :point.y];
}    

- moveTo:(NXCoord)x :(NXCoord)y
{
  frame.origin.x = x;
  frame.origin.y = y;
  if (_vFlags.needsAncestorNotify && _vFlags.ancestorNotifyWasEnabled)
    [superview descendantFrameChanged:self];
  if (_frameMatrix) 
    {
      NXPoint offset = [_frameMatrix offset];
      offset.x = x - offset.x;
      offset.y = y - offset.y;
      [_frameMatrix translate:offset];
    }
  [self _moveTo:x :y];
  [self update];
  return self;
}

- rotateBy:(NXCoord)deltaAngle
{
  NXCoord angle = 0;
  
  if (_frameMatrix)
    angle = [_frameMatrix rotation];
  angle += deltaAngle;
  return [self rotateTo:angle];
}    

- rotateTo:(NXCoord)angle
{
  if (!_frameMatrix)
    {
      _frameMatrix = [CGTMatrix new];
      /* Include our original offset */
      [_frameMatrix translate:frame.origin];
    }
  
  [_frameMatrix rotate:angle];
  vFlags.rotatedFromBase = 1;
  vFlags.rotatedOrScaledFromBase = 1;
  /* Does this method send descendantFrameChanged?  It doesn't, according to
     the NS GenRef. -km */
/*
  if (_vFlags.needsAncestorNotify && _vFlags.ancestorNotifyWasEnabled)
    [superview descendantFrameChanged:self];
*/
  [self update];
  return self;
}

- setFrame:(const NXRect *)frameRect
{
  frame = *frameRect;
  [self _setFrame:&frame];
  /* Need to calculate changes to bounds.  bounds may be translated, scaled,
     and rotated.  This assignment assumes no translating, scaling, or
     rotating, and therefore is wrong. -km */
/*
  bounds.size  = frame.size;
*/

  /* Does this method send descendantFrameChanged?  It doesn't, according to
     the NS GenRef, but logically it should. -km */
/*
  if (_vFlags.needsAncestorNotify && _vFlags.ancestorNotifyWasEnabled)
    [superview descendantFrameChanged:self];
*/
  return self;
}

- sizeBy:(NXCoord)deltaWidth :(NXCoord)deltaHeight
{
  NXSize size;
  
  size.width = frame.size.width + deltaWidth;
  size.height = frame.size.height + deltaHeight;
  return [self sizeTo:size.width :size.height];
}    

- sizeTo:(NXCoord)width :(NXCoord)height;
{
    NXSize oldSize;
    
    oldSize = frame.size;
    frame.size.width   = width;
    frame.size.height  = height;

    /* This assignment is wrong.  The bounds changes in relation to it's CTM. 
	See note in -setFrame:, above. -km */
    bounds.size.width  = width;
    bounds.size.height = height;

    [self _sizeTo:width :height];
    
    if (_vFlags.autoresizeSubviews)
	[self resizeSubviews:&oldSize];
    
    return self;
}

//
// Modifying the coordinate system
//
- (float)boundsAngle
{
  if (!_drawMatrix)
    return 0;
    
  return [_drawMatrix rotation];
}

- drawInSuperview
{
  /* FIXME: Should we check for a valid gstate? - asf */
  [_frameMatrix free];
  [_drawMatrix free];
  NX_X(&bounds) = 0;
  NX_Y(&bounds) = 0;
  return self;
}

- getBounds:(NXRect *)theRect
{
  if (!theRect)
    return nil;
  *theRect = bounds;
  return self;
}

- (BOOL)isFlipped
{
  return vFlags.needsFlipped;
}

- (BOOL)isRotatedFromBase
{
  return vFlags.rotatedFromBase;
}

- (BOOL)isRotatedOrScaledFromBase
{
  return vFlags.rotatedOrScaledFromBase;
}

- rotate:(NXCoord)angle
{
  if (!_drawMatrix)
      _drawMatrix = [CGTMatrix new];
  
  [_drawMatrix rotate:angle];
  return self;
}

- scale:(NXCoord)x :(NXCoord)y
{
  NXSize scale;
  if (!_drawMatrix)
      _drawMatrix = [CGTMatrix new];
  
  scale.width = x;
  scale.height = y;
  [_drawMatrix scale:scale];
  return self;
}

- setDrawOrigin:(NXCoord)x :(NXCoord)y
{
  NXPoint offset;
  
  offset.x = 0;
  offset.y = 0;
  if (!_drawMatrix)
    _drawMatrix = [CGTMatrix new];
  offset = [_drawMatrix offset];
  offset.x = -offset.x - x;
  offset.y = -offset.y - y;
  [_drawMatrix translate:offset];
  vFlags.translatedDraw = 1;
  return self;
}

- setDrawRotation:(NXCoord)angle
{
  /* Save CTM transformations for later. -km */
  return self;
}

- setDrawSize:(NXCoord)width :(NXCoord)height
{
  /* Save CTM transformations for later. -km */
  return self;
}

- setFlipped:(BOOL)flag
{
  BOOL origflag;
  
  origflag = vFlags.needsFlipped;
  vFlags.needsFlipped = !(!flag); // Insure that the BOOL is 1, not just "not 0"
  if (origflag != flag && _vFlags.notifyWhenFlipped)
    [superview descendantFlipped:self];
  return self;
}

- translate:(NXCoord)x :(NXCoord)y
{
  /* Save CTM transformations for later. -km */
  return self;
}

//
// Converting coordinates
//
- centerScanRect:(NXRect *)aRect
{
  /* Save coordinate conversion for after CTMs. -km */
  return self;
}

- convertPoint:(NXPoint *)aPoint fromView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView is not in same window\n");
    return nil;
  }
  
  if (aView)
    [aView convertPoint:aPoint toView:nil];
  /* Recursively convert from window coordinates */
  if (superview)
    [superview convertPoint:aPoint fromView:nil];
  /* And finally, convert from our superview coordinates to ours */
  [self convertPointFromSuperview:aPoint];
  return self;
}

- convertPoint:(NXPoint *)aPoint toView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView is not in same window\n");
    return nil;
  }

  /* Convert from our coordinates to our superview's */
  [self convertPointToSuperview:aPoint];
  /* Then, recursively convert to window coordinates */
  if (superview)
    [superview convertPoint:aPoint toView:nil];
  if (aView) 
    [aView convertPoint:aPoint fromView:nil];
  return self;
}

- convertPointFromSuperview:(NXPoint *)aPoint
{
  if (_frameMatrix)
    {
      CGTMatrix *invert = [[_frameMatrix copy] invert];
      *aPoint = [invert transformPoint:*aPoint];
      [invert free];
    }
  else
    {
      aPoint->x -= NX_X(&frame);
      aPoint->y -= NX_Y(&frame);
    }
  if (_drawMatrix)
    {
      CGTMatrix *invert = [[_drawMatrix copy] invert];
      *aPoint = [invert transformPoint:*aPoint];
      [invert free];
    }
  return self;
}

- convertPointToSuperview:(NXPoint *)aPoint
{
  if (_drawMatrix)
    *aPoint = [_drawMatrix transformPoint:*aPoint];
  if (_frameMatrix)
    *aPoint = [_frameMatrix transformPoint:*aPoint];
  else
    {
      aPoint->x += NX_X(&frame);
      aPoint->y += NX_Y(&frame);
    }
  return self;
}

- convertRect:(NXRect *)aRect fromView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView is not in same window\n");
    return nil;
  }
  
  if (aView)
    [aView convertRect:aRect toView:nil];
  /* Recursively convert from window coordinates */
  if (superview)
    [superview convertRect:aRect fromView:nil];
  /* And finally, convert from our superview coordinates to ours */
  [self convertRectFromSuperview:aRect];
  return self;
}

- convertRect:(NXRect *)aRect toView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView is not in same window\n");
    return nil;
  }

  /* Convert from our coordinates to our superview's */
  [self convertRectToSuperview:aRect];
  /* Then, recursively convert to window coordinates */
  if (superview)
    [superview convertRect:aRect toView:nil];
  if (aView) 
    [aView convertRect:aRect fromView:nil];
  return self;
}

- convertRectFromSuperview:(NXRect *)aRect
{
  if (_frameMatrix)
    {
      CGTMatrix *invert = [[_frameMatrix copy] invert];
      *aRect = [invert transformRect:*aRect];
      [invert free];
    }
  else
    {
      NX_X(aRect) -= NX_X(&frame);
      NX_Y(aRect) -= NX_Y(&frame);
    }
  if (_drawMatrix)
    {
      CGTMatrix *invert = [[_drawMatrix copy] invert];
      *aRect = [invert transformRect:*aRect];
      [invert free];
    }
  return self;
}

- convertRectToSuperview:(NXRect *)aRect
{
  if (_drawMatrix)
    *aRect = [_drawMatrix transformRect:*aRect];
  if (_frameMatrix)
    *aRect = [_frameMatrix transformRect:*aRect];
  else
    {
      NX_X(aRect) += NX_X(&frame);
      NX_Y(aRect) += NX_Y(&frame);
    }
  return self;
}

- convertSize:(NXSize *)aSize fromView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView does not have same window as self\n");
    return nil;
  }
  return self;
}

- convertSize:(NXSize *)aSize toView:aView
{
  if (aView && window != [aView window]) {
    fprintf(stderr, "Error (View): aView does not have same window as self\n");
    return nil;
  }
  return self;
}

//
// Notifying ancestor Views
//
- descendantFlipped:sender
{
  if (superview == nil)
    return self;
  return [superview descendantFlipped:sender];
}

- descendantFrameChanged:sender
{
  if (superview == nil)
    return self;
  return [superview descendantFrameChanged:sender];
}

- notifyAncestorWhenFrameChanged:(BOOL)flag
{
  _vFlags.needsAncestorNotify = flag;
  return self;
}

- notifyWhenFlipped:(BOOL)flag
{
  _vFlags.notifyWhenFlipped = flag;
  return self;
}

- suspendNotifyAncestorWhenFrameChanged:(BOOL)flag
{
    if ( flag ) {
	_vFlags.ancestorNotifyWasEnabled = NO;
    } else {
	_vFlags.ancestorNotifyWasEnabled = YES;
    }
    return self;
}

//
// Resizing subviews
//
- resizeSubviews:(const NXSize *)oldSize
{
    if (subviews)
    {
	int count = [subviews count] - 1;
	while (count >= 0)
	{
	    [[subviews objectAt:count] superviewSizeChanged:oldSize];
	    --count;
	}
    }
    return self;
}

- setAutoresizeSubviews:(BOOL)flag
{
  _vFlags.autoresizeSubviews = !(!flag); // Insure that the BOOL is 1, not
                                         // just "not 0"
  return self;
}

- setAutosizing:(unsigned int)mask
{
    _vFlags.autosizing = mask;
#ifdef	RESIZE_DEBUG
    fprintf(stderr, "View: autosizing = mask in setAutosizing:\n");
#endif	/* RESIZE_DEBUG */
    return self;
}

- (unsigned int)autosizing
{
  return _vFlags.autosizing;
}

- superviewSizeChanged:(const NXSize *)oldSize
{
    NXRect newSuperviewFrame, newFrame = frame;
    NXSize myOldSize = frame.size;
    int widthDif, heightDif;
    
#ifdef	RESIZE_DEBUG
    fprintf(stderr, "Autosizing flags: ");
    if (NX_NOTSIZABLE == _vFlags.autosizing)
      fprintf(stderr, "NX_NOTSIZABLE ");
    if (_vFlags.autosizing & NX_WIDTHSIZABLE)
      fprintf(stderr, "NX_WIDTHSIZABLE ");
    if (_vFlags.autosizing & NX_MINXMARGINSIZABLE)
      fprintf(stderr, "NX_MINXMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_MAXXMARGINSIZABLE)
      fprintf(stderr, "NX_MAXXMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_HEIGHTSIZABLE)
      fprintf(stderr, "NX_HEIGHTSIZABLE ");
    if (_vFlags.autosizing & NX_MINYMARGINSIZABLE)
      fprintf(stderr, "NX_MINYMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_MAXYMARGINSIZABLE)
      fprintf(stderr, "NX_MAXYMARGINSIZABLE ");
    fprintf(stderr, "\n");
#endif	/* RESIZE_DEBUG */

    if (_vFlags.autosizing & NX_NOTSIZABLE)  return self;
    
    [superview getFrame:&newSuperviewFrame];
    widthDif = newSuperviewFrame.size.width - oldSize->width;
    if ((_vFlags.autosizing & NX_WIDTHSIZABLE)
     && (_vFlags.autosizing & NX_MINXMARGINSIZABLE)
     && (_vFlags.autosizing & NX_MAXXMARGINSIZABLE))
    {
      newFrame.size.width += (widthDif / 3.0);
      newFrame.origin.x += (widthDif / 3.0);
    }
    else if ((_vFlags.autosizing & NX_WIDTHSIZABLE)
     && (_vFlags.autosizing & NX_MINXMARGINSIZABLE))
    {
      newFrame.size.width += (widthDif / 2.0);
      newFrame.origin.x += (widthDif / 2.0);
    }
    else if ((_vFlags.autosizing & NX_WIDTHSIZABLE)
     && (_vFlags.autosizing & NX_MAXXMARGINSIZABLE))
    {
      newFrame.size.width += (widthDif / 2.0);
    }
    else if ((_vFlags.autosizing & NX_MINXMARGINSIZABLE)
     && (_vFlags.autosizing & NX_MAXXMARGINSIZABLE))
    {
      newFrame.origin.x += (widthDif / 2.0);
    }
    else if (_vFlags.autosizing & NX_WIDTHSIZABLE)
    {
      newFrame.size.width += widthDif;
#ifdef	RESIZE_DEBUG
      fprintf(stderr, "View:  stretching width\n");
#endif	/* RESIZE_DEBUG */
    }
    else if (_vFlags.autosizing & NX_MINXMARGINSIZABLE)
    {
      newFrame.origin.x += widthDif;
    }
    else if (_vFlags.autosizing & NX_MAXXMARGINSIZABLE)
    {
      /* do nothing */
    }

    heightDif = newSuperviewFrame.size.height - oldSize->height;
    if ((_vFlags.autosizing & NX_HEIGHTSIZABLE)
     && (_vFlags.autosizing & NX_MINYMARGINSIZABLE)
     && (_vFlags.autosizing & NX_MAXYMARGINSIZABLE))
    {
      newFrame.size.height += (heightDif / 3.0);
      newFrame.origin.y += (heightDif / 3.0);
    }
    else if ((_vFlags.autosizing & NX_HEIGHTSIZABLE)
     && (_vFlags.autosizing & NX_MINYMARGINSIZABLE))
    {
      newFrame.size.height += (heightDif / 2.0);
      newFrame.origin.y += (heightDif / 2.0);
    }
    else if ((_vFlags.autosizing & NX_HEIGHTSIZABLE)
     && (_vFlags.autosizing & NX_MAXYMARGINSIZABLE))
    {
      newFrame.size.height += (heightDif / 2.0);
    }
    else if ((_vFlags.autosizing & NX_MINYMARGINSIZABLE)
     && (_vFlags.autosizing & NX_MAXYMARGINSIZABLE))
    {
      newFrame.origin.y += (heightDif / 2.0);
    }
    else if (_vFlags.autosizing & NX_HEIGHTSIZABLE)
    {
      newFrame.size.height += heightDif;
#ifdef	RESIZE_DEBUG
      fprintf(stderr, "View:  stretching height\n");
#endif	/* RESIZE_DEBUG */
    }
    else if (_vFlags.autosizing & NX_MINYMARGINSIZABLE)
    {
      newFrame.origin.y += heightDif;
    }
    else if (_vFlags.autosizing & NX_MAXYMARGINSIZABLE)
    {
      /* do nothing */
    }

#ifdef	RESIZE_DEBUG
    fprintf(stderr,
          "View:  changing from (%d, %d, %d, %d) to (%d, %d, %d, %d)\n",
          frame.origin.x, frame.origin.y, frame.size.width,
          frame.size.height, newFrame.origin.x, newFrame.origin.y,
          newFrame.size.width, newFrame.size.height);
#endif	/* RESIZE_DEBUG */

    frame = newFrame;

    if (YES == _vFlags.autoresizeSubviews )
      if ((_vFlags.autosizing & NX_HEIGHTSIZABLE)
       || (_vFlags.autosizing & NX_WIDTHSIZABLE))
          [self resizeSubviews:&myOldSize];

    frame = newFrame;
    [self _setFrame:&frame];

    return self;
}

- _windowRectChangedFrom:(const NXRect *)oldFrame to:(const NXRect *)newFrame
{
    NXRect myNewFrame = frame;
    NXSize myOldSize = frame.size;
    
    myNewFrame.size.width += newFrame->size.width - oldFrame->size.width;
    myNewFrame.size.height += newFrame->size.height - oldFrame->size.height;
    
#ifdef	RESIZE_DEBUG
    fprintf(stderr, "ContentView:  changing from (%d, %d) to (%d, %d)\n",
          frame.size.width, frame.size.height,
          myNewFrame.size.width, myNewFrame.size.height);
#endif	/* RESIZE_DEBUG */

    frame = myNewFrame;

    [self resizeSubviews:&myOldSize];
    frame = myNewFrame;
    [self _setFrame:&frame];

    return self;
}
// Graphics state objects
- allocateGState
{
    if (vFlags.validGState == 0)
	_vFlags.wantsGState = 1;
    return self;
}

- freeGState
{
    if (vFlags.validGState)
    	[self _displayFreeGState];
    vFlags.validGState = 0;
    return self;
}

- (int)gState
{
    if (!vFlags.validGState)
    	return 0;
    return _gstate;
}

- initGState
{
    return self;
}

- renewGState
{
  vFlags.validGState = 0;
  return self;
}

- notifyToInitGState:(BOOL)flag
{
  _vFlags.notifyToInitGState = flag;
  return self;
}

//
// Focusing
//
- clipToFrame:(const NXRect *)frameRect
{
  /* Does the default version of this method do anything? -km */
  return self;
}

- (BOOL)doesClip
{
  return !(vFlags.noClip);
}

- setClipping:(BOOL)flag
{
  vFlags.noClip = !flag;
  return self;
}

- (BOOL)isFocusView
{
  return (focusStack && [focusStack currentView] == self);
}

/* NOTE:  It is not done here, but it is the responsibility of widget
   categories to update the gstate by the current frame and draw
   coordinate system for the View (stored in _frameMatrix and _drawMatrix) */
- (BOOL)lockFocus
{
  BOOL myLock = NO;
  
  if (!focusStack)
     focusStack = [FocusStack new];
   
  if (!lockInProgress)
    {
      if ([self isFocusView])
        {
          [focusStack relockView:self]; /* Just increment the nesting */
	  return YES;
	}
      [focusStack lockView:self];
      [self _displayPreLockFocus];
      lockInProgress = YES;
      myLock = YES;
    }

  if (superview && ![superview isFocusView] && !vFlags.validGState)
      [superview lockFocus];
  [self _displayLockFocus];

  if (myLock)
    lockInProgress = NO;
  return NO;
}

- unlockFocus
{
  if (![self isFocusView])
    {
      fprintf(stderr, "Error (View): Unlocking focus on unfocused view\n");
      return nil;
    }

  /* Returns nil if we had nested focuses */
  if ([focusStack unlockView])
      [self _displayUnlockFocus];
  return self;
}

//
// Displaying
//
- (BOOL)canDraw
{
  if (window != nil) {	/* should check if window is enabled */
    return YES;
  }
  return NO;
}

- display
{
  [self display:NULL :0 :NO];
  return self;
}

- display:(const NXRect *)rects :(int)rectCount
{
  [self display:rects :rectCount];
  return self;
}

- display:(const NXRect *)rects :(int)rectCount :(BOOL)clipFlag
{
  NXRect i_rects[3];
  int rcount;
  
  [self lockFocus];

  /* clipFlag needs to be checked for. -km */
  if ((rectCount == 0) || (rects == NULL)) 
    {
      i_rects[0] = bounds; /* fake it */
      rcount = 1;
      [self drawSelf:i_rects :rcount];
    } 
  else 
    {
      [self drawSelf:rects :rectCount];
    }
  /* Need to calculate whether each subview is inside rects, and if so,
     compute a new array of rects for the subview.  Currently, I cheat. -km */
  [subviews makeObjectsPerform:@selector(display)];
 
  [self unlockFocus];
  return self;
}

- displayFromOpaqueAncestor:(const NXRect *)rects
    :(int)rectCount
    :(BOOL)clipFlag
{
  [self notImplemented:_cmd];
  return self;
}

- displayIfNeeded
{
  if (vFlags.disableAutodisplay && vFlags.needsDisplay)
    [self display];
  vFlags.needsDisplay = 0;
  return self;
}
    
- drawSelf:(const NXRect *)rects :(int)rectCount
{
  return self;
}

- (BOOL)getVisibleRect:(NXRect *)theRect
{
  /* Do calculations with parent Views; in other words, clip theRect to
     the parent and see if there's a rect remaining.  Right now, cheat and
     return the entire frameRect. -km */
  if (!window)
    return NO;
  theRect->origin = frame.origin;
  theRect->size = frame.size;
  return YES;
}

- (BOOL)isAutodisplay
{
  return !(vFlags.disableAutodisplay);
}

- setAutodisplay:(BOOL)flag
{
  vFlags.disableAutodisplay = !flag;
  if (vFlags.needsDisplay) {
    [self display];
    vFlags.needsDisplay = NO;
  }
  return self;
}

- (BOOL)isOpaque
{
  return vFlags.opaque;
}

- setOpaque:(BOOL)flag
{
  vFlags.opaque = !(!flag);  // Make sure that the first bit is on.  A BOOL in
                             // C can mean ANY bit is on, and we need the first.
  return self;
}

- (BOOL)needsDisplay
{
  return vFlags.needsDisplay;
}

- setNeedsDisplay:(BOOL)flag
{
  // Make sure that the first bit is on.  A BOOL in
  // C can mean ANY bit is on, and we need the first.
  vFlags.needsDisplay = !(!flag);
  if ( _gstate ) 
    [self _setNeedsDisplay:flag];
  return self;
}

- (BOOL)shouldDrawColor
{
  /* This should check the X server that the window is on to see if it is
     color.  Should be done in a category for both Xlib AND Xm/Xt.  The
     default of this will return YES for the time being. -km */
  return YES;
}

- update
{
  if (vFlags.disableAutodisplay)
    vFlags.needsDisplay = YES;
  else
    [self display];
  return self;
}

//
// Scrolling
//
- adjustScroll:(NXRect *)newVisible
{
  /* Default implementation does nothing */
  return self;
}

- autoscroll:(NXEvent *)theEvent
{
  return nil;
}

- (BOOL)calcUpdateRects:(NXRect *)rects
    :(int *)rectCount
    :(NXRect *)enclRect
    :(NXRect *)goodRect
{
  if (*rectCount > 0)
    return YES;
  else
    return NO;
}

- invalidate:(const NXRect *)rects
    :(int)rectCount
{
  return self;
}

- scrollPoint:(const NXPoint *)aPoint
{
  return self;
}

- scrollRect:(const NXRect *)aRect
    by:(const NXPoint *)delta
{
  return self;
}

- scrollRectToVisible:(const NXRect *)aRect
{
  return nil;
}

//
// Managing the cursor
//

// This can't be done with any Widget set (well, it can, but it's very messy).
// It requires a low level graphics library interface.  Override these methods
// in an appropriate category to implement.

- addCursorRect:(const NXRect *)aRect
    cursor:anNXCursor
{
  /* For rotated cursor rects, there's two ways to do it:
     1) Create a shaped InputOnly window (X only).
     2) Create many InputOnly (or equivalent non-X systems) windows so that
        it appears that there's a consecutive non-rectangular region.
        Using X, the efficiency difference between (1) and (2) is almost nil.
        (1) will save resources (fewer windows), but will only work if the
        shape extension exists.
     According to the NS GenRef, rotated cursor rects don't work right anyway,
     so maybe we don't have to worry about this... -km 
  */
  return self;
}

- discardCursorRects
{
  return self;
}

- removeCursorRect:(const NXRect *)aRect
    cursor:anNXCursor
{
  return self;
}

- resetCursorRects
{
  return self;
}

//
// Assigning a tag
//
- findViewWithTag:(int)aTag
{
  unsigned int i;
  unsigned int numchildren = [subviews count];
  unsigned int deepness[numchildren];
  unsigned int shallowest;
  id  deepobj[numchildren];
  id  shallowobj;
  
  if ([self tag] == aTag)
    return self;
  
  for (i = 0; i < numchildren; i++) {
    deepobj[i] = [[subviews objectAt:i] _searchForTag:aTag deep:&(deepness[i])];
    if (deepness[i] == 0)
      return deepobj[i];
  }
  shallowest = ~0;
  shallowobj = nil;
  for (i = 0; i < numchildren; i++)
    if (deepness[i] < shallowest) {
      shallowest = deepness[i];
      shallowobj = deepobj[i];
    }
  return shallowobj;
}

- (int)tag
{
  return -1;
}

//
// Aiding event handling
//
- (BOOL)acceptsFirstMouse
{
  // Do the default
  return NO;
}

- hitTest:(NXPoint *)aPoint
{
  NXPoint newPoint;
  unsigned int i;
  unsigned int numchildren = [subviews count];
  id obj;
  
  if (aPoint->x >= frame.origin.x &&
      aPoint->x <= frame.origin.x+frame.size.width &&
      aPoint->y >= frame.origin.y &&
      aPoint->y <= frame.origin.y+frame.size.height) {
    newPoint = *aPoint;
    [self convertPointFromSuperview:&newPoint];
    for (i = 0; i < numchildren; i++)
      if ((obj = [[subviews objectAt:i] hitTest:&newPoint]) != nil)
        return obj;
  }
  return nil;
}

- (BOOL)mouse:(NXPoint *)aPoint
    inRect:(NXRect *)aRect
{
  /* Uncomment the following line, and delete the one after, when this
     function is implemented. -km */
  /* return NXMouseInRect(aPoint, aRect, vFlags.needsFlipped); */
  return NO;
}

- (BOOL)performKeyEquivalent:(NXEvent *)theEvent
{
  unsigned int i;
  unsigned int numchildren = [subviews count];
  
  for (i = 0; i < numchildren; i++)
    if ([[subviews objectAt:i] performKeyEquivalent:theEvent] == YES)
      return YES;
  return NO;
}

- (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)anEvent
{
  return NO;
}

/* I am here, for implementation. -km */

//
// Dragging
//
- dragFile:(const char *)filename
    fromRect:(NXRect *)rect
    slideBack:(BOOL)aFlag
    event:(NXEvent *)event
{
  [self notImplemented:_cmd];
  return self;
}

- dragImage:anImage
    at:(NXPoint *)location
    offset:(NXPoint *)mouseOffset
    event:(NXEvent *)theMouseDown
    pasteboard:(id /* really (Pasteboard *) but it doesn't exist yet */)pboard
    source:sourceObject
    slideBack:(BOOL)slideFlag
{
  [self notImplemented:_cmd];
  return self;
}

- registerForDraggedTypes:(const char *const *)pbTypes
    count:(int)count
{
  [self notImplemented:_cmd];
  return self;
}

- unregisterDraggedTypes
{
  [self notImplemented:_cmd];
  return self;
}

//
// Printing
//
- printPSCode:sender
{
  [self notImplemented:_cmd];
  return self;
}

- faxPSCode:sender
{
  [self notImplemented:_cmd];
  return self;
}

- faxPSCode:sender
    toList:(const char *const *)names
    numberList:(const char *const *)numbers
    sendAt:(time_t)time
    wantsCover:(BOOL)coverFlag
    wantsNotify:(BOOL)notifyFlag
    wantsHires:(BOOL)hiresFlag
    faxName:(const char *)string
{
  [self notImplemented:_cmd];
  return self;
}

- copyPSCodeInside:(const NXRect *)rect
    to:(NXStream *)stream
{
  [self notImplemented:_cmd];
  return self;
}

- writePSCodeInside:(const NXRect *)aRect
    to:pasteboard
{
  [self notImplemented:_cmd];
  return self;
}

- openSpoolFile:(char *)filename
{
  [self notImplemented:_cmd];
  return self;
}

- spoolFile:(const char *)filename
{
  [self notImplemented:_cmd];
  return self;
}

- (BOOL)canPrintRIB
{
  return NO;
}

//
// Setting up pages
//
- (BOOL)knowsPagesFirst:(int *)firstPageNum
    last:(int *)lastPageNum
{
  [self notImplemented:_cmd];
  return NO;
}

- (BOOL)getRect:(NXRect *)theRect
    forPage:(int)page
{
  [self notImplemented:_cmd];
  return NO;
}

- placePrintRect:(const NXRect *)aRect
    offset:(NXPoint *)location
{
  [self notImplemented:_cmd];
  return self;
}

- (float)heightAdjustLimit
{
  [self notImplemented:_cmd];
  return 0;
}

- (float)widthAdjustLimit
{
  [self notImplemented:_cmd];
  return 0;
}

//
// Writing conforming PostScript
//

// This section does nothing but return self for all of the methods.
// Actually outputing PostScript code is something that should be done
// in the DPS category.  So it'll be done there.  Some methods below
// are actually considered to be implemented because they just return
// self, according to the NS GenRef.

- beginPSOutput
{
  return self;
}

- beginPrologueBBox:(const NXRect *)boundingbox
    creationDate:(const char *)dateCreated
    createdBy:(const char *)anApplication
    fonts:(const char *)fontNames
    forWhom:(const char *)user
    pages:(int)numPages
    title:(const char *)aTitle
{
  return self;
}

- endHeaderComments
{
  return self;
}

- endPrologue
{
  return self;
}

- beginSetup
{
  return self;
}

- endSetup
{
  return self;
}

- adjustPageWidthNew:(float *)newRight
    left:(float)oldLeft
    right:(float)oldRight
    limit:(float)rightLimit
{
  return self;
}

- adjustPageHeightNew:(float *)newBottom
    top:(float)oldTop
    bottom:(float)oldBottom
    limit:(float)bottomLimit
{
  return self;
}

- beginPageSetupRect:(const NXRect *)aRect
    placement:(const NXPoint *)location
{
  return self;
}

// This method is complete.  It doesn't do anything except return self.
- drawSheetBorder:(float)width
    :(float)height
{
  return self;
}

// This method is complete.  It doesn't do anything except return self.
- drawPageBorder:(float)width
    :(float)height
{
  return self;
}

// This method is complete.  It doesn't do anything except return self.
- addToPageSetup
{
  return self;
}

- endPageSetup
{
  return self;
}

- endPage
{
  return self;
}

- beginTrailer
{
  return self;
}

- endTrailer
{
  return self;
}

- endPSOutput
{
  return self;
}

//
// Archiving
//
- awake
{
  [super awake];
  
  bounds = frame;
  NX_X(&bounds) = 0;
  NX_Y(&bounds) = 0;
  instancename = ViewInstanceName();
  return self;
}

- read:(NXTypedStream *)stream
{
    unsigned int autosizing, autoresizeSubviews;
    
    [super read:stream];
    
    NXReadRect(stream, &frame);
    bounds = frame;
    NX_X(&bounds) = 0;
    NX_Y(&bounds) = 0;
    objc_read_type(stream, "i", &autosizing);
    _vFlags.autosizing = autosizing & 0x3F;
    
#ifdef	RESIZE_DEBUG
    fprintf(stderr, "reading Autosizing flags: ");
    if (NX_NOTSIZABLE == _vFlags.autosizing)
    fprintf(stderr, "NX_NOTSIZABLE ");
    if (_vFlags.autosizing & NX_WIDTHSIZABLE)
    fprintf(stderr, "NX_WIDTHSIZABLE ");
    if (_vFlags.autosizing & NX_MINXMARGINSIZABLE)
    fprintf(stderr, "NX_MINXMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_MAXXMARGINSIZABLE)
    fprintf(stderr, "NX_MAXXMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_HEIGHTSIZABLE)
    fprintf(stderr, "NX_HEIGHTSIZABLE ");
    if (_vFlags.autosizing & NX_MINYMARGINSIZABLE)
    fprintf(stderr, "NX_MINYMARGINSIZABLE ");
    if (_vFlags.autosizing & NX_MAXYMARGINSIZABLE)
    fprintf(stderr, "NX_MAXYMARGINSIZABLE ");
    fprintf(stderr, "\n");
#endif	/* RESIZE_DEBUG */
    
    objc_read_type(stream, "i", &autoresizeSubviews);
    _vFlags.autoresizeSubviews = autoresizeSubviews & 0x01;
    objc_read_object(stream, &subviews);
    return self;
}

- write:(NXTypedStream *)stream
{
  [self notImplemented:_cmd];
  return self;
}



/*
 * From here on, stuff added to make it work right.  These shouldn't be public
 * methods.  Some of them don't really need to exist anymore.  But we'll deal
 * with all of that later.  -km
 */

- translateCoords:(NXEvent *)nx
{
    /* simply translate the y coordinates! */

    nx->location.y = bounds.size.height - nx->location.y;
    return self;
}


/* Archiving methods */
- awakeFromNib
{
    CustomView	*subview, *custom;
    int		i;
    
    i = [subviews count];
    while ( i-- ) {
	subview = [subviews objectAt:i];
	if ( [subview isKindOf:[CustomView class]] ) {
	    subview = [subview nibInstantiate];
	    custom = [subviews replaceObjectAt:i with:subview];
	    [custom free];
	} else {
	    [subview awakeFromNib];
	}
    }
    return self;
}

- (NXRect *)frame
{
    return &frame;
}

- _managedBy:parent
{
    void	*widget = [parent _widget];

    if ( !widget ) {
    	fprintf(stderr, "%s: parent widget not found\n", [self name]);
	return nil;
    }
    if ( [parent isKindOf:[View class]] ) {
	superview = parent;
	window = [parent window];
    }
    [self _init];
    return [self _managedBy:parent wid:widget];
}

- _setWindow:(Window *)aWindow
{
    return [self _setWindow:aWindow andSuperview:nil];
}

- _setWindow:(Window *)aWindow andSuperview:(View *)aView
{
    int		i;

    /* build window and superview chain */
    window = aWindow;
    superview = aView;
    i = [subviews count];
    while (i--)  [[subviews objectAt:i] _setWindow:aWindow andSuperview:self];

    return self;
}

- _manageChildren
{
    View	*view;
    int		i;

    i = [subviews count];
    while ( i-- ) {
	view = [subviews objectAt:i];
	[view _managedBy:self];
    }
    return self;
}

/* really, only boxes should call this method:  
 	Right now, only does a setFrame, but could require special 
	additions later... at first it did, maybe it will again...?
 */
- _setBorderRect:(NXRect *)brect
{
    [self setFrame:brect];
    return self;
}

@end
