NSGL fullscreen toggling

Sage
Posts: 1,403
Joined: 2005.07
Post: #1
This works mostly, it fades to black changes the screen res then fades into the opengl context, which is great (but took me way too long), the problem though is it works once.
If you go to fullscreen and back then try to go to fullscreen again it fades alright and looks like its working but at the end it jumps back to the previous screen res and there's no fullscreen context.

Some pointers would be very helpful because im not sure if what im doing here is even right at all, thanks in advance.

Code:
- (IBAction)toggleFullscreen:(id)sender
{
    CGError cgError;
    CGDisplayErr displayError;
    CGDisplayReservationInterval seconds;
    CGDisplayFadeReservationToken enterFullScreenToken;
    
    CFDictionaryRef desktopMode = CGDisplayCurrentMode(kCGDirectMainDisplay);
    CFDictionaryRef fullScreenMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 32, 640, 480, NULL);
    
    seconds = 2.0;
    
    if(fullscreen) {
        [fullScreenGLContext clearDrawable];
        [[self openGLContext] makeCurrentContext];
        
        CGDisplaySwitchToMode(kCGDirectMainDisplay, desktopMode);
        CGReleaseAllDisplays();
        fullscreen = NO;
    }
    else {
        CGAcquireDisplayFadeReservation(seconds, &enterFullScreenToken);
        
        cgError = CGDisplayFade(enterFullScreenToken, seconds, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, true);
        if(cgError != kCGErrorSuccess) {
            NSLog(@"Cannot fade display");
            CGReleaseDisplayFadeReservation(enterFullScreenToken);
            return;
        }
        CGReleaseDisplayFadeReservation(enterFullScreenToken);
        
        CGCaptureAllDisplays();
        if(displayError != CGDisplayNoErr) {
            NSLog(@"Cannot capture displays for fullscreen mode");
            return;
        }
        
        [fullScreenGLContext setFullScreen];
        [fullScreenGLContext makeCurrentContext];
        
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        [[NSOpenGLContext currentContext] flushBuffer];
        
        CGAcquireDisplayFadeReservation(seconds, &enterFullScreenToken);
        cgError = CGDisplayFade(enterFullScreenToken, seconds, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, true);
        if(cgError != kCGErrorSuccess) {
            NSLog(@"Cannot fade display 2");
            CGReleaseDisplayFadeReservation(enterFullScreenToken);
            return;
        }
        CGReleaseDisplayFadeReservation(enterFullScreenToken);
        
        fullscreen = YES;
    }
    
    [my_application setFullscreen:fullscreen];
}

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #2
Dig dig dig dig...
Last time I checked, this code works flawlessly. Just cut out the stuff about the click-catching window, the gl, and viewport initializations stuff.

Code:
CFDictionaryRef            savedMode;
        NSOpenGLContext            *fullscreenContext;
Code:
- (void)initFullscreen {
    NSOpenGLPixelFormatAttribute attr[] = {
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFAAccelerated,
        NSOpenGLPFANoRecovery,
        NSOpenGLPFASingleRenderer,
        NSOpenGLPFAColorSize,    CGDisplayBitsPerPixel(kCGDirectMainDisplay),
        NSOpenGLPFAScreenMask,     CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
        NSOpenGLPFAFullScreen,
        NULL };
    NSOpenGLPixelFormat    *nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; [nsglFormat autorelease];
    NSAssert(nsglFormat,@"Pixel format is nil"); // If the format isn't valid...

    fullscreenContext = [[NSOpenGLContext alloc] initWithFormat:nsglFormat shareContext:[self openGLContext]];
    [self initContext:fullscreenContext];
    //[fullscreenContext copyAttributesFromContext:[self openGLContext] withMask:GL_ALL_ATTRIB_BITS];
}

