- Main Page
- Namespaces
- Classes
- Files

- File List

# AppController.mm

    00001
    00002 //
    00003 // SFML - Simple and Fast Multimedia Library
    00004 // Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com)
    00005 //
    00006 // This software is provided 'as-is', without any express or implied warranty.
    00007 // In no event will the authors be held liable for any damages arising from the use of this software.
    00008 //
    00009 // Permission is granted to anyone to use this software for any purpose,
    00010 // including commercial applications, and to alter it and redistribute it freely,
    00011 // subject to the following restrictions:
    00012 //
    00013 // 1. The origin of this software must not be misrepresented;
    00014 //    you must not claim that you wrote the original software.
    00015 //    If you use this software in a product, an acknowledgment
    00016 //    in the product documentation would be appreciated but is not required.
    00017 //
    00018 // 2. Altered source versions must be plainly marked as such,
    00019 //    and must not be misrepresented as being the original software.
    00020 //
    00021 // 3. This notice may not be removed or altered from any source distribution.
    00022 //
    00024
    00025
    00027 // Headers
    00029 #import <SFML/Window/Cocoa/AppController.h>
    00030 #import <SFML/Window/Cocoa/GLKit.h>
    00031 #import <SFML/System.hpp>
    00032 #import <ApplicationServices/ApplicationServices.h>
    00033 #import <iostream>
    00034
    00035
    00036 // AppController singleton object
    00037 static AppController *shared = nil;
    00038
    00039
    00040 /* setAppleMenu disappeared from the headers in 10.4 */
    00041 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
    00042 @interface NSApplication (SFML)
    00043 - (void)setAppleMenu:(NSMenu *)menu;
    00044 @end
    00045 #endif
    00046
    00047 #define ENABLE_FADE_OPERATIONS 1
    00048
    00049 @implementation NSApplication (SFML)
    00050
    00051 - (void)setRunning:(BOOL)flag
    00052 {
    00053     // Note: _running is a short, not a BOOL
    00054     if (flag)
    00055         _running = 1;
    00056     else
    00057         _running = 0;
    00058 }
    00059
    00060 @end
    00061
    00062
    00063 @implementation AppController
    00064
    00065
    00072 - (id)init
    00073 {
    00074     self = [super init];
    00075
    00076     if (self != nil) {
    00077         myOwningEventLoop = NO;
    00078
    00079         // Save the desktop mode
    00080         myDesktopMode = sf::VideoMode::GetDesktopMode();
    00081         myPrevMode = myDesktopMode;
    00082
    00083         // Make the app autorelease pool
    00084         myMainPool = [[NSAutoreleasePool alloc] init];
    00085
    00086         // Don't go on if the user handles the app
    00087         if (![NSApp isRunning])
    00088         {
    00089             // Force our application to appear in the Dock and make it able
    00090             // to get focus (even when it's a raw executable)
    00091             ProcessSerialNumber psn;
    00092
    00093             if (!GetCurrentProcess(&psn)) {
    00094                 TransformProcessType(&psn, kProcessTransformToForegroundApplication);
    00095                 SetFrontProcess(&psn);
    00096             }
    00097
    00098             // Make the app
    00099             [NSApplication sharedApplication];
    00100
    00101             NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    00102             // I want to go back to the desktop mode
    00103             // if we've a fullscreen window when hiding
    00104             [nc addObserver:self
    00105                    selector:@selector(applicationWillHide:)
    00106                        name:NSApplicationWillHideNotification
    00107                      object:NSApp];
    00108
    00109             // And restore de fullscreen mode when unhiding
    00110             [nc addObserver:self
    00111                    selector:@selector(applicationWillUnhide:)
    00112                        name:NSApplicationWillUnhideNotification
    00113                      object:NSApp];
    00114
    00115             // Go back to desktop mode before exit
    00116             [nc addObserver:self
    00117                    selector:@selector(applicationWillTerminate:)
    00118                        name:NSApplicationWillTerminateNotification
    00119                      object:NSApp];
    00120
    00121             if ([NSApp mainMenu] == nil) {
    00122                 [self makeMenuBar];
    00123             }
    00124         }
    00125     }
    00126
    00127     return self;
    00128 }
    00129
    00130
    00134 - (void)dealloc
    00135 {
    00136     [[NSNotificationCenter defaultCenter] removeObserver:self];
    00137     [myFullscreenWrapper release];
    00138     [super dealloc];
    00139 }
    00140
    00141
    00145 + (AppController *)sharedController
    00146 {
    00147     if (nil == shared)
    00148         shared = [[AppController alloc] init];
    00149
    00150     return shared;
    00151 }
    00152
    00153
    00157 - (void)applicationWillHide:(NSNotification *)aNotification
    00158 {
    00159     if (myFullscreenWrapper) {
    00160         myPrevMode = sf::VideoMode::GetDesktopMode();
    00161
    00162         CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay,
    00163                                                                       myDesktopMode.BitsPerPixel,
    00164                                                                       myDesktopMode.Width,
    00165                                                                       myDesktopMode.Height,
    00166                                                                       NULL);
    00167
    00168         // Fade to black screen
    00169         [self doFadeOperation:FillScreen time:0.2f sync:true];
    00170
    00171         // Make the full screen window unvisible
    00172         [[myFullscreenWrapper window] setAlphaValue:0.0f];
    00173
    00174         // Switch to the wished display mode
    00175         CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode);
    00176
    00177         // Fade to normal screen
    00178         [self doFadeOperation:CleanScreen time:0.5f sync:false];
    00179     }
    00180 }
    00181
    00182
    00186 - (void)applicationWillUnhide:(NSNotification *)aNotification
    00187 {
    00188     if (myFullscreenWrapper) {
    00189         CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay,
    00190                                                                       myPrevMode.BitsPerPixel,
    00191                                                                       myPrevMode.Width,
    00192                                                                       myPrevMode.Height,
    00193                                                                       NULL);
    00194
    00195         // Fade to a black screen
    00196         [self doFadeOperation:FillScreen time:0.5f sync:true];
    00197         [NSMenu setMenuBarVisible:NO];
    00198
    00199         // Switch to the wished display mode
    00200         CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode);
    00201
    00202         // Show the fullscreen window if existing
    00203         if (myFullscreenWrapper)
    00204         {
    00205                 [[myFullscreenWrapper window] setAlphaValue:1.0f];
    00206                 [[myFullscreenWrapper window] center];
    00207         }
    00208
    00209         // Fade to normal screen
    00210         [self doFadeOperation:CleanScreen time:0.5f sync:false];
    00211     }
    00212 }
    00213
    00214
    00215 - (void)applicationWillTerminate:(NSNotification *)aNotification
    00216 {
    00217     if (myFullscreenWrapper)
    00218         [self setFullscreenWindow:nil mode:NULL];
    00219
    00220     // FIXME: should I really do this ? what about the user owned windows ?
    00221     // And is this really useful as the application is about to exit ?
    00222     [NSApp makeWindowsPerform:@selector(close) inOrder:NO];
    00223 }
    00224
    00228 - (void)makeMenuBar
    00229 {
    00230     // Source taken from SDL 1.3
    00231
    00232     NSString *appName = nil;
    00233     NSString *title = nil;
    00234     NSMenu *appleMenu = nil;
    00235     NSMenu *fileMenu = nil;
    00236     NSMenu *windowMenu = nil;
    00237     NSMenuItem *menuItem = nil;
    00238     NSMenuItem *quitMenuItem = nil;
    00239
    00240     // Determine the application name
    00241     appName = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"CFBundleName"];
    00242
    00243     if (![appName length])
    00244         appName = [[NSProcessInfo processInfo] processName];
    00245
    00246
    00247     // Create the main menu bar
    00248     [NSApp setMainMenu:[[NSMenu alloc] init]];
    00249
    00250     // Create the application menu
    00251     appleMenu = [[NSMenu alloc] initWithTitle:@""];
    00252
    00253     // Put menu items
    00254     // + 'About' menu item
    00255     title = [@"About " stringByAppendingString:appName];
    00256     [appleMenu addItemWithTitle:title
    00257                          action:@selector(orderFrontStandardAboutPanel:)
    00258                   keyEquivalent:@""];
    00259
    00260     [appleMenu addItem:[NSMenuItem separatorItem]];
    00261
    00262     // + 'Hide' menu item
    00263     title = [@"Hide " stringByAppendingString:appName];
    00264     [appleMenu addItemWithTitle:title
    00265                          action:@selector(hide:)
    00266                   keyEquivalent:@"h"];
    00267
    00268     // + 'Hide other' menu item
    00269     menuItem = reinterpret_cast <NSMenuItem *> ([appleMenu addItemWithTitle:@"Hide Others"
    00270                                                                 action:@selector(hideOtherApplications:)
    00271                                                          keyEquivalent:@"h"]);
    00272     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
    00273
    00274     // + 'Show all' menu item
    00275     [appleMenu addItemWithTitle:@"Show All"
    00276                          action:@selector(unhideAllApplications:)
    00277                   keyEquivalent:@""];
    00278
    00279     [appleMenu addItem:[NSMenuItem separatorItem]];
    00280
    00281     // + 'Quit' menu item
    00282     title = [@"Quit " stringByAppendingString:appName];
    00283     quitMenuItem = [[[NSMenuItem alloc]
    00284                      initWithTitle:title
    00285                      action:@selector(terminate:)
    00286                      keyEquivalent:@"q"] autorelease];
    00287     //[quitMenuItem setTarget:self];
    00288     [appleMenu addItem:quitMenuItem];
    00289
    00290     // Put the menu into the menubar
    00291     menuItem = [[NSMenuItem alloc]
    00292                 initWithTitle:@""
    00293                 action:nil
    00294                 keyEquivalent:@""];
    00295     [menuItem setSubmenu:appleMenu];
    00296     [[NSApp mainMenu] addItem:menuItem];
    00297     [menuItem release];
    00298
    00299     // Tell the application object that this is now the application menu
    00300     [NSApp setAppleMenu:appleMenu];
    00301     [appleMenu release];
    00302
    00303     // 'File' menu
    00304     fileMenu = [[NSMenu alloc]
    00305                 initWithTitle:@"File"];
    00306
    00307     // + 'Close' menu item
    00308     menuItem = [[NSMenuItem alloc]
    00309                 initWithTitle:@"Close"
    00310                 action:@selector(performClose:)
    00311                 keyEquivalent:@"w"];
    00312     [fileMenu addItem:menuItem];
    00313     [menuItem release];
    00314
    00315     // + 'File' menu item (head)
    00316     menuItem = [[NSMenuItem alloc]
    00317                 initWithTitle:@"File"
    00318                 action:nil
    00319                 keyEquivalent:@""];
    00320     [menuItem setSubmenu:fileMenu];
    00321     [[NSApp mainMenu] addItem:menuItem];
    00322     [menuItem release];
    00323
    00324     // 'Window' menu
    00325     windowMenu = [[NSMenu alloc]
    00326                   initWithTitle:@"Window"];
    00327
    00328     // + 'Minimize' menu item
    00329     menuItem = [[NSMenuItem alloc]
    00330                 initWithTitle:@"Minimize"
    00331                 action:@selector(performMiniaturize:)
    00332                 keyEquivalent:@"m"];
    00333     [windowMenu addItem:menuItem];
    00334     [menuItem release];
    00335
    00336     // + 'Window' menu item (head)
    00337     menuItem = [[NSMenuItem alloc]
    00338                 initWithTitle:@"Window"
    00339                 action:nil keyEquivalent:@""];
    00340     [menuItem setSubmenu:windowMenu];
    00341     [[NSApp mainMenu] addItem:menuItem];
    00342     [menuItem release];
    00343
    00344     // Tell the application object that this is now the window menu
    00345     [NSApp setWindowsMenu:windowMenu];
    00346     [windowMenu release];
    00347 }
    00348
    00349
    00355 - (void)processEvents
    00356 {
    00357     // Check there is a run loop
    00358     if (![NSApp isRunning])
    00359     {
    00360         // Get the ownershipt of event handling if not and run
    00361         [NSApp finishLaunching];
    00362         [NSApp setRunning:YES];
    00363         myOwningEventLoop = YES;
    00364     }
    00365
    00366     // Clean the autorelease pool
    00367     [myMainPool release];
    00368     myMainPool = [[NSAutoreleasePool alloc] init];
    00369
    00370     NSEvent *event = nil;
    00371
    00372     if (myOwningEventLoop)
    00373     {
    00374         // Minimal event loop
    00375         while (nil != (event = [NSApp nextEventMatchingMask:NSAnyEventMask
    00376                                                   untilDate:nil
    00377                                                      inMode:NSDefaultRunLoopMode
    00378                                                     dequeue:YES]))
    00379         {
    00380             [NSApp sendEvent:event];
    00381         }
    00382     }
    00383 }
    00384
    00385
    00390 - (void)setFullscreenWindow:(WindowWrapper *)aWrapper mode:(sf::VideoMode *)fullscreenMode
    00391 {
    00392     // If we have a fullscreen window and want to remove it
    00393     if (aWrapper == nil && myFullscreenWrapper)
    00394     {
    00395         // Get the CoreGraphics display mode according to the desktop mode
    00396         CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay,
    00397                                                                       myDesktopMode.BitsPerPixel,
    00398                                                                       myDesktopMode.Width,
    00399                                                                       myDesktopMode.Height,
    00400                                                                       NULL);
    00401
    00402 #if ENABLE_FADE_OPERATIONS
    00403         // Fade to black screen
    00404         [self doFadeOperation:FillScreen time:0.2f sync:true];
    00405 #endif
    00406
    00407         // Switch to the desktop display mode
    00408         CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode);
    00409
    00410         // Close the window
    00411         [[myFullscreenWrapper window] close];
    00412
    00413         // Show the menu bar
    00414         [NSMenu setMenuBarVisible:YES];
    00415
    00416 #if ENABLE_FADE_OPERATIONS
    00417         // Fade to normal screen
    00418         [self doFadeOperation:CleanScreen time:0.5f sync:true];
    00419 #endif
    00420
    00421         // Release the saved window wrapper
    00422         myFullscreenWrapper = nil;
    00423     }
    00424     else if (aWrapper)
    00425     {
    00426         assert(fullscreenMode != NULL);
    00427
    00428         // Get the CoreGraphics display mode according to the given sf mode
    00429         CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay,
    00430                                                                       fullscreenMode->BitsPerPixel,
    00431                                                                       fullscreenMode->Width,
    00432                                                                       fullscreenMode->Height,
    00433                                                                       NULL);
    00434
    00435 #if ENABLE_FADE_OPERATIONS
    00436         // Fade to a black screen
    00437         [self doFadeOperation:FillScreen time:0.5f sync:true];
    00438 #endif
    00439
    00440         if (!myFullscreenWrapper)
    00441         {
    00442             // Hide the main menu bar
    00443             [NSMenu setMenuBarVisible:NO];
    00444         }
    00445
    00446         if (myPrevMode != *fullscreenMode)
    00447         {
    00448             // Switch to the wished display mode
    00449             CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode);
    00450         }
    00451
    00452         if (myFullscreenWrapper)
    00453         {
    00454             [[myFullscreenWrapper window] close];
    00455         }
    00456
    00457         // Open and center the window
    00458         [[aWrapper window] makeKeyAndOrderFront:nil];
    00459         [[aWrapper window] center];
    00460
    00461 #if ENABLE_FADE_OPERATIONS
    00462         // Fade to normal screen
    00463         [self doFadeOperation:CleanScreen time:0.2f sync:false];
    00464 #endif
    00465
    00466         // Save the fullscreen wrapper
    00467         myFullscreenWrapper = aWrapper;
    00468     }
    00469     else
    00470     {
    00471         std::cerr << "Inconcistency error for arguments given to -[AppController setFullscreenWindow:mode:]" << std::endl;
    00472     }
    00473 }
    00474
    00475
    00484 - (void) doFadeOperation:(int)operation time:(float)time sync:(bool)sync
    00485 {
    00486     static CGDisplayFadeReservationToken prevToken = kCGDisplayFadeReservationInvalidToken;
    00487     CGDisplayFadeReservationToken token = prevToken;
    00488
    00489     CGError result = 0, capture = 0;
    00490
    00491     if (operation == FillScreen) {
    00492         // Get access for the fade operation
    00493         result = CGAcquireDisplayFadeReservation((int)(3 + time), &token);
    00494
    00495         if (!result) {
    00496             // Capture display but do not fill the screen with black
    00497             // so that we can see the fade operation
    00498             capture = CGDisplayCaptureWithOptions(kCGDirectMainDisplay, kCGCaptureNoFill);
    00499
    00500             if (!capture) {
    00501                 // Do the increasing fade operation
    00502                 CGDisplayFade(token, time,
    00503                               kCGDisplayBlendNormal,
    00504                               kCGDisplayBlendSolidColor,
    00505                               0.0f, 0.0f, 0.0f, sync);
    00506
    00507                 // Now, release the non black-filling capture
    00508                 CGDisplayRelease(kCGDirectMainDisplay);
    00509
    00510                 // And capture with filling
    00511                 // so that we don't see the switching in the meantime
    00512                 CGDisplayCaptureWithOptions(kCGDirectMainDisplay, kCGCaptureNoOptions);
    00513             }
    00514
    00515             prevToken = token;
    00516         }
    00517     } else if (operation == CleanScreen) {
    00518         // Get access for the fade operation
    00519         if (token == kCGDisplayFadeReservationInvalidToken)
    00520             result = CGAcquireDisplayFadeReservation((int)(3 + time), &token);
    00521
    00522         if (!result) {
    00523             if (!capture) {
    00524                 // Release the black-filling capture
    00525                 CGDisplayRelease(kCGDirectMainDisplay);
    00526
    00527                 // Capture the display but do not fill with black (still for the fade operation)
    00528                 CGDisplayCaptureWithOptions(kCGDirectMainDisplay, kCGCaptureNoFill);
    00529
    00530                 // Do the decreasing fading
    00531                 CGDisplayFade(token, time,
    00532                               kCGDisplayBlendSolidColor,
    00533                               kCGDisplayBlendNormal,
    00534                               0.0f, 0.0f, 0.0f, sync);
    00535
    00536                 // Release the fade operation token
    00537                 CGReleaseDisplayFadeReservation(token);
    00538
    00539                 // Invalidate the given token
    00540                 prevToken = kCGDisplayFadeReservationInvalidToken;
    00541             }
    00542
    00543             // Release the captured display
    00544             CGDisplayRelease(kCGDirectMainDisplay);
    00545         }
    00546     }
    00547 }
    00548
    00549
    00553 - (const sf::VideoMode&)desktopMode
    00554 {
    00555     return myDesktopMode;
    00556 }
    00557
    00558 @end
    00559

:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::