objective-ccocoaopenglopenglcontext

Cannot set view for NSOpenGLContext


(Sorry in advance for the seemingly large amount of code here) I'm trying to create a window with an OpenGL context with Cocoa, but I'm finding that I am unable to set the view property of the NSOpenGLContext that I create.

I cannot simply use an NSOpenGLView, since I need to interface with a C++ drawing backend and use multiple contexts. The code I post here is just me trying to get to grips with handling NSOpenGLContexts, but it will be used in a much larger project. This is why I'm instantiating NSApplication and my NSWindow manually rather than through a NIB/NSApplicationMain.

My main.m file:

#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "Delegate.h"

int main(int argc, const char * argv[]) {

    [NSApplication sharedApplication];
    Delegate* dlg = [[Delegate alloc] init];

    [NSApp setDelegate:dlg];

    [NSApp run];

    return 0;
}

I then have my delegate class, and I'll refrain from posting the file Delegate.h since it'll be pretty obvious what's there given these contents of Delegate.m:

#import <Cocoa/Cocoa.h>
#import "Delegate.h"
#import <OpenGL/gl.h>

@implementation Delegate

- (void) draw
{
    [self.glContext makeCurrentContext];

    glClearColor(1, 0, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    [self.glContext flushBuffer];
}


- (void) applicationDidFinishLaunching:(NSNotification *)notification
{
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

    self.win = [[NSWindow alloc] initWithContentRect:NSMakeRect(30, 30, 300, 200)
                                           styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask
                                             backing:NSBackingStoreBuffered
                                               defer:YES];



    NSOpenGLPixelFormatAttribute glAttributes[] =
    {
        NSOpenGLPFAColorSize, 24,
        NSOpenGLPFAAlphaSize, 8,
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFAAccelerated,
        0
    };

    self.glContext = [[NSOpenGLContext alloc] initWithFormat:[[NSOpenGLPixelFormat alloc] initWithAttributes:glAttributes]
                                                shareContext:nil];
    [self.glContext setView: [self.win contentView]];
    printf("view:%p, contentView:%p\n", [self.glContext view], [self.win contentView]);


    [self.win makeKeyAndOrderFront:nil];

    [NSTimer
     scheduledTimerWithTimeInterval:.1
     target:self
     selector:@selector(draw)
     userInfo:nil
     repeats:YES];
}

The window opens just fine. I am able to tell that -applicationDidFinishLaunching and -draw are being called. The window shows up empty however.

The printf call shows that the view property of self.glContext is equal to the address 0x0. I see no documentation or other forum threads about why I would be unable to set the drawable object of an NSOpenGLContext.

I have tried putting the NSOpenGLContext in its own subclass of NSView and adding that subclass as a subview of the window's content view, but with no success.


Solution

  • Try setting the defer parameter of -[NSWindow initWithContentRect:...] to NO. You may also wish to set the GL context's view after ordering the window on-screen.

    Basically, -[NSOpenGLContext setView:] can fail if the view's window doesn't yet have a "device". When that's happened to me, it usually logs a message to the console about an "invalid drawable", but I haven't checked in recent versions of the OS.

    Also, you need to register as an observer of the NSViewGlobalFrameDidChangeNotification notification from the view and, in response, call -update on the GL context object.