src/video/cocoa/SDL_cocoaevents.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8237 6cc44a5d9eef
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 #include "SDL_timer.h"
    25 
    26 #include "SDL_cocoavideo.h"
    27 #include "../../events/SDL_events_c.h"
    28 
    29 #if !defined(UsrActivity) && defined(__LP64__) && !defined(__POWER__)
    30 /*
    31  * Workaround for a bug in the 10.5 SDK: By accident, OSService.h does
    32  * not include Power.h at all when compiling in 64bit mode. This has
    33  * been fixed in 10.6, but for 10.5, we manually define UsrActivity
    34  * to ensure compilation works.
    35  */
    36 #define UsrActivity 1
    37 #endif
    38 
    39 /* setAppleMenu disappeared from the headers in 10.4 */
    40 @interface NSApplication(NSAppleMenu)
    41 - (void)setAppleMenu:(NSMenu *)menu;
    42 @end
    43 
    44 @interface SDLAppDelegate : NSObject {
    45 @public
    46     BOOL seenFirstActivate;
    47 }
    48 
    49 - (id)init;
    50 @end
    51 
    52 @implementation SDLAppDelegate : NSObject
    53 - (id)init
    54 {
    55     self = [super init];
    56 
    57     if (self) {
    58         seenFirstActivate = NO;
    59         [[NSNotificationCenter defaultCenter] addObserver:self
    60                                                  selector:@selector(focusSomeWindow:)
    61                                                      name:NSApplicationDidBecomeActiveNotification
    62                                                    object:nil];
    63     }
    64 
    65     return self;
    66 }
    67 
    68 - (void)dealloc
    69 {
    70     [[NSNotificationCenter defaultCenter] removeObserver:self];
    71     [super dealloc];
    72 }
    73 
    74 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
    75 {
    76     SDL_SendQuit();
    77     return NSTerminateCancel;
    78 }
    79 
    80 - (void)focusSomeWindow:(NSNotification *)aNotification
    81 {
    82     /* HACK: Ignore the first call. The application gets a
    83      * applicationDidBecomeActive: a little bit after the first window is
    84      * created, and if we don't ignore it, a window that has been created with
    85      * SDL_WINDOW_MINIZED will ~immediately be restored.
    86      */
    87     if (!seenFirstActivate) {
    88         seenFirstActivate = YES;
    89         return;
    90     }
    91 
    92     SDL_VideoDevice *device = SDL_GetVideoDevice();
    93     if (device && device->windows)
    94     {
    95         SDL_Window *window = device->windows;
    96         int i;
    97         for (i = 0; i < device->num_displays; ++i)
    98         {
    99             SDL_Window *fullscreen_window = device->displays[i].fullscreen_window;
   100             if (fullscreen_window)
   101             {
   102                 if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) {
   103                     SDL_RestoreWindow(fullscreen_window);
   104                 }
   105                 return;
   106             }
   107         }
   108 
   109         if (window->flags & SDL_WINDOW_MINIMIZED) {
   110             SDL_RestoreWindow(window);
   111         } else {
   112             SDL_RaiseWindow(window);
   113         }
   114     }
   115 }
   116 
   117 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
   118 {
   119     return (BOOL)SDL_SendDropFile([filename UTF8String]);
   120 }
   121 @end
   122 
   123 static SDLAppDelegate *appDelegate = nil;
   124 
   125 static NSString *
   126 GetApplicationName(void)
   127 {
   128     NSDictionary *dict;
   129     NSString *appName = 0;
   130 
   131     /* Determine the application name */
   132     dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
   133     if (dict)
   134         appName = [dict objectForKey: @"CFBundleName"];
   135 
   136     if (![appName length])
   137         appName = [[NSProcessInfo processInfo] processName];
   138 
   139     return appName;
   140 }
   141 
   142 static void
   143 CreateApplicationMenus(void)
   144 {
   145     NSString *appName;
   146     NSString *title;
   147     NSMenu *appleMenu;
   148     NSMenu *serviceMenu;
   149     NSMenu *windowMenu;
   150     NSMenu *viewMenu;
   151     NSMenuItem *menuItem;
   152 
   153     if (NSApp == nil) {
   154         return;
   155     }
   156     
   157     /* Create the main menu bar */
   158     [NSApp setMainMenu:[[NSMenu alloc] init]];
   159 
   160     /* Create the application menu */
   161     appName = GetApplicationName();
   162     appleMenu = [[NSMenu alloc] initWithTitle:@""];
   163 
   164     /* Add menu items */
   165     title = [@"About " stringByAppendingString:appName];
   166     [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
   167 
   168     [appleMenu addItem:[NSMenuItem separatorItem]];
   169 
   170     [appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","];
   171 
   172     [appleMenu addItem:[NSMenuItem separatorItem]];
   173 
   174     serviceMenu = [[NSMenu alloc] initWithTitle:@""];
   175     menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
   176     [menuItem setSubmenu:serviceMenu];
   177 
   178     [NSApp setServicesMenu:serviceMenu];
   179     [serviceMenu release];
   180 
   181     [appleMenu addItem:[NSMenuItem separatorItem]];
   182 
   183     title = [@"Hide " stringByAppendingString:appName];
   184     [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
   185 
   186     menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
   187     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
   188 
   189     [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
   190 
   191     [appleMenu addItem:[NSMenuItem separatorItem]];
   192 
   193     title = [@"Quit " stringByAppendingString:appName];
   194     [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
   195 
   196     /* Put menu into the menubar */
   197     menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
   198     [menuItem setSubmenu:appleMenu];
   199     [[NSApp mainMenu] addItem:menuItem];
   200     [menuItem release];
   201 
   202     /* Tell the application object that this is now the application menu */
   203     [NSApp setAppleMenu:appleMenu];
   204     [appleMenu release];
   205 
   206 
   207     /* Create the window menu */
   208     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
   209 
   210     /* Add menu items */
   211     [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
   212 
   213     [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
   214 
   215     /* Put menu into the menubar */
   216     menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
   217     [menuItem setSubmenu:windowMenu];
   218     [[NSApp mainMenu] addItem:menuItem];
   219     [menuItem release];
   220 
   221     /* Tell the application object that this is now the window menu */
   222     [NSApp setWindowsMenu:windowMenu];
   223     [windowMenu release];
   224 
   225 
   226     /* Add the fullscreen view toggle menu option, if supported */
   227     if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) {
   228         /* Create the view menu */
   229         viewMenu = [[NSMenu alloc] initWithTitle:@"View"];
   230 
   231         /* Add menu items */
   232         menuItem = [viewMenu addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
   233         [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
   234 
   235         /* Put menu into the menubar */
   236         menuItem = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""];
   237         [menuItem setSubmenu:viewMenu];
   238         [[NSApp mainMenu] addItem:menuItem];
   239         [menuItem release];
   240 
   241         [viewMenu release];
   242     }
   243 }
   244 
   245 void
   246 Cocoa_RegisterApp(void)
   247 {
   248     /* This can get called more than once! Be careful what you initialize! */
   249     ProcessSerialNumber psn;
   250     NSAutoreleasePool *pool;
   251 
   252     if (!GetCurrentProcess(&psn)) {
   253         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
   254         SetFrontProcess(&psn);
   255     }
   256 
   257     pool = [[NSAutoreleasePool alloc] init];
   258     if (NSApp == nil) {
   259         [NSApplication sharedApplication];
   260 
   261         if ([NSApp mainMenu] == nil) {
   262             CreateApplicationMenus();
   263         }
   264         [NSApp finishLaunching];
   265         NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"AppleMomentumScrollSupported"];
   266         [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
   267 
   268     }
   269     if (NSApp && !appDelegate) {
   270         appDelegate = [[SDLAppDelegate alloc] init];
   271 
   272         /* If someone else has an app delegate, it means we can't turn a
   273          * termination into SDL_Quit, and we can't handle application:openFile:
   274          */
   275         if (![NSApp delegate]) {
   276             [NSApp setDelegate:appDelegate];
   277         } else {
   278             appDelegate->seenFirstActivate = YES;
   279         }
   280     }
   281     [pool release];
   282 }
   283 
   284 void
   285 Cocoa_PumpEvents(_THIS)
   286 {
   287     NSAutoreleasePool *pool;
   288 
   289     /* Update activity every 30 seconds to prevent screensaver */
   290     if (_this->suspend_screensaver) {
   291         SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
   292         Uint32 now = SDL_GetTicks();
   293         if (!data->screensaver_activity ||
   294             SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
   295             UpdateSystemActivity(UsrActivity);
   296             data->screensaver_activity = now;
   297         }
   298     }
   299 
   300     pool = [[NSAutoreleasePool alloc] init];
   301     for ( ; ; ) {
   302         NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
   303         if ( event == nil ) {
   304             break;
   305         }
   306 
   307         switch ([event type]) {
   308         case NSLeftMouseDown:
   309         case NSOtherMouseDown:
   310         case NSRightMouseDown:
   311         case NSLeftMouseUp:
   312         case NSOtherMouseUp:
   313         case NSRightMouseUp:
   314         case NSLeftMouseDragged:
   315         case NSRightMouseDragged:
   316         case NSOtherMouseDragged: /* usually middle mouse dragged */
   317         case NSMouseMoved:
   318         case NSScrollWheel:
   319             Cocoa_HandleMouseEvent(_this, event);
   320             break;
   321         case NSKeyDown:
   322         case NSKeyUp:
   323         case NSFlagsChanged:
   324             Cocoa_HandleKeyEvent(_this, event);
   325             break;
   326         default:
   327             break;
   328         }
   329         /* Pass through to NSApp to make sure everything stays in sync */
   330         [NSApp sendEvent:event];
   331     }
   332     [pool release];
   333 }
   334 
   335 #endif /* SDL_VIDEO_DRIVER_COCOA */
   336 
   337 /* vi: set ts=4 sw=4 expandtab: */