- (void)enterFullscreen {
    if (isFullscreen) return;
    NSRect frame = _viewRect;

    savedMode = CGDisplayCurrentMode(kCGDirectMainDisplay);
    
    CFDictionaryRef newMode =
        CGDisplayBestModeForParameters(kCGDirectMainDisplay,
                                       _viewDepth,
                                       frame.size.width, frame.size.height,
                                       NULL);
    NSAssert(newMode, @"Couldn't find display mode");


    //fade out
    CGDisplayReservationInterval seconds = 2.0;
    CGDisplayFadeReservationToken newToken;
    CGAcquireDisplayFadeReservation(seconds, &newToken); // reserve display hardware time

    CGDisplayFade(newToken,
                  0.3,                // 0.3 seconds
                  kCGDisplayBlendNormal,    // Starting state
                  kCGDisplayBlendSolidColor,     // Ending state
                  0.0, 0.0, 0.0,        // black
                  true);            // wait for completion

    CGDisplayCapture(kCGDirectMainDisplay);        //capture main display

    //Switch to selected resolution.
    CGDisplayErr err = CGDisplaySwitchToMode(kCGDirectMainDisplay, newMode);
    NSAssert(err == CGDisplayNoErr, @"Error switching resolution.");
    int newWidth = [[(NSDictionary*)newMode objectForKey:(NSString *)kCGDisplayWidth] intValue];
    int newHeight = [[(NSDictionary*)newMode objectForKey:(NSString *)kCGDisplayHeight] intValue];
    
    glDisable(GL_TEXTURE_2D);
    [self initFullscreen];
    [fullscreenContext setFullScreen];                //set openGL context to draw to screen
    glEnable(GL_TEXTURE_2D);
    isFullscreen = YES;


    frame.origin = NSMakePoint((newWidth-frame.size.width)/2,(newHeight-frame.size.height)/2);
    [fullscreenContext makeCurrentContext];
    glClearColor(0,0,0,0);
    
    glDisable(GL_SCISSOR_TEST);
    glDisable(GL_TEXTURE_2D);
    glClear(GL_COLOR_BUFFER_BIT);
    [fullscreenContext flushBuffer];
    glClear(GL_COLOR_BUFFER_BIT);
    [fullscreenContext flushBuffer];
    
    glEnable(GL_TEXTURE_2D);
    glClearColor([backgroundColor redComponent],
                 [backgroundColor greenComponent],
                 [backgroundColor blueComponent],
                 [backgroundColor alphaComponent]);
    glViewport((GLint)frame.origin.x,
            (GLint)frame.origin.y,
            (GLint)frame.size.width,
            (GLint)frame.size.height);

    glScissor((GLint)frame.origin.x,
            (GLint)frame.origin.y,
            (GLint)frame.size.width,
            (GLint)frame.size.height);
    glEnable(GL_SCISSOR_TEST);

    long enable[1] = {(long)1};
    long swapRect[4] =
      { (long)frame.origin.x,
        (long)frame.origin.y,
        (long)frame.size.width,
        (long)frame.size.height };
    [fullscreenContext setValues:swapRect forParameter:NSOpenGLCPSwapRectangle];
    [fullscreenContext setValues:enable forParameter:NSOpenGLCPSwapRectangleEnable];

    //setup orthographic camera
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(_viewRect.origin.x,
               _viewRect.origin.x+_viewRect.size.width,
               _viewRect.origin.y,
               _viewRect.origin.y+_viewRect.size.height);
    
    frame.origin.y -= newHeight;
    frame.origin.y += ([[NSScreen mainScreen] frame].size.height);
    NSWindow *FullScreenWindow = [[NSWindow alloc] initWithContentRect:frame
                                                             styleMask:NSBorderlessWindowMask
                                                               backing:NSBackingStoreBuffered
                                                                 defer:NO];
    _superView = [self superview];
    myFrame = [self frame];
    
    if(FullScreenWindow != nil) {
        [FullScreenWindow setTitle: @"eventCatcher"];
        [FullScreenWindow setReleasedWhenClosed: YES];
        [FullScreenWindow setContentView: self];
        [self setFrame:NSMakeRect(0,0,_viewRect.size.width,_viewRect.size.height)];
        [FullScreenWindow setLevel: CGShieldingWindowLevel()];
        [FullScreenWindow makeFirstResponder:self];
        [FullScreenWindow makeKeyAndOrderFront:self];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(exitFullscreen)
                                                     name:NSApplicationWillTerminateNotification
                                                   object:NSApp];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(applicationHide)
                                                     name:NSApplicationWillHideNotification
                                                   object:NSApp];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(applicationUnhide)
                                                     name:NSApplicationDidUnhideNotification
                                                   object:NSApp];
        //[CBCursor setConstrainsToRect:frame];

    }
    
    [self setMouseVisible:mouseIsVisible];
    [self display];
    
    CGDisplayFade(newToken,
                  0.5,                // 0.5 seconds
                  kCGDisplayBlendSolidColor,     // Starting state
                  kCGDisplayBlendNormal,    // Ending state
                  0.0, 0.0, 0.0,        // black
                  false);            // Don't wait for completion

    CGReleaseDisplayFadeReservation(newToken);

    [NSNotification postToDelegate:delegate
                      withSelector:@selector(viewDidEnterFullscreen:)
                          withName:CBViewDidEnterFullscreenNotification
                            object:self
                          userInfo:nil];

}


