SDL_cocoaevents.m (10648B)
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#include "SDL_assert.h" 29 30@interface SDLApplication : NSApplication 31 32- (void)terminate:(id)sender; 33 34@end 35 36@implementation SDLApplication 37 38// Override terminate to handle Quit and System Shutdown smoothly. 39- (void)terminate:(id)sender 40{ 41 SDL_SendQuit(); 42} 43 44@end // SDLApplication 45 46/* setAppleMenu disappeared from the headers in 10.4 */ 47@interface NSApplication(NSAppleMenu) 48- (void)setAppleMenu:(NSMenu *)menu; 49@end 50 51@interface SDLAppDelegate : NSObject <NSApplicationDelegate> { 52@public 53 BOOL seenFirstActivate; 54} 55 56- (id)init; 57@end 58 59@implementation SDLAppDelegate : NSObject 60- (id)init 61{ 62 self = [super init]; 63 if (self) { 64 seenFirstActivate = NO; 65 [[NSNotificationCenter defaultCenter] addObserver:self 66 selector:@selector(focusSomeWindow:) 67 name:NSApplicationDidBecomeActiveNotification 68 object:nil]; 69 } 70 71 return self; 72} 73 74- (void)dealloc 75{ 76 [[NSNotificationCenter defaultCenter] removeObserver:self]; 77 [super dealloc]; 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 SDL_Window *window = device->windows; 95 int i; 96 for (i = 0; i < device->num_displays; ++i) { 97 SDL_Window *fullscreen_window = device->displays[i].fullscreen_window; 98 if (fullscreen_window) { 99 if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) { 100 SDL_RestoreWindow(fullscreen_window); 101 } 102 return; 103 } 104 } 105 106 if (window->flags & SDL_WINDOW_MINIMIZED) { 107 SDL_RestoreWindow(window); 108 } else { 109 SDL_RaiseWindow(window); 110 } 111 } 112} 113 114- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename 115{ 116 return (BOOL)SDL_SendDropFile([filename UTF8String]); 117} 118@end 119 120static SDLAppDelegate *appDelegate = nil; 121 122static NSString * 123GetApplicationName(void) 124{ 125 NSString *appName; 126 127 /* Determine the application name */ 128 appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; 129 if (!appName) { 130 appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; 131 } 132 133 if (![appName length]) { 134 appName = [[NSProcessInfo processInfo] processName]; 135 } 136 137 return appName; 138} 139 140static void 141CreateApplicationMenus(void) 142{ 143 NSString *appName; 144 NSString *title; 145 NSMenu *appleMenu; 146 NSMenu *serviceMenu; 147 NSMenu *windowMenu; 148 NSMenu *viewMenu; 149 NSMenuItem *menuItem; 150 NSMenu *mainMenu; 151 152 if (NSApp == nil) { 153 return; 154 } 155 156 mainMenu = [[NSMenu alloc] init]; 157 158 /* Create the main menu bar */ 159 [NSApp setMainMenu:mainMenu]; 160 161 [mainMenu release]; /* we're done with it, let NSApp own it. */ 162 mainMenu = nil; 163 164 /* Create the application menu */ 165 appName = GetApplicationName(); 166 appleMenu = [[NSMenu alloc] initWithTitle:@""]; 167 168 /* Add menu items */ 169 title = [@"About " stringByAppendingString:appName]; 170 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; 171 172 [appleMenu addItem:[NSMenuItem separatorItem]]; 173 174 [appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","]; 175 176 [appleMenu addItem:[NSMenuItem separatorItem]]; 177 178 serviceMenu = [[NSMenu alloc] initWithTitle:@""]; 179 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""]; 180 [menuItem setSubmenu:serviceMenu]; 181 182 [NSApp setServicesMenu:serviceMenu]; 183 [serviceMenu release]; 184 185 [appleMenu addItem:[NSMenuItem separatorItem]]; 186 187 title = [@"Hide " stringByAppendingString:appName]; 188 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; 189 190 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; 191 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; 192 193 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; 194 195 [appleMenu addItem:[NSMenuItem separatorItem]]; 196 197 title = [@"Quit " stringByAppendingString:appName]; 198 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; 199 200 /* Put menu into the menubar */ 201 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; 202 [menuItem setSubmenu:appleMenu]; 203 [[NSApp mainMenu] addItem:menuItem]; 204 [menuItem release]; 205 206 /* Tell the application object that this is now the application menu */ 207 [NSApp setAppleMenu:appleMenu]; 208 [appleMenu release]; 209 210 211 /* Create the window menu */ 212 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; 213 214 /* Add menu items */ 215 [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; 216 217 [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; 218 219 /* Put menu into the menubar */ 220 menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; 221 [menuItem setSubmenu:windowMenu]; 222 [[NSApp mainMenu] addItem:menuItem]; 223 [menuItem release]; 224 225 /* Tell the application object that this is now the window menu */ 226 [NSApp setWindowsMenu:windowMenu]; 227 [windowMenu release]; 228 229 230 /* Add the fullscreen view toggle menu option, if supported */ 231 if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) { 232 /* Create the view menu */ 233 viewMenu = [[NSMenu alloc] initWithTitle:@"View"]; 234 235 /* Add menu items */ 236 menuItem = [viewMenu addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"]; 237 [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask]; 238 239 /* Put menu into the menubar */ 240 menuItem = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""]; 241 [menuItem setSubmenu:viewMenu]; 242 [[NSApp mainMenu] addItem:menuItem]; 243 [menuItem release]; 244 245 [viewMenu release]; 246 } 247} 248 249void 250Cocoa_RegisterApp(void) 251{ @autoreleasepool 252{ 253 /* This can get called more than once! Be careful what you initialize! */ 254 ProcessSerialNumber psn; 255 256 if (!GetCurrentProcess(&psn)) { 257 TransformProcessType(&psn, kProcessTransformToForegroundApplication); 258 SetFrontProcess(&psn); 259 } 260 261 if (NSApp == nil) { 262 [SDLApplication sharedApplication]; 263 SDL_assert(NSApp != nil); 264 265 if ([NSApp mainMenu] == nil) { 266 CreateApplicationMenus(); 267 } 268 [NSApp finishLaunching]; 269 NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys: 270 [NSNumber numberWithBool:NO], @"AppleMomentumScrollSupported", 271 [NSNumber numberWithBool:NO], @"ApplePressAndHoldEnabled", 272 [NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState", 273 nil]; 274 [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; 275 [appDefaults release]; 276 } 277 if (NSApp && !appDelegate) { 278 appDelegate = [[SDLAppDelegate alloc] init]; 279 280 /* If someone else has an app delegate, it means we can't turn a 281 * termination into SDL_Quit, and we can't handle application:openFile: 282 */ 283 if (![NSApp delegate]) { 284 [(NSApplication *)NSApp setDelegate:appDelegate]; 285 } else { 286 appDelegate->seenFirstActivate = YES; 287 } 288 } 289}} 290 291void 292Cocoa_PumpEvents(_THIS) 293{ @autoreleasepool 294{ 295 /* Update activity every 30 seconds to prevent screensaver */ 296 if (_this->suspend_screensaver) { 297 SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; 298 Uint32 now = SDL_GetTicks(); 299 if (!data->screensaver_activity || 300 SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { 301 UpdateSystemActivity(UsrActivity); 302 data->screensaver_activity = now; 303 } 304 } 305 306 for ( ; ; ) { 307 NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ]; 308 if ( event == nil ) { 309 break; 310 } 311 312 switch ([event type]) { 313 case NSLeftMouseDown: 314 case NSOtherMouseDown: 315 case NSRightMouseDown: 316 case NSLeftMouseUp: 317 case NSOtherMouseUp: 318 case NSRightMouseUp: 319 case NSLeftMouseDragged: 320 case NSRightMouseDragged: 321 case NSOtherMouseDragged: /* usually middle mouse dragged */ 322 case NSMouseMoved: 323 case NSScrollWheel: 324 Cocoa_HandleMouseEvent(_this, event); 325 break; 326 case NSKeyDown: 327 case NSKeyUp: 328 case NSFlagsChanged: 329 Cocoa_HandleKeyEvent(_this, event); 330 break; 331 default: 332 break; 333 } 334 /* Pass through to NSApp to make sure everything stays in sync */ 335 [NSApp sendEvent:event]; 336 } 337}} 338 339#endif /* SDL_VIDEO_DRIVER_COCOA */ 340 341/* vi: set ts=4 sw=4 expandtab: */