NSOpenGLView redraw problems after a window is closed and re-opened.

Q: I have an instance of an NSOpenGLView subclass that doesn't draw correctly after I close and then re-open its window. What's happening, and how can I fix it?

A: In Mac OS X, version 10.3 and earlier, NSOpenGLView doesn't redraw properly after the window it's in has been closed and re-opened. One easy work-around is to remove the view from the view hierarchy, and then re-insert it.

In the code below, MyOpenGLView registers itself for the notification that its window will close. In the -prepareForWindowClosing: method, the view also registers itself for the NSWindowDidUpdateNotification, which will be sent when the window is re-opened.

The -windowReopened: method retains the view, removes it from the view hierarchy, then re-inserts it and balances the -retain message with a -release message.

Listing 1: Resetting NSOpenGLView's drawing environment


@implementation MyOpenGLView

- (void) awakeFromNib
{
    [[NSNotificationCenter defaultCenter]
      addObserver: self
         selector: @selector(prepareForWindowClosing:)
             name: NSWindowWillCloseNotification
           object: [self window]];
}

- (void) prepareForWindowClosing:(NSNotification *) notification
{
      // we'll need to know the next time the window updates,
      // which will be when it's re-opened.
    [[NSNotificationCenter defaultCenter]
      addObserver: self
         selector: @selector(windowReopened:)
             name: NSWindowDidUpdateNotification
           object: [self window]];

      // Make sure we draw right away when the window is re-opened.
    [self setNeedsDisplay:YES];
}

- (void) windowReopened:(NSNotification *)aNotification
{
      // Fix up the state of the NSOpenGLView by removing it from and
      // re-adding it to the view hierarchy
    NSView *superviewStash = [self superview];

    [self retain];  // Must retain before removing from superview
    [self removeFromSuperview];
    [superviewStash addSubview:self];
    [self release]; // Must balance all -retain and -release messages.

      // After this, we don't care about window exposed notifications, so
      // we'll stop listening for them
    [[NSNotificationCenter defaultCenter]
      removeObserver:self
                name:NSWindowDidUpdateNotification
              object:[self window]];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@end

Document Revision History

DateNotes
2004-12-03Workaround for NSOpenGLView failure to draw after its window is closed and re-opened.

Posted: 2004-12-03


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.