- (void)exitFullscreen {
    if (!isFullscreen) return;
    CGDisplayReservationInterval seconds = 2.0;
    CGDisplayFadeReservationToken newToken;
    CGAcquireDisplayFadeReservation(seconds, &newToken); // reserve display hardware time

    CGDisplayFade(newToken,
                  0.3,                // 0.3 seconds
                  kCGDisplayBlendNormal,    // Starting state
                  kCGDisplayBlendSolidColor,     // Ending state
                  0.0, 0.0, 0.0,        // black
                  true);            // wait for completion

    NSWindow *FullscreenWindow = [self window];
    [fullscreenContext clearDrawable];
    [FullscreenWindow close];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSApplicationWillTerminateNotification
                                                  object:NSApp];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSApplicationWillHideNotification
                                                  object:NSApp];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSApplicationDidUnhideNotification
                                                  object:NSApp];

    
    CGDisplaySwitchToMode(kCGDirectMainDisplay, savedMode);
    [_superView addSubview:self];
    [self setFrame:myFrame];
    [[self window] makeKeyAndOrderFront:self];
    
    isFullscreen = NO;
    
    //[CBCursor setConstrainsToRect:NSZeroRect];
    [self display];
    CGDisplayFade(newToken,
                  0.5,                // 0.5 seconds
                  kCGDisplayBlendSolidColor,     // Starting state
                  kCGDisplayBlendNormal,    // Ending state
                  0.0, 0.0, 0.0,        // black
                  true);            // Don't wait for completion

    CGReleaseDisplayFadeReservation(newToken);
    CGDisplayRelease(kCGDirectMainDisplay);

    [self setMouseVisible:mouseIsVisible];
    [fullscreenContext release];

    [NSNotification postToDelegate:delegate
                      withSelector:@selector(viewDidExitFullscreen:)
                          withName:CBViewDidExitFullscreenNotification
                            object:self
                          userInfo:nil];
}

- (void)applicationHide {
    if (!isFullscreen) return;
    CGDisplaySwitchToMode(kCGDirectMainDisplay, savedMode);
    [fullscreenContext clearDrawable];
    //[CBCursor setConstrainsToRect:NSZeroRect];
    [[self window] orderOut:self];
    CGDisplayRelease(kCGDirectMainDisplay);
}

