Custom View drawn twice?

  • I have a text view that contains a custom view which in turn contains
    an imageview and draws an image and a drop shadow.  During selection
    the bits of the view which are not fully opaque (the shadow and the
    image) sometimes draw twice, producing a darker shadow than I want.
    This seems to alternate with normal looking drawing, so when I select
    text the shadow flickers between regular and darker along with the
    other non-opaque bits in the image.  My method for drawing the shadow
    looks like this:

    - (void)drawRect:(NSRect)rect {
    NSAffineTransform *xform = [NSAffineTransform transform];

    [NSGraphicsContext saveGraphicsState];

    [xform translateXBy:imageViewOrigin.x yBy:imageViewOrigin.y];
    [xform rotateByDegrees:rotation];
    [xform concat];

    NSShadow *imageShadow = [[NSShadow alloc] init];
    [imageShadow setShadowOffset:NSMakeSize(0,-5)];
    [imageShadow setShadowBlurRadius:5];
    [imageShadow setShadowColor:[NSColor blackColor]];

    [imageShadow set];
    [[NSColor whiteColor] set];
    [NSBezierPath fillRect:[imageView bounds]];
    [NSGraphicsContext restoreGraphicsState];

    [imageShadow release];
    }

    I should note that the selection area does not overlap the view
    (custom shaped text container).  Anyone have any ideas as to what
    might be going wrong?

    ->Ben

    --
    Ben Lachman
    Acacia Tree Software

    http://acaciatreesoftware.com

    <blachman...>
    740.590.0009
  • Well, I finally was able to get this solved, but not to my
    satisfaction.  What I'm having to do is this:

    if( ! NSContainsRect(rect, [self visibleRect]) && ! NSEqualRects
    (rect,[self visibleRect]) ) {
      [self setNeedsDisplayInRect:[self bounds]];
      [self displayIfNeededIgnoringOpacity];

      return;
    }

    which in my opinion is a really dirt hack and I'd love to find a
    better (real?) solution.  I'm pretty sure I'm just drawing twice
    between flushing the buffer, but I'm not sure how to debug it or
    prevent it.  Anyone run into something like this?

    Thanks,
    ->Ben
    --
    Ben Lachman
    Acacia Tree Software

    http://acaciatreesoftware.com

    <blachman...>
    740.590.0009

    On Feb 21, 2008, at 1:23 AM, Ben Lachman wrote:

    > I have a text view that contains a custom view which in turn
    > contains an imageview and draws an image and a drop shadow.  During
    > selection the bits of the view which are not fully opaque (the
    > shadow and the image) sometimes draw twice, producing a darker
    > shadow than I want.  This seems to alternate with normal looking
    > drawing, so when I select text the shadow flickers between regular
    > and darker along with the other non-opaque bits in the image.  My
    > method for drawing the shadow looks like this:
    >
    > - (void)drawRect:(NSRect)rect {
    > NSAffineTransform *xform = [NSAffineTransform transform];
    >
    > [NSGraphicsContext saveGraphicsState];
    >
    > [xform translateXBy:imageViewOrigin.x yBy:imageViewOrigin.y];
    > [xform rotateByDegrees:rotation];
    > [xform concat];
    >
    > NSShadow *imageShadow = [[NSShadow alloc] init];
    > [imageShadow setShadowOffset:NSMakeSize(0,-5)];
    > [imageShadow setShadowBlurRadius:5];
    > [imageShadow setShadowColor:[NSColor blackColor]];
    >
    > [imageShadow set];
    > [[NSColor whiteColor] set];
    > [NSBezierPath fillRect:[imageView bounds]];
    > [NSGraphicsContext restoreGraphicsState];
    >
    > [imageShadow release];
    > }
    >
    > I should note that the selection area does not overlap the view
    > (custom shaped text container).  Anyone have any ideas as to what
    > might be going wrong?
  • I don't see a problem in your drawRect: code, so it'd be in something
    you haven't posted.  Perhaps you could post a sample application?

    One possibility is that your -isOpaque method returns YES, so the view
    system thinks it doesn't have to redraw your superview before asking
    you to draw.

    If you're subclassing NSView, you'd have to opt-in to return YES from
    -isOpaque, but if you're subclassing a deeper AppKit view class, it
    may already be marked as opaque.

    -Ken

    On Fri, Feb 29, 2008 at 11:55 AM, Ben Lachman <blachman...> wrote:
    > Well, I finally was able to get this solved, but not to my
    > satisfaction.  What I'm having to do is this:
    >
    > if( ! NSContainsRect(rect, [self visibleRect]) && ! NSEqualRects
    > (rect,[self visibleRect]) ) {
    > [self setNeedsDisplayInRect:[self bounds]];
    > [self displayIfNeededIgnoringOpacity];
    >
    > return;
    > }
    >
    > which in my opinion is a really dirt hack and I'd love to find a
    > better (real?) solution.  I'm pretty sure I'm just drawing twice
    > between flushing the buffer, but I'm not sure how to debug it or
    > prevent it.  Anyone run into something like this?
    >
    > Thanks,
    >
    > ->Ben
    > --
    > Ben Lachman
    > Acacia Tree Software
    >
    > http://acaciatreesoftware.com
    >
    > <blachman...>
    > 740.590.0009
    >
    >
    >
    >
    > On Feb 21, 2008, at 1:23 AM, Ben Lachman wrote:
    >
    >> I have a text view that contains a custom view which in turn
    >> contains an imageview and draws an image and a drop shadow.  During
    >> selection the bits of the view which are not fully opaque (the
    >> shadow and the image) sometimes draw twice, producing a darker
    >> shadow than I want.  This seems to alternate with normal looking
    >> drawing, so when I select text the shadow flickers between regular
    >> and darker along with the other non-opaque bits in the image.  My
    >> method for drawing the shadow looks like this:
    >>
    >> - (void)drawRect:(NSRect)rect {
    >> NSAffineTransform *xform = [NSAffineTransform transform];
    >>
    >> [NSGraphicsContext saveGraphicsState];
    >>
    >> [xform translateXBy:imageViewOrigin.x yBy:imageViewOrigin.y];
    >> [xform rotateByDegrees:rotation];
    >> [xform concat];
    >>
    >> NSShadow *imageShadow = [[NSShadow alloc] init];
    >> [imageShadow setShadowOffset:NSMakeSize(0,-5)];
    >> [imageShadow setShadowBlurRadius:5];
    >> [imageShadow setShadowColor:[NSColor blackColor]];
    >>
    >> [imageShadow set];
    >> [[NSColor whiteColor] set];
    >> [NSBezierPath fillRect:[imageView bounds]];
    >> [NSGraphicsContext restoreGraphicsState];
    >>
    >> [imageShadow release];
    >> }
    >>
    >> I should note that the selection area does not overlap the view
    >> (custom shaped text container).  Anyone have any ideas as to what
    >> might be going wrong?

    >
  • So I tried this and wasn't able to get it to display the behavior,
    which makes me assume the issue must be the interaction with the rest
    of the views in the hierarchy.  If I turn off all calls to
    setNeedsDisplay... I don't get the double drawing, but I also don't
    get UI updates.  The view hierarchy looks like this:

    BackgroundView (Opaque) -> (scrollview) -> RVTextView (Not Opaque)  -
    > MagnetClipView (not Opaque, draws drop shadow)    -> MagnetView (not
    opaque)
                  -> RVImageView (subclass of NSImageView)

    So I set logging on all setNeedsDisplay... and drawRect methods in
    this hierarchy as well as logging on every time through the run loop
    (break,log & continue on __CFRunLoopRun) during a selection drag (the
    action that causes the double drawing effect) and this is what I get
    (cleaned up for readability).  The thing I wonder about is the number
    of setNeedDisplayInRect: calls to BackgroundView--they all seem to be
    called from propagating dirty rect from non-opaque subviews though.
    Other than that I don't see anything that looks odd.  Anyone?

    **************Top of Run loop******************
    17.617 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 56},
    {400, 16}}
    17.618 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 438},
    {243, 32}}
    17.618 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 470},
    {400, 24}}
    17.619 RVApp[25760] BackgroundView: drawRect:
    17.629 RVApp[25760] TextView: drawRect:
    17.635 RVApp[25760] MagnetClipView: setNeedsDisplayInRect:{{0, 0},
    {160, 200}}
    17.636 RVApp[25760] MagnetClipView: drawRect:
    17.638 RVApp[25760] MagnetClipView: setsNeedsDisplay:NO
    17.638 RVApp[25760] RVImageView: drawRect:
    17.649 RVApp[25760] MagnetView: drawRect:
    17.653 RVApp[25760] BackgroundView: setsNeedsDisplay:NO
    **************Top of Run loop******************
    17.830 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 72},
    {400, 382}}
    17.830 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{261,
    454}, {157, 16}}
    17.831 RVApp[25760] BackgroundView: drawRect:
    17.842 RVApp[25760] TextView: drawRect:
    17.848 RVApp[25760] MagnetClipView: setNeedsDisplayInRect:{{0, 0},
    {160, 176}}
    17.849 RVApp[25760] MagnetClipView: drawRect:
    17.852 RVApp[25760] RVImageView: setNeedsDisplayInRect:{{0, 0}, {128,
    128}}
    17.852 RVApp[25760] MagnetView: setNeedsDisplayInRect:{{0, 0}, {160,
    176}}
    17.852 RVApp[25760] RVImageView: drawRect:
    17.859 RVApp[25760] RVImageView: setsNeedsDisplay:NO
    17.860 RVApp[25760] MagnetView: drawRect:
    17.861 RVApp[25760] BackgroundView: setsNeedsDisplay:NO
    17.862 RVApp[25760] MagnetClipView: setsNeedsDisplay:NO
    17.862 RVApp[25760] MagnetView: setsNeedsDisplay:NO
    **************Top of Run loop******************
    18.075 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 56},
    {400, 16}}
    18.075 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 232},
    {400, 144}}
    18.075 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 454},
    {243, 16}}
    18.075 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 470},
    {400, 24}}
    18.076 RVApp[25760] BackgroundView: drawRect:
    18.085 RVApp[25760] TextView: drawRect:
    18.091 RVApp[25760] MagnetClipView: setNeedsDisplayInRect:{{0, 0},
    {160, 200}}
    18.091 RVApp[25760] MagnetClipView: drawRect:
    18.094 RVApp[25760] MagnetClipView: setsNeedsDisplay:NO
    18.094 RVApp[25760] RVImageView: drawRect:
    18.101 RVApp[25760] MagnetView: drawRect:
    18.102 RVApp[25760] BackgroundView: setsNeedsDisplay:NO
    **************Top of Run loop******************
    18.263 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 72},
    {400, 176}}
    18.264 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 376},
    {400, 78}}
    18.264 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{261,
    454}, {157, 16}}
    18.265 RVApp[25760] BackgroundView: drawRect:
    18.275 RVApp[25760] TextView: drawRect:
    18.281 RVApp[25760] MagnetClipView: setNeedsDisplayInRect:{{0, 0},
    {160, 176}}
    18.282 RVApp[25760] MagnetClipView: drawRect:
    18.285 RVApp[25760] RVImageView: setNeedsDisplayInRect:{{0, 0}, {128,
    128}}
    18.285 RVApp[25760] MagnetView: setNeedsDisplayInRect:{{0, 0}, {160,
    176}}
    18.285 RVApp[25760] RVImageView: drawRect:
    18.293 RVApp[25760] RVImageView: setsNeedsDisplay:NO
    18.294 RVApp[25760] MagnetView: drawRect:
    18.296 RVApp[25760] BackgroundView: setsNeedsDisplay:NO
    18.298 RVApp[25760] MagnetClipView: setsNeedsDisplay:NO
    18.298 RVApp[25760] MagnetView: setsNeedsDisplay:NO
    **************Top of Run loop******************
    18.460 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 56},
    {400, 16}}
    18.460 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 152},
    {400, 32}}
    18.460 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 248},
    {400, 128}}
    18.460 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 454},
    {243, 16}}
    18.460 RVApp[25760] BackgroundView: setNeedsDisplayInRect:{{18, 470},
    {400, 24}}
    18.461 RVApp[25760] BackgroundView: drawRect:
    18.473 RVApp[25760] TextView: drawRect:
    18.479 RVApp[25760] MagnetClipView: setNeedsDisplayInRect:{{0, 0},
    {160, 200}}
    18.479 RVApp[25760] MagnetClipView: drawRect:
    18.481 RVApp[25760] MagnetClipView: setsNeedsDisplay:NO
    18.481 RVApp[25760] RVImageView: drawRect:
    18.489 RVApp[25760] MagnetView: drawRect:
    18.490 RVApp[25760] BackgroundView: setsNeedsDisplay:NO
    **************Top of Run loop******************

    --
    Ben Lachman
    Acacia Tree Software

    http://acaciatreesoftware.com

    <blachman...>
    740.590.0009

    On Feb 29, 2008, at 5:52 PM, Ken Ferry wrote:

    > I don't see a problem in your drawRect: code, so it'd be in something
    > you haven't posted.  Perhaps you could post a sample application?
    >
    > One possibility is that your -isOpaque method returns YES, so the view
    > system thinks it doesn't have to redraw your superview before asking
    > you to draw.
    >
    > If you're subclassing NSView, you'd have to opt-in to return YES from
    > -isOpaque, but if you're subclassing a deeper AppKit view class, it
    > may already be marked as opaque.
    >
  • Am 29.02.2008 um 20:55 schrieb Ben Lachman:
    > [self displayIfNeededIgnoringOpacity];

      Is there a particular reason why you're calling this method? Won't
    plain old -displayIfNeeded do the job?

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.zathras.de
  • displayIfNeededIgnoringOpacity goes back up the view hierarchy
    looking for an opaque superview to start drawing with. Doing so was
    causing an infinite drawing loop.  I'm pretty sure this is because
    you're not really supposed to be calling setNeedsDisplay...: and
    displayIfNeeded...: within your drawRect: method.  In any case it was
    a nasty hack to get correct looking functionality and I'm actually
    more interested in figuring out what is causing the double drawing
    than hack a fix on top of it.

    ->Ben
    --
    Ben Lachman
    Acacia Tree Software

    http://acaciatreesoftware.com

    <blachman...>
    740.590.0009

    On Mar 3, 2008, at 5:38 AM, Uli Kusterer wrote:

    > Am 29.02.2008 um 20:55 schrieb Ben Lachman:
    >> [self displayIfNeededIgnoringOpacity];
    >
    >
    > Is there a particular reason why you're calling this method? Won't
    > plain old -displayIfNeeded do the job?
    >
    > Cheers,
    > -- Uli Kusterer
    > "The Witnesses of TeachText are everywhere..."
    > http://www.zathras.de
    >
    >
    >
    >
    >
  • I think I finally solved this while chatting with Wil Shipley earlier
    this evening.  Wil mentioned sometimes needing to display from the
    opaque ancestor which is basically what I was trying to do with the
    code Uli questioned.  The way I was doing it was only partially
    successful at best.  Given Wil's hints, I added the following to my
    drawing code and my drawing glitches are no more:

    - (void)drawRect:(NSRect)rect {
    static BOOL toggle = YES;

    if( toggle ) {
      toggle = NO;
      [[self opaqueAncestor] display];
      return;
    } else {
      toggle = YES;
    }
    ...

    Thanks to all those who responded to my original post.  Hopefully
    this will help someone else down the road.

    ->Ben
    --
    Ben Lachman
    Acacia Tree Software

    http://acaciatreesoftware.com

    <blachman...>
    740.590.0009

    On Mar 5, 2008, at 4:22 PM, Ben Lachman wrote:

    > displayIfNeededIgnoringOpacity goes back up the view hierarchy
    > looking for an opaque superview to start drawing with. Doing so was
    > causing an infinite drawing loop.  I'm pretty sure this is because
    > you're not really supposed to be calling setNeedsDisplay...: and
    > displayIfNeeded...: within your drawRect: method.  In any case it
    > was a nasty hack to get correct looking functionality and I'm
    > actually more interested in figuring out what is causing the double
    > drawing than hack a fix on top of it.
    >
    > On Mar 3, 2008, at 5:38 AM, Uli Kusterer wrote:
    >
    >> Am 29.02.2008 um 20:55 schrieb Ben Lachman:
    >>> [self displayIfNeededIgnoringOpacity];
    >>
    >>
    >> Is there a particular reason why you're calling this method?
    >> Won't plain old -displayIfNeeded do the job?
    >>
  • On 14.03.2008, at 09:11, Ben Lachman wrote:
    > I think I finally solved this while chatting with Wil Shipley
    > earlier this evening.  Wil mentioned sometimes needing to display
    > from the opaque ancestor which is basically what I was trying to do
    > with the code Uli questioned.  The way I was doing it was only
    > partially successful at best.  Given Wil's hints, I added the
    > following to my drawing code and my drawing glitches are no more:
    >
    > - (void)drawRect:(NSRect)rect {
    > static BOOL toggle = YES;
    >
    > if( toggle ) {
    > toggle = NO;
    > [[self opaqueAncestor] display];
    > return;
    > } else {
    > toggle = YES;
    > }
    > ...

      Urk. That does not sound like a good idea at all. display is
    supposed to eventually call -drawRect:, and also the -drawRect: of any
    subviews that might need redrawing. Calling display inside -drawRect:
    is essentially requesting an endless recursion from Apple. Even if it
    works now due to some fortunate optimization or whatever Apple put in,
    I don't think this is a good idea going forward.

      I think what you really should do is do this call wherever you call -
    setNeedsDisplay: or -display: on your view. *not* in -drawRect:. Even
    then, it's highly dubious code that should not be required at all. If
    you have to call display on the opaque ancestor and calling display on
    the view itself doesn't work, I would definitely recommend you file a
    bug on that, ideally including a sample application that reproduces
    the issue.

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.zathras.de
  • On 14.03.2008, at 09:11, Ben Lachman wrote:
    > I think I finally solved this while chatting with Wil Shipley
    > earlier this evening.  Wil mentioned sometimes needing to display
    > from the opaque ancestor which is basically what I was trying to do
    > with the code Uli questioned.  The way I was doing it was only
    > partially successful at best.  Given Wil's hints, I added the
    > following to my drawing code and my drawing glitches are no more:
    >
    > - (void)drawRect:(NSRect)rect {
    > static BOOL toggle = YES;
    >
    > if( toggle ) {
    > toggle = NO;
    > [[self opaqueAncestor] display];
    > return;
    > } else {
    > toggle = YES;
    > }
    > ...

      I think you're supposed to call display outside of drawRect, not
    inside. What you're doing here is requesting the OS to draw everything
    twice, once with toggle YES, once with toggle NO. Only your view
    doesn't draw as long as toggle is YES.

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.zathras.de
  • On 14.03.2008, at 13:11, Uli Kusterer wrote:
    > On 14.03.2008, at 09:11, Ben Lachman wrote:
    >> I think I finally solved this while chatting with Wil Shipley
    >> earlier this evening.  Wil mentioned sometimes needing to display
    >> from the opaque ancestor which is basically what I was trying to do
    >> with the code Uli questioned.  The way I was doing it was only
    >> partially successful at best.  Given Wil's hints, I added the
    >> following to my drawing code and my drawing glitches are no more:
    >>
    >> - (void)drawRect:(NSRect)rect {
    >> static BOOL toggle = YES;
    >>
    >> if( toggle ) {
    >> toggle = NO;
    >> [[self opaqueAncestor] display];
    >> return;
    >> } else {
    >> toggle = YES;
    >> }
    >> ...
    >
    > Urk. That does not sound like a good idea at all. display is
    > supposed to eventually call -drawRect:, and also the -drawRect: of
    > any subviews that might need redrawing. Calling display inside -
    > drawRect: is essentially requesting an endless recursion from Apple.
    > Even if it works now due to some fortunate optimization or whatever
    > Apple put in, I don't think this is a good idea going forward.

      Oh great, so this message *did* get through even though I canceled
    and it didn't get saved to my outbox...

      Anyway, of course your "toggle" prevents the endless loop, but it's
    still an ugly hack. Not to mention a bad way to name such a variable.
    So, why exactly do you have a subview in a text view, and why aren't
    you a text attachment or something similar? And isn't there a better
    place to call display than drawRect:? Have you made sure your text
    view and your image view and any of the partially transparent views in
    between are not marked opaque like Ken Ferry suggested? Or if you want
    some of them to be opaque, have you made sure they actually erase
    their background appropriately?

      I really think you're just going about this the wrong way. What
    exactly are you trying to do in a high-level way? Are you trying to do
    text layout that flows around an image? Are you trying to show text
    behind an image? Are you trying to embed a picture in an image?

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.zathras.de
  • Le 14 mars 08 à 13:54, Uli Kusterer a écrit :

    > On 14.03.2008, at 13:11, Uli Kusterer wrote:
    >> On 14.03.2008, at 09:11, Ben Lachman wrote:
    >>> I think I finally solved this while chatting with Wil Shipley
    >>> earlier this evening.  Wil mentioned sometimes needing to display
    >>> from the opaque ancestor which is basically what I was trying to
    >>> do with the code Uli questioned.  The way I was doing it was only
    >>> partially successful at best.  Given Wil's hints, I added the
    >>> following to my drawing code and my drawing glitches are no more:
    >>>
    >>> - (void)drawRect:(NSRect)rect {
    >>> static BOOL toggle = YES;
    >>>
    >>> if( toggle ) {
    >>> toggle = NO;
    >>> [[self opaqueAncestor] display];
    >>> return;
    >>> } else {
    >>> toggle = YES;
    >>> }
    >>> ...
    >>
    >> Urk. That does not sound like a good idea at all. display is
    >> supposed to eventually call -drawRect:, and also the -drawRect: of
    >> any subviews that might need redrawing. Calling display inside -
    >> drawRect: is essentially requesting an endless recursion from
    >> Apple. Even if it works now due to some fortunate optimization or
    >> whatever Apple put in, I don't think this is a good idea going
    >> forward.
    >
    >
    > Oh great, so this message *did* get through even though I canceled
    > and it didn't get saved to my outbox...
    >
    > Anyway, of course your "toggle" prevents the endless loop, but it's
    > still an ugly hack. Not to mention a bad way to name such a
    > variable. So, why exactly do you have a subview in a text view, and
    > why aren't you a text attachment or something similar? And isn't
    > there a better place to call display than drawRect:? Have you made
    > sure your text view and your image view and any of the partially
    > transparent views in between are not marked opaque like Ken Ferry
    > suggested? Or if you want some of them to be opaque, have you made
    > sure they actually erase their background appropriately?
    >
    > I really think you're just going about this the wrong way. What
    > exactly are you trying to do in a high-level way? Are you trying to
    > do text layout that flows around an image? Are you trying to show
    > text behind an image? Are you trying to embed a picture in an image?
    >
    > Cheers,

    There is a nasty side effet here. You can have only ONE instance of
    your view, else the static variable will be in an inconsistent state.
    If you want to use this strange hack in your view, use at least an
    ivar instead of a static var.
  • On Mar 14, 2008, at 8:54 AM, Uli Kusterer wrote:

    > Oh great, so this message *did* get through even though I canceled
    > and it didn't get saved to my outbox...
    >
    > Anyway, of course your "toggle" prevents the endless loop, but
    > it's still an ugly hack. Not to mention a bad way to name such a
    > variable. So, why exactly do you have a subview in a text view, and
    > why aren't you a text attachment or something similar? And isn't
    > there a better place to call display than drawRect:? Have you made
    > sure your text view and your image view and any of the partially
    > transparent views in between are not marked opaque like Ken Ferry
    > suggested? Or if you want some of them to be opaque, have you made
    > sure they actually erase their background appropriately?

    I realize that it's an ugly hack.  If I could find a way to remove
    that code without completely restructuring my view hierarchy again
    and rewriting huge chunks of my code, I'd do it.  However I've been
    through every call to setNeedsDisplay, looked at every view's
    opaqueness, done my best to create a sample app and subclassed each
    view in the hierarchy to look at when they're being drawn and set
    needing display, etc. and I haven't been able to find a solution
    other than never calling setNeedsDisplay... on the textview which
    isn't really an option since the textview does need displayed at
    times. At this point I've probably spent a full week debugging this
    this issue and I don't really have much more time for it.  Which
    leads me to the fact that if this works, while I know I shouldn't
    need to do things this way, I need to use it for the time being.

    > I really think you're just going about this the wrong way. What
    > exactly are you trying to do in a high-level way? Are you trying to
    > do text layout that flows around an image? Are you trying to show
    > text behind an image? Are you trying to embed a picture in an image?

    The high-level task I'm trying to accomplish is a rotated image view
    with a drop shadow in the top right corner of my text view that
    selection and text flow around.  I can't use a text attachment
    because I need to support several bindings on the image view as well
    as other subviews.  My solution for this is to use a custom text
    container to control the flow of the text and selection around the
    area where the subview is laid out.  If anyone has a better way of
    doing this I'd love to hear it.  I haven't been amazingly pleased
    with this approach as it obviously has been less than headache free.

    A more important point perhaps is that I don't really see why a text
    view can't have a subview.  It seems that it should behave like any
    other view in the view hierarchy that is given a subview--it displays
    itself and then its children, handles first responder and various
    other things.  And if it is the case that an NSTextView is some kind
    of "leaf" view that can't have any child views then it should
    probably be documented as such.  FTW, are there any other views that
    can't viably have children?

    Thanks for the thoughts,

    ->Ben