1// This file is part of VSTGUI. It is subject to the license terms 2// in the LICENSE file found in the top-level directory of this 3// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE 4 5#import "../../../../lib/platform/mac/cocoa/cocoahelpers.h" 6#import "../../../include/iappdelegate.h" 7#import "../../../include/iapplication.h" 8#import "../../application.h" 9#import "../../genericalertbox.h" 10#import "../../shareduiresources.h" 11#import "../../window.h" 12#import "VSTGUICommand.h" 13#import "macasync.h" 14#import "maccommondirectories.h" 15#import "macpreference.h" 16#import "macutilities.h" 17#import "macwindow.h" 18#import <Cocoa/Cocoa.h> 19 20#if __has_feature(nullability) == 0 21static_assert (false, "Need newer clang compiler!"); 22#endif 23 24//------------------------------------------------------------------------ 25@interface VSTGUIApplicationDelegate : NSObject <NSApplicationDelegate> 26{ 27 VSTGUI::Standalone::Platform::Mac::MacPreference prefs; 28 VSTGUI::Standalone::Platform::Mac::CommonDirectories commonDirecories; 29} 30@property NSArray<NSString*>* _Nullable startupOpenFiles; 31@property BOOL hasFinishedLaunching; 32@property BOOL hasTriggeredSetupMainMenu; 33@end 34 35using namespace VSTGUI::Standalone; 36using VSTGUI::Standalone::Platform::Mac::IMacWindow; 37using VSTGUI::Standalone::Detail::IPlatformApplication; 38using VSTGUI::Standalone::Detail::CommandWithKey; 39using VSTGUI::Standalone::Detail::IPlatformWindowAccess; 40using CommandWithKeyList = VSTGUI::Standalone::Detail::IPlatformApplication::CommandWithKeyList; 41using VSTGUI::Standalone::Detail::PlatformCallbacks; 42 43//------------------------------------------------------------------------ 44static CommandWithKeyList getCommandList (const char* _Nonnull group) 45{ 46 for (auto& e : Detail::getApplicationPlatformAccess ()->getCommandList ()) 47 { 48 if (e.first == group) 49 return e.second; 50 } 51 return {}; 52} 53 54//------------------------------------------------------------------------ 55@implementation VSTGUIApplicationDelegate 56 57//------------------------------------------------------------------------ 58- (instancetype _Nonnull)init 59{ 60 self = [super init]; 61 if (self) 62 { 63 } 64 return self; 65} 66 67//------------------------------------------------------------------------ 68- (NSApplicationTerminateReply)applicationShouldTerminate:(nonnull NSApplication*)sender 69{ 70 if (Detail::getApplicationPlatformAccess ()->canQuit ()) 71 return NSTerminateNow; 72 return NSTerminateCancel; 73} 74 75//------------------------------------------------------------------------ 76- (IBAction)showAboutDialog:(nullable id)sender 77{ 78 if (IApplication::instance ().getDelegate ().hasAboutDialog ()) 79 IApplication::instance ().getDelegate ().showAboutDialog (); 80 else 81 [NSApp orderFrontStandardAboutPanel:sender]; 82} 83 84//------------------------------------------------------------------------ 85- (IBAction)showPreferenceDialog:(nullable id)sender 86{ 87 IApplication::instance ().getDelegate ().showPreferenceDialog (); 88} 89 90//------------------------------------------------------------------------ 91- (IBAction)processCommand:(nullable id)sender 92{ 93 if (VSTGUICommand* command = [sender representedObject]) 94 Detail::getApplicationPlatformAccess ()->handleCommand ([command command]); 95} 96 97//------------------------------------------------------------------------ 98- (void)showHelp:(nullable id)sender 99{ 100} 101 102//------------------------------------------------------------------------ 103- (BOOL)validateMenuItem:(nonnull NSMenuItem*)menuItem 104{ 105 if (menuItem.action == @selector (showPreferenceDialog:)) 106 { 107 if (!IApplication::instance ().getDelegate ().hasPreferenceDialog ()) 108 { 109 return NO; 110 } 111 return YES; 112 } 113 else if (menuItem.action == @selector (showAboutDialog:)) 114 { 115 return YES; 116 } 117 else if (VSTGUICommand* command = menuItem.representedObject) 118 { 119 return Detail::getApplicationPlatformAccess ()->canHandleCommand ([command command]); 120 } 121 return NO; 122} 123 124//------------------------------------------------------------------------ 125- (nonnull SEL)selectorForCommand:(const CommandWithKey&)command 126{ 127 if (command == Commands::CloseWindow) 128 return @selector (performClose:); 129 else if (command == Commands::Undo) 130 return @selector (undo); 131 else if (command == Commands::Redo) 132 return @selector (redo); 133 else if (command == Commands::Cut) 134 return @selector (cut:); 135 else if (command == Commands::Copy) 136 return @selector (copy:); 137 else if (command == Commands::Paste) 138 return @selector (paste:); 139 else if (command == Commands::Delete) 140 return @selector (delete:); 141 else if (command == Commands::SelectAll) 142 return @selector (selectAll:); 143 return @selector (processCommand:); 144} 145 146//------------------------------------------------------------------------ 147- (nonnull NSMenuItem*)createMenuItemFromCommand:(const CommandWithKey&)command 148{ 149 if (command.name == CommandName::MenuSeparator) 150 return [NSMenuItem separatorItem]; 151 152 NSMenuItem* item = [NSMenuItem new]; 153 item.title = stringFromUTF8String (command.name); 154 item.action = [self selectorForCommand:command]; 155 if (command.defaultKey) 156 { 157 item.keyEquivalent = 158 [NSString stringWithCharacters:reinterpret_cast<const unichar*> (&command.defaultKey) 159 length:1]; 160 } 161 VSTGUICommand* representedObject = [VSTGUICommand new]; 162 representedObject.cmd = command; 163 item.representedObject = representedObject; 164 return item; 165} 166 167//------------------------------------------------------------------------ 168- (nonnull NSString*)appName 169{ 170 NSDictionary* dict = [[NSBundle mainBundle] infoDictionary]; 171 return dict[(@"CFBundleName")]; 172} 173 174//------------------------------------------------------------------------ 175- (nonnull NSMenu*)createAppMenu 176{ 177 NSString* appName = [self appName]; 178 NSMenu* menu = [[NSMenu alloc] initWithTitle:appName]; 179 180 [menu addItemWithTitle:[NSLocalizedString (@"About ", "Menu Item") 181 stringByAppendingString:appName] 182 action:@selector (showAboutDialog:) 183 keyEquivalent:@""]; 184 [menu addItem:[NSMenuItem separatorItem]]; 185 186 [menu addItemWithTitle:NSLocalizedString (@"Preferences...", "Menu Item") 187 action:@selector (showPreferenceDialog:) 188 keyEquivalent:@","]; 189 190 [menu addItem:[NSMenuItem separatorItem]]; 191 192 auto commandList = getCommandList (CommandGroup::Application); 193 if (!commandList.empty ()) 194 { 195 for (auto& command : commandList) 196 { 197 if (command != Commands::About && command != Commands::Preferences && 198 command != Commands::Quit && command != Commands::Help) 199 { 200 [menu addItem:[self createMenuItemFromCommand:command]]; 201 } 202 } 203 } 204 205 [menu addItem:[NSMenuItem separatorItem]]; 206 [menu 207 addItemWithTitle:[NSLocalizedString (@"Hide ", "Menu Item") stringByAppendingString:appName] 208 action:@selector (hide:) 209 keyEquivalent:@"h"]; 210 [menu addItemWithTitle:NSLocalizedString (@"Hide Others", "Menu Item") 211 action:@selector (hideOtherApplications:) 212 keyEquivalent:@""]; 213 [menu addItemWithTitle:NSLocalizedString (@"Show All", "Menu Item") 214 action:@selector (unhideAllApplications:) 215 keyEquivalent:@""]; 216 [menu addItem:[NSMenuItem separatorItem]]; 217 [menu 218 addItemWithTitle:[NSLocalizedString (@"Quit ", "Menu Item") stringByAppendingString:appName] 219 action:@selector (terminate:) 220 keyEquivalent:@"q"]; 221 222 return menu; 223} 224 225//------------------------------------------------------------------------ 226- (void)fillMenu:(nonnull NSMenu*)menu fromCommandList:(const CommandWithKeyList&)commandList 227{ 228 for (auto& command : commandList) 229 { 230 [menu addItem:[self createMenuItemFromCommand:command]]; 231 } 232} 233 234//------------------------------------------------------------------------ 235- (nonnull NSMenu*)createWindowsMenu 236{ 237 NSMenu* menu = 238 [[NSMenu alloc] initWithTitle:NSLocalizedString (@"Window", "Window Menu Title")]; 239 [menu addItemWithTitle:NSLocalizedString (@"Minimize", "Menu Item in Window Menu") 240 action:@selector (performMiniaturize:) 241 keyEquivalent:@"m"]; 242 [menu addItemWithTitle:NSLocalizedString (@"Zoom", "Menu Item in Window Menu") 243 action:@selector (performZoom:) 244 keyEquivalent:@""]; 245 NSMenuItem* item = 246 [menu addItemWithTitle:NSLocalizedString (@"Fullscreen", "Menu Item in Window Menu") 247 action:@selector (toggleFullScreen:) 248 keyEquivalent:@"f"]; 249 item.keyEquivalentModifierMask = 250 MacEventModifier::CommandKeyMask | MacEventModifier::ControlKeyMask; 251 [menu addItem:[NSMenuItem separatorItem]]; 252 253#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 && __clang_major__ >= 9 254 if (@available (macOS 10.12, *)) 255 { 256 item = [menu 257 addItemWithTitle:NSLocalizedString (@"Show Previous Tab", "Menu Item in Window Menu") 258 action:@selector (selectPreviousTab:) 259 keyEquivalent:@"\t"]; 260 item.keyEquivalentModifierMask = 261 MacEventModifier::ShiftKeyMask | MacEventModifier::ControlKeyMask; 262 item = 263 [menu addItemWithTitle:NSLocalizedString (@"Show Next Tab", "Menu Item in Window Menu") 264 action:@selector (selectNextTab:) 265 keyEquivalent:@"\t"]; 266 item.keyEquivalentModifierMask = MacEventModifier::ControlKeyMask; 267 [menu addItemWithTitle:NSLocalizedString (@"Move Tab To New Window", 268 "Menu Item in Window Menu") 269 action:@selector (moveTabToNewWindow:) 270 keyEquivalent:@""]; 271 [menu addItemWithTitle:NSLocalizedString (@"Merge All Windows", "Menu Item in Window Menu") 272 action:@selector (mergeAllWindows:) 273 keyEquivalent:@""]; 274 item = 275 [menu addItemWithTitle:NSLocalizedString (@"Show All Tabs", "Menu Item in Window Menu") 276 action:@selector (toggleTabOverview:) 277 keyEquivalent:@"\\"]; 278 item.keyEquivalentModifierMask = 279 MacEventModifier::ShiftKeyMask | MacEventModifier::CommandKeyMask; 280 281 [menu addItem:[NSMenuItem separatorItem]]; 282 } 283#endif 284 [menu addItemWithTitle:NSLocalizedString (@"Bring All to Front", "Menu Item in Window Menu") 285 action:@selector (arrangeInFront:) 286 keyEquivalent:@""]; 287 [menu addItem:[NSMenuItem separatorItem]]; 288 return menu; 289} 290 291//------------------------------------------------------------------------ 292- (nonnull NSMenu*)createHelpMenu 293{ 294 NSMenu* menu = [[NSMenu alloc] initWithTitle:NSLocalizedString (@"Help", "Help Menu Title")]; 295 return menu; 296} 297 298//------------------------------------------------------------------------ 299- (void)setupMainMenu 300{ 301 NSMenu* mainMenu = [NSApp mainMenu]; 302 NSMenuItem* appMenuItem = nil; 303 if (mainMenu == nil) 304 { 305 mainMenu = [NSMenu new]; 306 [NSApp setMainMenu:mainMenu]; 307 308 appMenuItem = [[NSMenuItem alloc] initWithTitle:@"App" action:nil keyEquivalent:@""]; 309 [mainMenu addItem:appMenuItem]; 310 311 NSMenuItem* item = 312 [[NSMenuItem alloc] initWithTitle:NSLocalizedString (@"Window", "Menu Name") 313 action:nullptr 314 keyEquivalent:@""]; 315 NSMenu* windowsMenu = [self createWindowsMenu]; 316 [NSApp setWindowsMenu:windowsMenu]; 317 item.submenu = windowsMenu; 318 [mainMenu addItem:item]; 319 320 item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString (@"Help", "Menu Name") 321 action:nullptr 322 keyEquivalent:@""]; 323 NSMenu* helpMenu = [self createHelpMenu]; 324 [NSApp setHelpMenu:helpMenu]; 325 item.submenu = helpMenu; 326 [mainMenu addItem:item]; 327 } 328 else 329 { 330 appMenuItem = [mainMenu itemAtIndex:0]; 331 } 332 333 appMenuItem.submenu = [self createAppMenu]; 334 335 auto commandList = Detail::getApplicationPlatformAccess ()->getCommandList (); 336 for (auto& e : commandList) 337 { 338 if (e.first == CommandGroup::Window) 339 { 340 NSMenu* windowsMenu = [NSApp windowsMenu]; 341 for (auto& command : e.second) 342 { 343 NSString* title = stringFromUTF8String (command.name); 344 NSMenuItem* item = [windowsMenu itemWithTitle:title]; 345 if (!item) 346 [windowsMenu addItem:[self createMenuItemFromCommand:command]]; 347 } 348 } 349 else if (e.first == CommandGroup::Application) 350 { 351 for (auto& cmd : e.second) 352 { 353 if (cmd.name == CommandName::Help) 354 { 355 NSMenu* helpMenu = [NSApp helpMenu]; 356 NSMenuItem* item = [helpMenu itemWithTitle:stringFromUTF8String (cmd.name)]; 357 if (!item) 358 { 359 item = [self createMenuItemFromCommand:cmd]; 360 NSString* appName = [self appName]; 361 item.title = [appName 362 stringByAppendingString:NSLocalizedString (@" Help", "Menu Item")]; 363 [helpMenu addItem:item]; 364 } 365 } 366 } 367 } 368 else 369 { 370 NSString* title = stringFromUTF8String (e.first); 371 NSMenuItem* item = [mainMenu itemWithTitle:title]; 372 if (!item) 373 { 374 item = [[NSMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""]; 375 [mainMenu addItem:item]; 376 NSMenu* menu = [[NSMenu alloc] initWithTitle:title]; 377 item.submenu = menu; 378 } 379 else 380 [item.submenu removeAllItems]; 381 [self fillMenu:item.submenu fromCommandList:e.second]; 382 } 383 } 384 385 NSMenuItem* editMenu = [mainMenu itemWithTitle:NSLocalizedString (@"Edit", "Menu Name")]; 386 if (editMenu && editMenu.submenu) 387 { 388 NSMenuItem* showCharacterPanelItem = 389 [editMenu.submenu itemWithTitle:NSLocalizedString (@"Characters", "Menu Item")]; 390 if (showCharacterPanelItem == nil) 391 { 392 [editMenu.submenu addItem:[NSMenuItem separatorItem]]; 393 [editMenu.submenu 394 addItemWithTitle:NSLocalizedString (@"Emoji & Symbols", "Menu Item in Edit Menu") 395 action:@selector (orderFrontCharacterPalette:) 396 keyEquivalent:@""]; 397 } 398 } 399 400 NSMenuItem* debugMenu = [mainMenu itemWithTitle:@"Debug"]; 401 if (debugMenu && debugMenu.submenu) 402 { 403 if ([debugMenu.submenu itemWithTitle:@"Color Panel"] == nil) 404 { 405 [debugMenu.submenu addItem:[NSMenuItem separatorItem]]; 406 [debugMenu.submenu addItemWithTitle:@"Color Panel" 407 action:@selector (orderFrontColorPanel:) 408 keyEquivalent:@""]; 409 } 410 } 411 412 // move Windows menu to the end 413 NSMenuItem* windowsMenuItem = 414 [mainMenu itemWithTitle:NSLocalizedString (@"Window", "Menu Name")]; 415 [mainMenu removeItem:windowsMenuItem]; 416 [mainMenu addItem:windowsMenuItem]; 417 // move Help menu to the end 418 NSMenuItem* helpMenuItem = [mainMenu itemWithTitle:NSLocalizedString (@"Help", "Menu Name")]; 419 [mainMenu removeItem:helpMenuItem]; 420 [mainMenu addItem:helpMenuItem]; 421} 422 423//------------------------------------------------------------------------ 424- (void)triggerSetupMainMenu 425{ 426 if (self.hasTriggeredSetupMainMenu) 427 return; 428 self.hasTriggeredSetupMainMenu = YES; 429 Async::perform (Async::Context::Main, [self] () { 430 [self setupMainMenu]; 431 self.hasTriggeredSetupMainMenu = NO; 432 }); 433} 434 435//------------------------------------------------------------------------ 436- (nonnull NSAlert*)createAlert:(const AlertBoxConfig&)config 437{ 438 NSAlert* alert = [NSAlert new]; 439 if (!config.headline.empty ()) 440 alert.messageText = stringFromUTF8String (config.headline); 441 if (!config.description.empty ()) 442 alert.informativeText = stringFromUTF8String (config.description); 443 [alert addButtonWithTitle:stringFromUTF8String (config.defaultButton)]; 444 if (!config.secondButton.empty ()) 445 [alert addButtonWithTitle:stringFromUTF8String (config.secondButton)]; 446 if (!config.thirdButton.empty ()) 447 [alert addButtonWithTitle:stringFromUTF8String (config.thirdButton)]; 448 return alert; 449} 450 451//------------------------------------------------------------------------ 452- (AlertResult)showAlert:(const AlertBoxConfig&)config 453{ 454 NSAlert* alert = [self createAlert:config]; 455 NSModalResponse response = [alert runModal]; 456 if (response == NSAlertSecondButtonReturn) 457 return AlertResult::SecondButton; 458 if (response == NSAlertThirdButtonReturn) 459 return AlertResult::ThirdButton; 460 return AlertResult::DefaultButton; 461} 462 463//------------------------------------------------------------------------ 464- (void)showAlertForWindow:(const AlertBoxForWindowConfig&)config 465{ 466 auto platformWindowAccess = VSTGUI::dynamicPtrCast<IPlatformWindowAccess> (config.window); 467 if (!platformWindowAccess) 468 return; 469 auto macWindow = VSTGUI::staticPtrCast<IMacWindow> (platformWindowAccess->getPlatformWindow ()); 470 if (!macWindow) 471 return; 472 if (macWindow->isPopup ()) 473 { 474 auto result = [self showAlert:config]; 475 if (config.callback) 476 config.callback (result); 477 return; 478 } 479 480 auto callback = std::move (config.callback); 481 482#if VSTGUI_STANDALONE_USE_GENERIC_ALERTBOX_ON_MACOS 483 struct Params 484 { 485 NSWindow* sheet {nullptr}; 486 NSWindow* parent {nullptr}; 487 }; 488 489 auto params = std::make_shared<Params> (); 490 params->parent = macWindow->getNSWindow (); 491 auto parentWindow = config.window; 492 auto alertWindow = Detail::createAlertBox (config, [=] (AlertResult r) { 493 if (callback) 494 callback (r); 495 [params->parent endSheet:params->sheet]; 496 }); 497 auto platformAlertWindow = VSTGUI::dynamicPtrCast<IPlatformWindowAccess> (alertWindow); 498 assert (platformAlertWindow); 499 auto macAlertWindow = 500 VSTGUI::staticPtrCast<IMacWindow> (platformAlertWindow->getPlatformWindow ()); 501 assert (macAlertWindow); 502 params->sheet = macAlertWindow->getNSWindow (); 503 504 [params->parent beginSheet:params->sheet completionHandler:^(NSModalResponse returnCode) {}]; 505 506#else 507 508 NSAlert* alert = [self createAlert:config]; 509 [alert beginSheetModalForWindow:macWindow->getNSWindow () 510 completionHandler:^(NSModalResponse returnCode) { 511 if (callback) 512 { 513 AlertResult result = AlertResult::Error; 514 if (returnCode == NSAlertFirstButtonReturn) 515 result = AlertResult::DefaultButton; 516 else if (returnCode == NSAlertSecondButtonReturn) 517 result = AlertResult::SecondButton; 518 else if (returnCode == NSAlertThirdButtonReturn) 519 result = AlertResult::ThirdButton; 520 callback (result); 521 } 522 }]; 523#endif 524} 525 526//------------------------------------------------------------------------ 527- (BOOL)verifyInfoPlistEntries 528{ 529 NSDictionary* dict = [[NSBundle mainBundle] infoDictionary]; 530 const auto& appInfo = IApplication::instance ().getDelegate ().getInfo (); 531 NSString* infoPlistString = dict[(@"CFBundleName")]; 532 if (![stringFromUTF8String (appInfo.name) isEqualToString:infoPlistString]) 533 { 534 NSLog (@"Warning: CFBundleName is not equal to Application::Info::name"); 535 } 536 infoPlistString = dict[(@"CFBundleShortVersionString")]; 537 if (![stringFromUTF8String (appInfo.version) isEqualToString:infoPlistString]) 538 { 539 NSLog (@"Warning: CFBundleShortVersionString is not equal to Application::Info::version"); 540 } 541 infoPlistString = dict[(@"CFBundleIdentifier")]; 542 if (![stringFromUTF8String (appInfo.uri) isEqualToString:infoPlistString]) 543 { 544 NSLog (@"Warning: CFBundleIdentifier is not equal to Application::Info::uri"); 545 } 546 return YES; 547} 548 549//------------------------------------------------------------------------ 550- (void)applicationDidFinishLaunching:(nonnull NSNotification*)notification 551{ 552 if ([self verifyInfoPlistEntries] == NO) 553 { 554 [NSApp terminate:nil]; 555 return; 556 } 557 558 IApplication::CommandLineArguments cmdArgs; 559 NSArray* args = [[NSProcessInfo processInfo] arguments]; 560 cmdArgs.reserve ([args count]); 561 for (NSString* str in args) 562 { 563 cmdArgs.emplace_back ([str UTF8String]); 564 } 565 566 VSTGUIApplicationDelegate* Self = self; 567 PlatformCallbacks callbacks; 568 callbacks.quit = [] () { 569 [NSApp performSelector:@selector (terminate:) withObject:nil afterDelay:0]; 570 }; 571 callbacks.onCommandUpdate = [Self] () { [Self triggerSetupMainMenu]; }; 572 callbacks.showAlert = [Self] (const AlertBoxConfig& config) { return [Self showAlert:config]; }; 573 callbacks.showAlertForWindow = [Self] (const AlertBoxForWindowConfig& config) { 574 return [Self showAlertForWindow:config]; 575 }; 576 auto app = Detail::getApplicationPlatformAccess (); 577 vstgui_assert (app); 578 [self setupMainMenu]; 579 IPlatformApplication::OpenFilesList openFilesList; 580 if (auto filenames = self.startupOpenFiles) 581 { 582 openFilesList.reserve (filenames.count); 583 for (NSString* filename in filenames) 584 { 585 openFilesList.emplace_back ([filename UTF8String]); 586 } 587 self.startupOpenFiles = nil; 588 } 589 self.hasFinishedLaunching = YES; 590 app->init ({prefs, commonDirecories, std::move (cmdArgs), std::move (callbacks), 591 std::move (openFilesList)}); 592} 593 594//------------------------------------------------------------------------ 595- (void)applicationWillTerminate:(nonnull NSNotification*)notification 596{ 597 IApplication::instance ().getDelegate ().onQuit (); 598 for (NSWindow* window in [NSApp windows]) 599 { 600 [window close]; 601 } 602 Detail::cleanupSharedUIResources (); 603 Async::waitAllTasksDone (); 604} 605 606//------------------------------------------------------------------------ 607- (BOOL)openFilesInternal:(nonnull NSArray<NSString*>*)filenames 608{ 609 std::vector<VSTGUI::UTF8String> paths; 610 paths.reserve (filenames.count); 611 for (NSString* filename in filenames) 612 { 613 paths.emplace_back ([filename UTF8String]); 614 } 615 return IApplication::instance ().getDelegate ().openFiles (paths) ? YES : NO; 616} 617 618//------------------------------------------------------------------------ 619- (void)application:(nonnull NSApplication*)sender openFiles:(nonnull NSArray<NSString*>*)filenames 620{ 621 if (!self.hasFinishedLaunching) 622 { 623 self.startupOpenFiles = filenames; 624 return; 625 } 626 BOOL result = [self openFilesInternal:filenames]; 627 [sender replyToOpenOrPrint:result ? NSApplicationDelegateReplySuccess : 628 NSApplicationDelegateReplyFailure]; 629} 630 631@end 632 633//------------------------------------------------------------------------ 634namespace VSTGUI { void* _Nullable gBundleRef = nullptr; } 635 636//------------------------------------------------------------------------ 637int main (int argc, const char* _Nonnull* _Nonnull argv) 638{ 639 VSTGUI::gBundleRef = CFBundleGetMainBundle (); 640 VSTGUIApplicationDelegate* delegate = [VSTGUIApplicationDelegate new]; 641 [NSApplication sharedApplication].delegate = delegate; 642 return NSApplicationMain (argc, argv); 643} 644