- (void)applicationUnhide {
    if (!isFullscreen) return;
    NSRect frame = _viewRect;

    [NSApp activateIgnoringOtherApps:YES];
    
    CFDictionaryRef newMode =
        CGDisplayBestModeForParameters(kCGDirectMainDisplay,
                                       _viewDepth,
                                       frame.size.width, frame.size.height,
                                       NULL);

    //fade out
    CGDisplayReservationInterval seconds = 2.0;
    CGDisplayFadeReservationToken newToken;
    CGAcquireDisplayFadeReservation(seconds, &newToken); // reserve display hardware time

    CGDisplayFade(newToken,
                  0.3,                // 0.3 seconds
                  kCGDisplayBlendNormal,    // Starting state
                  kCGDisplayBlendSolidColor,     // Ending state
                  0.0, 0.0, 0.0,        // black
                  true);            // wait for completion

    CGDisplayCapture(kCGDirectMainDisplay);        //capture main display

    //Switch to selected resolution.
    /*CGDisplayErr err = */CGDisplaySwitchToMode(kCGDirectMainDisplay, newMode);
    int newWidth = [[(NSDictionary*)newMode objectForKey:(NSString *)kCGDisplayWidth] intValue];
    int newHeight = [[(NSDictionary*)newMode objectForKey:(NSString *)kCGDisplayHeight] intValue];

    frame.origin = NSMakePoint((newWidth-frame.size.width)/2,(newHeight-frame.size.height)/2);
    
    [fullscreenContext setFullScreen];                //set openGL context to draw to screen
    [[self window] makeKeyAndOrderFront:self];
    
    [fullscreenContext makeCurrentContext];
    glClearColor(0,0,0,0);

    glDisable(GL_SCISSOR_TEST);
    glDisable(GL_TEXTURE_2D);
    glClear(GL_COLOR_BUFFER_BIT);
    [fullscreenContext flushBuffer];
    glClear(GL_COLOR_BUFFER_BIT);
    [fullscreenContext flushBuffer];

    glEnable(GL_TEXTURE_2D);
    glClearColor([backgroundColor redComponent],
                 [backgroundColor greenComponent],
                 [backgroundColor blueComponent],
                 [backgroundColor alphaComponent]);

    glViewport((GLint)frame.origin.x,
               (GLint)frame.origin.y,
               (GLint)frame.size.width,
               (GLint)frame.size.height);
    
    glScissor((GLint)frame.origin.x,
              (GLint)frame.origin.y,
              (GLint)frame.size.width,
              (GLint)frame.size.height);
    glEnable(GL_SCISSOR_TEST);

    //[CBCursor setConstrainsToRect:frame];
    
    [self display];
    
    
    CGDisplayFade(newToken,
                  0.5,                // 0.5 seconds
                  kCGDisplayBlendSolidColor,     // Starting state
                  kCGDisplayBlendNormal,    // Ending state
                  0.0, 0.0, 0.0,        // black
                  false);            // Don't wait for completion

    CGReleaseDisplayFadeReservation(newToken);
}

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Sage
Posts: 1,403
Joined: 2005.07
Post: #4
Thanks guys! Smile
Its a lot of source code for me to try and understand just now but I think I can try and spot the difference between what im doing which is wrong and what the other sources are doing.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #5
I've taken to code to the bare minimum, it now just catures the display then changes the resolution. For some reason I am now not getting anything visual when in fullscreen mode.
Is there anything clearly wrong here or somthing i'm missing?

Code:
- (IBAction)toggleFullscreen:(id)sender
{
    CGError cgError;
    CGDisplayErr displayError;
    CGDisplayFadeReservationToken enterFullScreenToken;
    
    CFDictionaryRef fullScreenMode;
    
    if(fullscreen) {
        NSLog(@"small mode");
        [fullScreenGLContext clearDrawable];
        [[self openGLContext] makeCurrentContext];
        
        CGDisplaySwitchToMode(kCGDirectMainDisplay, desktopMode);
        CGReleaseAllDisplays();
        
        fullscreen = NO;
    }
    else {
        NSLog(@"Big mode");
        desktopMode = CGDisplayCurrentMode(kCGDirectMainDisplay); // desktopMode is an instance variable of the class so that It is kept for returning to later on
        fullScreenMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 32, 800, 600, NULL);
        
        CGCaptureAllDisplays();
        if(displayError != CGDisplayNoErr) {
            NSLog(@"Cannot capture displays for fullscreen mode");
            return;
        }
        
        displayError = CGDisplaySwitchToMode(kCGDirectMainDisplay, fullScreenMode);
        if(displayError != CGDisplayNoErr) {
            NSLog(@"Cannot switch to fullscreen mode");
            return;
        }
        
        [fullScreenGLContext setFullScreen];
        [fullScreenGLContext makeCurrentContext];
        
        [self drawGL];
        [[NSOpenGLContext currentContext] flushBuffer];
        fullscreen = YES;
    }
    
    [my_application setFullscreen:fullscreen];
}

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #6
maybe your -drawGL method is changing the context?

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #7
I did have to make sure to use the right clear context function in my draw method ([[NSOpenGLContext currentContext] flushBuffer]Wink.

I've fixed it now Im still not sure what was going wrong but several minor problems added up to just make it not work at all, thanks for all the help again though Smile

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Modern fullscreen toggling Fenris 3 2,822 Dec 17, 2007 02:27 PM
Last Post: Fenris