| @@ -30,7 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #if JUCE_ALSA | |||
| @@ -1040,5 +1039,3 @@ AudioIODeviceType* juce_createDefaultAudioIODeviceType() { return 0; } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| #endif | |||
| @@ -30,8 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #include "linuxincludes.h" | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| @@ -56,5 +54,3 @@ void FileChooser::showPlatformDialog (OwnedArray<File>& results, | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -30,8 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #include "linuxincludes.h" | |||
| /* Got a build error here? You'll need to install the freetype library... | |||
| @@ -640,5 +638,3 @@ void Font::getDefaultFontNames (String& defaultSans, String& defaultSerif, Strin | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -30,7 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #include "linuxincludes.h" | |||
| #include <stdio.h> | |||
| @@ -419,5 +418,3 @@ bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -30,7 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #if JUCE_ALSA | |||
| @@ -486,5 +485,3 @@ MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { re | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| #endif | |||
| @@ -255,7 +255,8 @@ void Process::lowerPrivilege() | |||
| } | |||
| } | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #if ! JUCE_ONLY_BUILD_CORE_LIBRARY | |||
| void* PlatformUtilities::loadDynamicLibrary (const String& name) | |||
| { | |||
| return dlopen ((const char*) name.toUTF8(), RTLD_LOCAL | RTLD_NOW); | |||
| @@ -270,7 +271,7 @@ void* PlatformUtilities::getProcedureEntryPoint (void* libraryHandle, const Stri | |||
| { | |||
| return dlsym (libraryHandle, (const char*) procedureName); | |||
| } | |||
| #endif | |||
| #endif | |||
| END_JUCE_NAMESPACE | |||
| @@ -30,9 +30,6 @@ | |||
| */ | |||
| #include "../../../juce_Config.h" | |||
| #if JUCE_BUILD_GUI_CLASSES | |||
| #include "linuxincludes.h" | |||
| #include <X11/Xlib.h> | |||
| #include <X11/Xutil.h> | |||
| @@ -3354,5 +3351,3 @@ const int KeyPress::rewindKey = (0xffeeff03) | extendedKeyModifier; | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -36,6 +36,8 @@ | |||
| //============================================================================== | |||
| END_JUCE_NAMESPACE | |||
| #define OpenDiskDevice MakeObjCClassName(OpenDiskDevice) | |||
| @interface OpenDiskDevice : NSObject | |||
| { | |||
| DRDevice* device; | |||
| @@ -53,6 +55,8 @@ END_JUCE_NAMESPACE | |||
| @end | |||
| //============================================================================== | |||
| #define AudioTrackProducer MakeObjCClassName(AudioTrackProducer) | |||
| @interface AudioTrackProducer : NSObject | |||
| { | |||
| JUCE_NAMESPACE::AudioSource* source; | |||
| @@ -37,6 +37,8 @@ | |||
| END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| #define JuceFileChooserDelegate MakeObjCClassName(JuceFileChooserDelegate) | |||
| @interface JuceFileChooserDelegate : NSObject | |||
| { | |||
| StringArray* filters; | |||
| @@ -1,414 +1,429 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| //============================================================================== | |||
| class JuceMainMenuHandler; | |||
| END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| @interface JuceMenuCallback : NSObject | |||
| { | |||
| JuceMainMenuHandler* owner; | |||
| } | |||
| - (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_; | |||
| - (void) dealloc; | |||
| - (void) menuItemInvoked: (id) menu; | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| class JuceMainMenuHandler : private MenuBarModelListener, | |||
| private DeletedAtShutdown | |||
| { | |||
| public: | |||
| static JuceMainMenuHandler* instance; | |||
| //============================================================================== | |||
| JuceMainMenuHandler() throw() | |||
| : currentModel (0) | |||
| { | |||
| callback = [[JuceMenuCallback alloc] initWithOwner: this]; | |||
| } | |||
| ~JuceMainMenuHandler() throw() | |||
| { | |||
| setMenu (0); | |||
| jassert (instance == this); | |||
| instance = 0; | |||
| [callback release]; | |||
| } | |||
| void setMenu (MenuBarModel* const newMenuBarModel) throw() | |||
| { | |||
| if (currentModel != newMenuBarModel) | |||
| { | |||
| if (currentModel != 0) | |||
| currentModel->removeListener (this); | |||
| currentModel = newMenuBarModel; | |||
| if (currentModel != 0) | |||
| currentModel->addListener (this); | |||
| menuBarItemsChanged (0); | |||
| } | |||
| } | |||
| void addSubMenu (NSMenu* parent, const PopupMenu& child, | |||
| const String& name, int& menuId, int& tag) | |||
| { | |||
| NSMenuItem* item = [parent addItemWithTitle: juceStringToNS (name) | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setTag: tag]; | |||
| NSMenu* sub = createMenu (child, name, menuId, tag); | |||
| [parent setSubmenu: sub forItem: item]; | |||
| [sub setAutoenablesItems: false]; | |||
| [sub release]; | |||
| } | |||
| void menuBarItemsChanged (MenuBarModel*) | |||
| { | |||
| NSMenu* menuBar = [NSApp mainMenu]; | |||
| while ([menuBar numberOfItems] > 1) | |||
| [menuBar removeItemAtIndex: 1]; | |||
| if (currentModel != 0) | |||
| { | |||
| const StringArray menuNames (currentModel->getMenuBarNames()); | |||
| int menuId = 1; | |||
| for (int i = 0; i < menuNames.size(); ++i) | |||
| { | |||
| const PopupMenu menu (currentModel->getMenuForIndex (i, menuNames [i])); | |||
| addSubMenu (menuBar, menu, menuNames [i], menuId, i); | |||
| } | |||
| } | |||
| } | |||
| static void flashMenuBar (NSMenu* menu) | |||
| { | |||
| const unichar f35Key = NSF35FunctionKey; | |||
| NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1]; | |||
| NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x" | |||
| action: nil | |||
| keyEquivalent: f35String]; | |||
| [item setTarget: nil]; | |||
| [menu insertItem: item atIndex: [menu numberOfItems]]; | |||
| [item release]; | |||
| NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown | |||
| location: NSZeroPoint | |||
| modifierFlags: NSCommandKeyMask | |||
| timestamp: 0 | |||
| windowNumber: 0 | |||
| context: [NSGraphicsContext currentContext] | |||
| characters: f35String | |||
| charactersIgnoringModifiers: f35String | |||
| isARepeat: NO | |||
| keyCode: 0]; | |||
| [menu performKeyEquivalent: f35Event]; | |||
| [menu removeItem: item]; | |||
| } | |||
| void menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo& info) | |||
| { | |||
| NSMenuItem* item = [[NSApp mainMenu] itemWithTag: info.commandID]; | |||
| if (item != 0) | |||
| flashMenuBar ([item menu]); | |||
| } | |||
| void invoke (const int commandId, ApplicationCommandManager* const commandManager, const int topLevelIndex) const | |||
| { | |||
| if (currentModel != 0) | |||
| { | |||
| if (commandManager != 0) | |||
| { | |||
| ApplicationCommandTarget::InvocationInfo info (commandId); | |||
| info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu; | |||
| commandManager->invoke (info, true); | |||
| } | |||
| currentModel->menuItemSelected (commandId, topLevelIndex); | |||
| } | |||
| } | |||
| MenuBarModel* currentModel; | |||
| private: | |||
| JuceMenuCallback* callback; | |||
| NSMenu* createMenu (const PopupMenu menu, | |||
| const String& menuName, | |||
| int& id, | |||
| const int topLevelIndex) | |||
| { | |||
| NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
| [m setAutoenablesItems: false]; | |||
| PopupMenu::MenuItemIterator iter (menu); | |||
| while (iter.next()) | |||
| { | |||
| NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
| if (iter.isSeparator) | |||
| { | |||
| [m addItem: [NSMenuItem separatorItem]]; | |||
| } | |||
| else if (iter.isSectionHeader) | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| } | |||
| else if (iter.subMenu != 0) | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setTag: iter.itemId]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, id, topLevelIndex); | |||
| [m setSubmenu: sub forItem: item]; | |||
| [sub release]; | |||
| } | |||
| else | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: @selector (menuItemInvoked:) | |||
| keyEquivalent: @""]; | |||
| [item setTag: iter.itemId]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| [item setState: iter.isTicked ? NSOnState : NSOffState]; | |||
| [item setTarget: (id) callback]; | |||
| NSMutableArray* info = [NSMutableArray arrayWithObject: [NSNumber numberWithUnsignedLongLong: (pointer_sized_int) (void*) iter.commandManager]]; | |||
| [info addObject: [NSNumber numberWithInt: topLevelIndex]]; | |||
| [item setRepresentedObject: info]; | |||
| if (iter.commandManager != 0) | |||
| { | |||
| const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
| ->getKeyPressesAssignedToCommand (iter.itemId)); | |||
| if (keyPresses.size() > 0) | |||
| { | |||
| const KeyPress& kp = keyPresses.getReference(0); | |||
| juce_wchar key = kp.getTextCharacter(); | |||
| if (kp.getKeyCode() == KeyPress::backspaceKey) | |||
| key = NSBackspaceCharacter; | |||
| else if (kp.getKeyCode() == KeyPress::deleteKey) | |||
| key = NSDeleteCharacter; | |||
| else if (key == 0) | |||
| key = (juce_wchar) kp.getKeyCode(); | |||
| unsigned int mods = 0; | |||
| if (kp.getModifiers().isShiftDown()) | |||
| mods |= NSShiftKeyMask; | |||
| if (kp.getModifiers().isCtrlDown()) | |||
| mods |= NSControlKeyMask; | |||
| if (kp.getModifiers().isAltDown()) | |||
| mods |= NSAlternateKeyMask; | |||
| if (kp.getModifiers().isCommandDown()) | |||
| mods |= NSCommandKeyMask; | |||
| [item setKeyEquivalent: juceStringToNS (String::charToString (key))]; | |||
| [item setKeyEquivalentModifierMask: mods]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| [m update]; | |||
| return m; | |||
| } | |||
| }; | |||
| JuceMainMenuHandler* JuceMainMenuHandler::instance = 0; | |||
| END_JUCE_NAMESPACE | |||
| @implementation JuceMenuCallback | |||
| - (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_ | |||
| { | |||
| [super init]; | |||
| owner = owner_; | |||
| return self; | |||
| } | |||
| - (void) dealloc | |||
| { | |||
| [super dealloc]; | |||
| } | |||
| - (void) menuItemInvoked: (id) menu | |||
| { | |||
| NSMenuItem* item = (NSMenuItem*) menu; | |||
| if ([[item representedObject] isKindOfClass: [NSArray class]]) | |||
| { | |||
| NSArray* info = (NSArray*) [item representedObject]; | |||
| owner->invoke ([item tag], | |||
| (ApplicationCommandManager*) (pointer_sized_int) | |||
| [((NSNumber*) [info objectAtIndex: 0]) unsignedLongLongValue], | |||
| (int) [((NSNumber*) [info objectAtIndex: 1]) intValue]); | |||
| } | |||
| } | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel) throw() | |||
| { | |||
| if (getMacMainMenu() != newMenuBarModel) | |||
| { | |||
| if (newMenuBarModel == 0) | |||
| { | |||
| delete JuceMainMenuHandler::instance; | |||
| jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | |||
| } | |||
| else | |||
| { | |||
| if (JuceMainMenuHandler::instance == 0) | |||
| JuceMainMenuHandler::instance = new JuceMainMenuHandler(); | |||
| JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
| } | |||
| } | |||
| } | |||
| MenuBarModel* MenuBarModel::getMacMainMenu() throw() | |||
| { | |||
| return JuceMainMenuHandler::instance != 0 | |||
| ? JuceMainMenuHandler::instance->currentModel : 0; | |||
| } | |||
| //============================================================================== | |||
| static NSMenu* createStandardAppMenu (const String& appName) | |||
| { | |||
| NSMenu* menu = [[NSMenu alloc] initWithTitle: @"Apple"]; | |||
| NSMenuItem* item; | |||
| // xxx should allow the 'about' and 'preferences' items to be turned on programatically... | |||
| /* item = [menu addItemWithTitle: juceStringToNS ("About " + appName)] | |||
| action: @selector(orderFrontStandardAboutPanel:) keyEquivalent: @""]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| */ | |||
| /* item = [menu addItemWithTitle: NSLocalizedString (@"Preferences...", nil) | |||
| action: nil keyEquivalent: @","]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| */ | |||
| // Services... | |||
| item = [menu addItemWithTitle: NSLocalizedString (@"Services", nil) | |||
| action: nil keyEquivalent: @""]; | |||
| NSMenu* servicesMenu = [[NSMenu alloc] initWithTitle: @"Services"]; | |||
| [menu setSubmenu: servicesMenu forItem: item]; | |||
| [NSApp setServicesMenu: servicesMenu]; | |||
| [servicesMenu release]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| // Hide + Show stuff... | |||
| item = [menu addItemWithTitle: juceStringToNS ("Hide " + appName) | |||
| action: @selector (hide:) keyEquivalent: @"h"]; | |||
| [item setTarget: NSApp]; | |||
| item = [menu addItemWithTitle: NSLocalizedString (@"Hide Others", nil) | |||
| action: @selector (hideOtherApplications:) keyEquivalent: @"h"]; | |||
| [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask]; | |||
| [item setTarget: NSApp]; | |||
| item = [menu addItemWithTitle: NSLocalizedString (@"Show All", nil) | |||
| action: @selector (unhideAllApplications:) keyEquivalent: @""]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| // Quit item.... | |||
| item = [menu addItemWithTitle: juceStringToNS ("Quit " + appName) | |||
| action: @selector (terminate:) keyEquivalent: @"q"]; | |||
| [item setTarget: NSApp]; | |||
| return menu; | |||
| } | |||
| // Since our app has no NIB, this initialises a standard app menu... | |||
| void initialiseMainMenu() | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| NSMenu* mainMenu = [[NSMenu alloc] initWithTitle: @"MainMenu"]; | |||
| NSMenuItem* item = [mainMenu addItemWithTitle: @"Apple" action: nil keyEquivalent: @""]; | |||
| NSMenu* appMenu = createStandardAppMenu (JUCEApplication::getInstance()->getApplicationName()); | |||
| [NSApp performSelector: @selector (setAppleMenu:) withObject: appMenu]; | |||
| [mainMenu setSubmenu: appMenu forItem: item]; | |||
| [NSApp setMainMenu: mainMenu]; | |||
| [appMenu release]; | |||
| [mainMenu release]; | |||
| } | |||
| } | |||
| #endif | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| //============================================================================== | |||
| class JuceMainMenuHandler; | |||
| END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| #define JuceMenuCallback MakeObjCClassName(JuceMenuCallback) | |||
| @interface JuceMenuCallback : NSObject | |||
| { | |||
| JuceMainMenuHandler* owner; | |||
| } | |||
| - (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_; | |||
| - (void) dealloc; | |||
| - (void) menuItemInvoked: (id) menu; | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| class JuceMainMenuHandler : private MenuBarModelListener, | |||
| private DeletedAtShutdown | |||
| { | |||
| public: | |||
| static JuceMainMenuHandler* instance; | |||
| //============================================================================== | |||
| JuceMainMenuHandler() throw() | |||
| : currentModel (0) | |||
| { | |||
| callback = [[JuceMenuCallback alloc] initWithOwner: this]; | |||
| } | |||
| ~JuceMainMenuHandler() throw() | |||
| { | |||
| setMenu (0); | |||
| jassert (instance == this); | |||
| instance = 0; | |||
| [callback release]; | |||
| } | |||
| void setMenu (MenuBarModel* const newMenuBarModel) throw() | |||
| { | |||
| if (currentModel != newMenuBarModel) | |||
| { | |||
| if (currentModel != 0) | |||
| currentModel->removeListener (this); | |||
| currentModel = newMenuBarModel; | |||
| if (currentModel != 0) | |||
| currentModel->addListener (this); | |||
| menuBarItemsChanged (0); | |||
| } | |||
| } | |||
| void addSubMenu (NSMenu* parent, const PopupMenu& child, | |||
| const String& name, int& menuId, int& tag) | |||
| { | |||
| NSMenuItem* item = [parent addItemWithTitle: juceStringToNS (name) | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setTag: tag]; | |||
| NSMenu* sub = createMenu (child, name, menuId, tag); | |||
| [parent setSubmenu: sub forItem: item]; | |||
| [sub setAutoenablesItems: false]; | |||
| [sub release]; | |||
| } | |||
| void menuBarItemsChanged (MenuBarModel*) | |||
| { | |||
| NSMenu* menuBar = [NSApp mainMenu]; | |||
| while ([menuBar numberOfItems] > 1) | |||
| [menuBar removeItemAtIndex: 1]; | |||
| if (currentModel != 0) | |||
| { | |||
| const StringArray menuNames (currentModel->getMenuBarNames()); | |||
| int menuId = 1; | |||
| for (int i = 0; i < menuNames.size(); ++i) | |||
| { | |||
| const PopupMenu menu (currentModel->getMenuForIndex (i, menuNames [i])); | |||
| addSubMenu (menuBar, menu, menuNames [i], menuId, i); | |||
| } | |||
| } | |||
| } | |||
| static void flashMenuBar (NSMenu* menu) | |||
| { | |||
| const unichar f35Key = NSF35FunctionKey; | |||
| NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1]; | |||
| NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x" | |||
| action: nil | |||
| keyEquivalent: f35String]; | |||
| [item setTarget: nil]; | |||
| [menu insertItem: item atIndex: [menu numberOfItems]]; | |||
| [item release]; | |||
| NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown | |||
| location: NSZeroPoint | |||
| modifierFlags: NSCommandKeyMask | |||
| timestamp: 0 | |||
| windowNumber: 0 | |||
| context: [NSGraphicsContext currentContext] | |||
| characters: f35String | |||
| charactersIgnoringModifiers: f35String | |||
| isARepeat: NO | |||
| keyCode: 0]; | |||
| [menu performKeyEquivalent: f35Event]; | |||
| [menu removeItem: item]; | |||
| } | |||
| void menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo& info) | |||
| { | |||
| NSMenuItem* item = [[NSApp mainMenu] itemWithTag: info.commandID]; | |||
| if (item != 0) | |||
| flashMenuBar ([item menu]); | |||
| } | |||
| void invoke (const int commandId, ApplicationCommandManager* const commandManager, const int topLevelIndex) const | |||
| { | |||
| if (currentModel != 0) | |||
| { | |||
| if (commandManager != 0) | |||
| { | |||
| ApplicationCommandTarget::InvocationInfo info (commandId); | |||
| info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu; | |||
| commandManager->invoke (info, true); | |||
| } | |||
| currentModel->menuItemSelected (commandId, topLevelIndex); | |||
| } | |||
| } | |||
| MenuBarModel* currentModel; | |||
| private: | |||
| JuceMenuCallback* callback; | |||
| NSMenu* createMenu (const PopupMenu menu, | |||
| const String& menuName, | |||
| int& id, | |||
| const int topLevelIndex) | |||
| { | |||
| NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
| [m setAutoenablesItems: false]; | |||
| PopupMenu::MenuItemIterator iter (menu); | |||
| while (iter.next()) | |||
| { | |||
| NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
| if (iter.isSeparator) | |||
| { | |||
| [m addItem: [NSMenuItem separatorItem]]; | |||
| } | |||
| else if (iter.isSectionHeader) | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| } | |||
| else if (iter.subMenu != 0) | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: nil | |||
| keyEquivalent: @""]; | |||
| [item setTag: iter.itemId]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, id, topLevelIndex); | |||
| [m setSubmenu: sub forItem: item]; | |||
| [sub release]; | |||
| } | |||
| else | |||
| { | |||
| NSMenuItem* item = [m addItemWithTitle: text | |||
| action: @selector (menuItemInvoked:) | |||
| keyEquivalent: @""]; | |||
| [item setTag: iter.itemId]; | |||
| [item setEnabled: iter.isEnabled]; | |||
| [item setState: iter.isTicked ? NSOnState : NSOffState]; | |||
| [item setTarget: (id) callback]; | |||
| NSMutableArray* info = [NSMutableArray arrayWithObject: [NSNumber numberWithUnsignedLongLong: (pointer_sized_int) (void*) iter.commandManager]]; | |||
| [info addObject: [NSNumber numberWithInt: topLevelIndex]]; | |||
| [item setRepresentedObject: info]; | |||
| if (iter.commandManager != 0) | |||
| { | |||
| const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
| ->getKeyPressesAssignedToCommand (iter.itemId)); | |||
| if (keyPresses.size() > 0) | |||
| { | |||
| const KeyPress& kp = keyPresses.getReference(0); | |||
| juce_wchar key = kp.getTextCharacter(); | |||
| if (kp.getKeyCode() == KeyPress::backspaceKey) | |||
| key = NSBackspaceCharacter; | |||
| else if (kp.getKeyCode() == KeyPress::deleteKey) | |||
| key = NSDeleteCharacter; | |||
| else if (key == 0) | |||
| key = (juce_wchar) kp.getKeyCode(); | |||
| unsigned int mods = 0; | |||
| if (kp.getModifiers().isShiftDown()) | |||
| mods |= NSShiftKeyMask; | |||
| if (kp.getModifiers().isCtrlDown()) | |||
| mods |= NSControlKeyMask; | |||
| if (kp.getModifiers().isAltDown()) | |||
| mods |= NSAlternateKeyMask; | |||
| if (kp.getModifiers().isCommandDown()) | |||
| mods |= NSCommandKeyMask; | |||
| [item setKeyEquivalent: juceStringToNS (String::charToString (key))]; | |||
| [item setKeyEquivalentModifierMask: mods]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| [m update]; | |||
| return m; | |||
| } | |||
| }; | |||
| JuceMainMenuHandler* JuceMainMenuHandler::instance = 0; | |||
| END_JUCE_NAMESPACE | |||
| @implementation JuceMenuCallback | |||
| - (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_ | |||
| { | |||
| [super init]; | |||
| owner = owner_; | |||
| return self; | |||
| } | |||
| - (void) dealloc | |||
| { | |||
| [super dealloc]; | |||
| } | |||
| - (void) menuItemInvoked: (id) menu | |||
| { | |||
| NSMenuItem* item = (NSMenuItem*) menu; | |||
| if ([[item representedObject] isKindOfClass: [NSArray class]]) | |||
| { | |||
| NSArray* info = (NSArray*) [item representedObject]; | |||
| owner->invoke ([item tag], | |||
| (ApplicationCommandManager*) (pointer_sized_int) | |||
| [((NSNumber*) [info objectAtIndex: 0]) unsignedLongLongValue], | |||
| (int) [((NSNumber*) [info objectAtIndex: 1]) intValue]); | |||
| } | |||
| } | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel) throw() | |||
| { | |||
| if (getMacMainMenu() != newMenuBarModel) | |||
| { | |||
| if (newMenuBarModel == 0) | |||
| { | |||
| delete JuceMainMenuHandler::instance; | |||
| jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | |||
| } | |||
| else | |||
| { | |||
| if (JuceMainMenuHandler::instance == 0) | |||
| JuceMainMenuHandler::instance = new JuceMainMenuHandler(); | |||
| JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
| } | |||
| } | |||
| } | |||
| MenuBarModel* MenuBarModel::getMacMainMenu() throw() | |||
| { | |||
| return JuceMainMenuHandler::instance != 0 | |||
| ? JuceMainMenuHandler::instance->currentModel : 0; | |||
| } | |||
| //============================================================================== | |||
| static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName) | |||
| { | |||
| NSMenuItem* item; | |||
| // xxx should allow the 'about' and 'preferences' items to be turned on programatically... | |||
| /* item = [menu addItemWithTitle: juceStringToNS ("About " + appName)] | |||
| action: @selector(orderFrontStandardAboutPanel:) keyEquivalent: @""]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| */ | |||
| /* item = [menu addItemWithTitle: NSLocalizedString (@"Preferences...", nil) | |||
| action: nil keyEquivalent: @","]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| */ | |||
| // Services... | |||
| item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (@"Services", nil) | |||
| action: nil keyEquivalent: @""]; | |||
| [menu addItem: item]; | |||
| [item release]; | |||
| NSMenu* servicesMenu = [[NSMenu alloc] initWithTitle: @"Services"]; | |||
| [menu setSubmenu: servicesMenu forItem: item]; | |||
| [NSApp setServicesMenu: servicesMenu]; | |||
| [servicesMenu release]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| // Hide + Show stuff... | |||
| item = [[NSMenuItem alloc] initWithTitle: juceStringToNS ("Hide " + appName) | |||
| action: @selector (hide:) keyEquivalent: @"h"]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: item]; | |||
| [item release]; | |||
| item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (@"Hide Others", nil) | |||
| action: @selector (hideOtherApplications:) keyEquivalent: @"h"]; | |||
| [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: item]; | |||
| [item release]; | |||
| item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (@"Show All", nil) | |||
| action: @selector (unhideAllApplications:) keyEquivalent: @""]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: item]; | |||
| [item release]; | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| // Quit item.... | |||
| item = [[NSMenuItem alloc] initWithTitle: juceStringToNS ("Quit " + appName) | |||
| action: @selector (terminate:) keyEquivalent: @"q"]; | |||
| [item setTarget: NSApp]; | |||
| [menu addItem: item]; | |||
| [item release]; | |||
| return menu; | |||
| } | |||
| // Since our app has no NIB, this initialises a standard app menu... | |||
| void initialiseMainMenu() | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| NSMenu* mainMenu = [[NSMenu alloc] initWithTitle: @"MainMenu"]; | |||
| NSMenuItem* item = [mainMenu addItemWithTitle: @"Apple" action: nil keyEquivalent: @""]; | |||
| NSMenu* appMenu = [[NSMenu alloc] initWithTitle: @"Apple"]; | |||
| [NSApp performSelector: @selector (setAppleMenu:) withObject: appMenu]; | |||
| [mainMenu setSubmenu: appMenu forItem: item]; | |||
| [NSApp setMainMenu: mainMenu]; | |||
| createStandardAppMenu (appMenu, JUCEApplication::getInstance()->getApplicationName()); | |||
| [appMenu release]; | |||
| [mainMenu release]; | |||
| } | |||
| } | |||
| #endif | |||
| @@ -1,285 +1,341 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| struct CallbackMessagePayload | |||
| { | |||
| MessageCallbackFunction* function; | |||
| void* parameter; | |||
| void* volatile result; | |||
| bool volatile hasBeenExecuted; | |||
| }; | |||
| END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| @interface JuceAppDelegate : NSObject | |||
| { | |||
| id oldDelegate; | |||
| } | |||
| - (JuceAppDelegate*) init; | |||
| - (void) dealloc; | |||
| - (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; | |||
| - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; | |||
| - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; | |||
| - (void) applicationDidBecomeActive: (NSNotification*) aNotification; | |||
| - (void) applicationDidResignActive: (NSNotification*) aNotification; | |||
| - (void) applicationWillUnhide: (NSNotification*) aNotification; | |||
| - (void) customEvent: (id) data; | |||
| - (void) performCallback: (id) info; | |||
| - (void) dummyMethod; | |||
| @end | |||
| @implementation JuceAppDelegate | |||
| - (JuceAppDelegate*) init | |||
| { | |||
| [super init]; | |||
| NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| oldDelegate = [NSApp delegate]; | |||
| [NSApp setDelegate: self]; | |||
| } | |||
| else | |||
| { | |||
| oldDelegate = 0; | |||
| [center addObserver: self selector: @selector (applicationDidResignActive:) | |||
| name: NSApplicationDidResignActiveNotification object: NSApp]; | |||
| [center addObserver: self selector: @selector (applicationDidBecomeActive:) | |||
| name: NSApplicationDidBecomeActiveNotification object: NSApp]; | |||
| [center addObserver: self selector: @selector (applicationWillUnhide:) | |||
| name: NSApplicationWillUnhideNotification object: NSApp]; | |||
| } | |||
| return self; | |||
| } | |||
| - (void) dealloc | |||
| { | |||
| if (oldDelegate != 0) | |||
| [NSApp setDelegate: oldDelegate]; | |||
| [super dealloc]; | |||
| } | |||
| - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||
| if (! MessageManager::getInstance()->hasStopMessageBeenSent()) | |||
| return NSTerminateCancel; | |||
| } | |||
| return NSTerminateNow; | |||
| } | |||
| - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); | |||
| return YES; | |||
| } | |||
| return NO; | |||
| } | |||
| - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames | |||
| { | |||
| StringArray files; | |||
| for (int i = 0; i < [filenames count]; ++i) | |||
| files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||
| if (files.size() > 0 && JUCEApplication::getInstance() != 0) | |||
| JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" "))); | |||
| } | |||
| - (void) applicationDidBecomeActive: (NSNotification*) aNotification | |||
| { | |||
| juce_HandleProcessFocusChange(); | |||
| } | |||
| - (void) applicationDidResignActive: (NSNotification*) aNotification | |||
| { | |||
| juce_HandleProcessFocusChange(); | |||
| } | |||
| - (void) applicationWillUnhide: (NSNotification*) aNotification | |||
| { | |||
| juce_HandleProcessFocusChange(); | |||
| } | |||
| - (void) customEvent: (id) n | |||
| { | |||
| NSData* data = (NSData*) n; | |||
| void* message = 0; | |||
| [data getBytes: &message length: sizeof (message)]; | |||
| if (message != 0) | |||
| MessageManager::getInstance()->deliverMessage (message); | |||
| [data release]; | |||
| } | |||
| - (void) performCallback: (id) info | |||
| { | |||
| CallbackMessagePayload* pl = (CallbackMessagePayload*) info; | |||
| if (pl != 0) | |||
| { | |||
| pl->result = (*pl->function) (pl->parameter); | |||
| pl->hasBeenExecuted = true; | |||
| } | |||
| } | |||
| - (void) dummyMethod {} // (used as a way of running a dummy thread) | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| static JuceAppDelegate* juceAppDelegate = 0; | |||
| void MessageManager::runDispatchLoop() | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| MessageManagerLock mml; | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| [NSApp run]; | |||
| } | |||
| void MessageManager::stopDispatchLoop() | |||
| { | |||
| quitMessagePosted = true; | |||
| [NSApp stop: nil]; | |||
| } | |||
| bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| jassert (isThisTheMessageThread()); // must only be called by the message thread | |||
| uint32 endTime = Time::getMillisecondCounter() + millisecondsToRunFor; | |||
| NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001]; | |||
| while (Time::getMillisecondCounter() < endTime) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode | |||
| beforeDate: endDate]; | |||
| NSEvent* e = [NSApp nextEventMatchingMask: NSAnyEventMask | |||
| untilDate: endDate | |||
| inMode: NSDefaultRunLoopMode | |||
| dequeue: YES]; | |||
| [NSApp sendEvent: e]; | |||
| } | |||
| return ! quitMessagePosted; | |||
| } | |||
| //============================================================================== | |||
| void MessageManager::doPlatformSpecificInitialisation() | |||
| { | |||
| if (juceAppDelegate == 0) | |||
| juceAppDelegate = [[JuceAppDelegate alloc] init]; | |||
| // This launches a dummy thread, which forces Cocoa to initialise NSThreads | |||
| // correctly (needed prior to 10.5) | |||
| if (! [NSThread isMultiThreaded]) | |||
| [NSThread detachNewThreadSelector: @selector (dummyMethod) | |||
| toTarget: juceAppDelegate | |||
| withObject: nil]; | |||
| initialiseMainMenu(); | |||
| } | |||
| void MessageManager::doPlatformSpecificShutdown() | |||
| { | |||
| [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate]; | |||
| [[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate]; | |||
| [juceAppDelegate release]; | |||
| juceAppDelegate = 0; | |||
| } | |||
| bool juce_postMessageToSystemQueue (void* message) | |||
| { | |||
| [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) | |||
| withObject: (id) [[NSData alloc] initWithBytes: &message | |||
| length: (int) sizeof (message)] | |||
| waitUntilDone: NO]; | |||
| return true; | |||
| } | |||
| void MessageManager::broadcastMessage (const String& value) throw() | |||
| { | |||
| } | |||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, | |||
| void* data) | |||
| { | |||
| if (isThisTheMessageThread()) | |||
| { | |||
| return (*callback) (data); | |||
| } | |||
| else | |||
| { | |||
| CallbackMessagePayload cmp; | |||
| cmp.function = callback; | |||
| cmp.parameter = data; | |||
| cmp.result = 0; | |||
| cmp.hasBeenExecuted = false; | |||
| [juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) | |||
| withObject: (id) &cmp | |||
| waitUntilDone: YES]; | |||
| return cmp.result; | |||
| } | |||
| } | |||
| #endif | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #ifdef JUCE_INCLUDED_FILE | |||
| struct CallbackMessagePayload | |||
| { | |||
| MessageCallbackFunction* function; | |||
| void* parameter; | |||
| void* volatile result; | |||
| bool volatile hasBeenExecuted; | |||
| }; | |||
| /* When you use multiple DLLs which share similarly-named obj-c classes - like | |||
| for example having more than one juce plugin loaded into a host, then when a | |||
| method is called, the actual code that runs might actually be in a different module | |||
| than the one you expect... So any calls to library functions or statics that are | |||
| made inside obj-c methods will probably end up getting executed in a different DLL's | |||
| memory space. Not a great thing to happen - this obviously leads to bizarre crashes. | |||
| To work around this insanity, I'm only allowing obj-c methods to make calls to | |||
| virtual methods of an object that's known to live inside the right module's space. | |||
| */ | |||
| class AppDelegateRedirector | |||
| { | |||
| public: | |||
| AppDelegateRedirector() {} | |||
| virtual ~AppDelegateRedirector() {} | |||
| virtual NSApplicationTerminateReply shouldTerminate() | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||
| if (! MessageManager::getInstance()->hasStopMessageBeenSent()) | |||
| return NSTerminateCancel; | |||
| } | |||
| return NSTerminateNow; | |||
| } | |||
| virtual BOOL openFile (const NSString* filename) | |||
| { | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); | |||
| return YES; | |||
| } | |||
| return NO; | |||
| } | |||
| virtual void openFiles (NSArray* filenames) | |||
| { | |||
| StringArray files; | |||
| for (int i = 0; i < [filenames count]; ++i) | |||
| files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); | |||
| if (files.size() > 0 && JUCEApplication::getInstance() != 0) | |||
| JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" "))); | |||
| } | |||
| virtual void focusChanged() | |||
| { | |||
| juce_HandleProcessFocusChange(); | |||
| } | |||
| virtual void deliverMessage (void* message) | |||
| { | |||
| MessageManager::getInstance()->deliverMessage (message); | |||
| } | |||
| virtual void deleteSelf() | |||
| { | |||
| delete this; | |||
| } | |||
| }; | |||
| END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| typedef void (*juce_HandleProcessFocusChangeFunction)(); | |||
| #define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) | |||
| @interface JuceAppDelegate : NSObject | |||
| { | |||
| @private | |||
| id oldDelegate; | |||
| AppDelegateRedirector* redirector; | |||
| } | |||
| - (JuceAppDelegate*) init; | |||
| - (void) dealloc; | |||
| - (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; | |||
| - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; | |||
| - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; | |||
| - (void) applicationDidBecomeActive: (NSNotification*) aNotification; | |||
| - (void) applicationDidResignActive: (NSNotification*) aNotification; | |||
| - (void) applicationWillUnhide: (NSNotification*) aNotification; | |||
| - (void) customEvent: (id) data; | |||
| - (void) performCallback: (id) info; | |||
| - (void) dummyMethod; | |||
| @end | |||
| @implementation JuceAppDelegate | |||
| - (JuceAppDelegate*) init | |||
| { | |||
| [super init]; | |||
| redirector = new AppDelegateRedirector(); | |||
| NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |||
| if (JUCEApplication::getInstance() != 0) | |||
| { | |||
| oldDelegate = [NSApp delegate]; | |||
| [NSApp setDelegate: self]; | |||
| } | |||
| else | |||
| { | |||
| oldDelegate = 0; | |||
| [center addObserver: self selector: @selector (applicationDidResignActive:) | |||
| name: NSApplicationDidResignActiveNotification object: NSApp]; | |||
| [center addObserver: self selector: @selector (applicationDidBecomeActive:) | |||
| name: NSApplicationDidBecomeActiveNotification object: NSApp]; | |||
| [center addObserver: self selector: @selector (applicationWillUnhide:) | |||
| name: NSApplicationWillUnhideNotification object: NSApp]; | |||
| } | |||
| return self; | |||
| } | |||
| - (void) dealloc | |||
| { | |||
| if (oldDelegate != 0) | |||
| [NSApp setDelegate: oldDelegate]; | |||
| redirector->deleteSelf(); | |||
| [super dealloc]; | |||
| } | |||
| - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app | |||
| { | |||
| return redirector->shouldTerminate(); | |||
| } | |||
| - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename | |||
| { | |||
| return redirector->openFile (filename); | |||
| } | |||
| - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames | |||
| { | |||
| return redirector->openFiles (filenames); | |||
| } | |||
| - (void) applicationDidBecomeActive: (NSNotification*) aNotification | |||
| { | |||
| redirector->focusChanged(); | |||
| } | |||
| - (void) applicationDidResignActive: (NSNotification*) aNotification | |||
| { | |||
| redirector->focusChanged(); | |||
| } | |||
| - (void) applicationWillUnhide: (NSNotification*) aNotification | |||
| { | |||
| redirector->focusChanged(); | |||
| } | |||
| - (void) customEvent: (id) n | |||
| { | |||
| NSData* data = (NSData*) n; | |||
| void* message = 0; | |||
| [data getBytes: &message length: sizeof (message)]; | |||
| if (message != 0) | |||
| redirector->deliverMessage (message); | |||
| [data release]; | |||
| } | |||
| - (void) performCallback: (id) info | |||
| { | |||
| CallbackMessagePayload* pl = (CallbackMessagePayload*) info; | |||
| if (pl != 0) | |||
| { | |||
| pl->result = (*pl->function) (pl->parameter); | |||
| pl->hasBeenExecuted = true; | |||
| } | |||
| } | |||
| - (void) dummyMethod {} // (used as a way of running a dummy thread) | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| static JuceAppDelegate* juceAppDelegate = 0; | |||
| void MessageManager::runDispatchLoop() | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| MessageManagerLock mml; | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| [NSApp run]; | |||
| } | |||
| void MessageManager::stopDispatchLoop() | |||
| { | |||
| quitMessagePosted = true; | |||
| [NSApp stop: nil]; | |||
| } | |||
| bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| jassert (isThisTheMessageThread()); // must only be called by the message thread | |||
| uint32 endTime = Time::getMillisecondCounter() + millisecondsToRunFor; | |||
| NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001]; | |||
| while (Time::getMillisecondCounter() < endTime) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode | |||
| beforeDate: endDate]; | |||
| NSEvent* e = [NSApp nextEventMatchingMask: NSAnyEventMask | |||
| untilDate: endDate | |||
| inMode: NSDefaultRunLoopMode | |||
| dequeue: YES]; | |||
| [NSApp sendEvent: e]; | |||
| } | |||
| return ! quitMessagePosted; | |||
| } | |||
| //============================================================================== | |||
| void MessageManager::doPlatformSpecificInitialisation() | |||
| { | |||
| if (juceAppDelegate == 0) | |||
| juceAppDelegate = [[JuceAppDelegate alloc] init]; | |||
| // This launches a dummy thread, which forces Cocoa to initialise NSThreads | |||
| // correctly (needed prior to 10.5) | |||
| if (! [NSThread isMultiThreaded]) | |||
| [NSThread detachNewThreadSelector: @selector (dummyMethod) | |||
| toTarget: juceAppDelegate | |||
| withObject: nil]; | |||
| initialiseMainMenu(); | |||
| } | |||
| void MessageManager::doPlatformSpecificShutdown() | |||
| { | |||
| [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate]; | |||
| [[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate]; | |||
| [juceAppDelegate release]; | |||
| juceAppDelegate = 0; | |||
| } | |||
| bool juce_postMessageToSystemQueue (void* message) | |||
| { | |||
| [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) | |||
| withObject: (id) [[NSData alloc] initWithBytes: &message | |||
| length: (int) sizeof (message)] | |||
| waitUntilDone: NO]; | |||
| return true; | |||
| } | |||
| void MessageManager::broadcastMessage (const String& value) throw() | |||
| { | |||
| } | |||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, | |||
| void* data) | |||
| { | |||
| if (isThisTheMessageThread()) | |||
| { | |||
| return (*callback) (data); | |||
| } | |||
| else | |||
| { | |||
| CallbackMessagePayload cmp; | |||
| cmp.function = callback; | |||
| cmp.parameter = data; | |||
| cmp.result = 0; | |||
| cmp.hasBeenExecuted = false; | |||
| [juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) | |||
| withObject: (id) &cmp | |||
| waitUntilDone: YES]; | |||
| return cmp.result; | |||
| } | |||
| } | |||
| #endif | |||
| @@ -77,6 +77,12 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h" | |||
| #undef Point | |||
| //============================================================================== | |||
| #define ObjCExtraSuffix 1 | |||
| #define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d | |||
| #define appendMacro2(a, b, c, d) appendMacro1(a, b, c, d) | |||
| #define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, ObjCExtraSuffix) | |||
| //============================================================================== | |||
| #define JUCE_INCLUDED_FILE 1 | |||
| @@ -166,6 +166,8 @@ END_JUCE_NAMESPACE | |||
| using namespace JUCE_NAMESPACE; | |||
| //============================================================================== | |||
| #define JuceURLConnection MakeObjCClassName(JuceURLConnection) | |||
| @interface JuceURLConnection : NSObject | |||
| { | |||
| NSURLRequest* request; | |||
| @@ -1,235 +1,246 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #if JUCE_INCLUDED_FILE && JUCE_OPENGL | |||
| //============================================================================== | |||
| class WindowedGLContext : public OpenGLContext | |||
| { | |||
| public: | |||
| WindowedGLContext (Component* const component, | |||
| const OpenGLPixelFormat& pixelFormat_, | |||
| NSOpenGLContext* sharedContext) | |||
| : renderContext (0), | |||
| pixelFormat (pixelFormat_) | |||
| { | |||
| jassert (component != 0); | |||
| NSOpenGLPixelFormatAttribute attribs [64]; | |||
| int n = 0; | |||
| attribs[n++] = NSOpenGLPFADoubleBuffer; | |||
| attribs[n++] = NSOpenGLPFAAccelerated; | |||
| attribs[n++] = NSOpenGLPFAColorSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.redBits, | |||
| pixelFormat.greenBits, | |||
| pixelFormat.blueBits); | |||
| attribs[n++] = NSOpenGLPFAAlphaSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.alphaBits; | |||
| attribs[n++] = NSOpenGLPFADepthSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.depthBufferBits; | |||
| attribs[n++] = NSOpenGLPFAStencilSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.stencilBufferBits; | |||
| attribs[n++] = NSOpenGLPFAAccumSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.accumulationBufferRedBits, | |||
| pixelFormat.accumulationBufferGreenBits, | |||
| pixelFormat.accumulationBufferBlueBits, | |||
| pixelFormat.accumulationBufferAlphaBits); | |||
| // xxx not sure how to do fullSceneAntiAliasingNumSamples.. | |||
| attribs[n++] = NSOpenGLPFASampleBuffers; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) 1; | |||
| attribs[n++] = NSOpenGLPFAClosestPolicy; | |||
| attribs[n++] = NSOpenGLPFANoRecovery; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) 0; | |||
| NSOpenGLPixelFormat* format | |||
| = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs]; | |||
| NSOpenGLView* view | |||
| = [[NSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) | |||
| pixelFormat: format]; | |||
| renderContext = [view openGLContext]; | |||
| [format release]; | |||
| viewHolder = new NSViewComponentInternal (view, component); | |||
| } | |||
| ~WindowedGLContext() | |||
| { | |||
| makeInactive(); | |||
| [renderContext setView: nil]; | |||
| delete viewHolder; | |||
| } | |||
| bool makeActive() const throw() | |||
| { | |||
| jassert (renderContext != 0); | |||
| [renderContext makeCurrentContext]; | |||
| return renderContext != 0; | |||
| } | |||
| bool makeInactive() const throw() | |||
| { | |||
| if (! isActive()) | |||
| [NSOpenGLContext clearCurrentContext]; | |||
| return true; | |||
| } | |||
| bool isActive() const throw() | |||
| { | |||
| return [NSOpenGLContext currentContext] == renderContext; | |||
| } | |||
| const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; } | |||
| void* getRawContext() const throw() { return renderContext; } | |||
| void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) | |||
| { | |||
| } | |||
| void swapBuffers() | |||
| { | |||
| glFlush(); | |||
| [renderContext flushBuffer]; | |||
| } | |||
| bool setSwapInterval (const int numFramesPerSwap) | |||
| { | |||
| [renderContext setValues: (const GLint*) &numFramesPerSwap | |||
| forParameter: NSOpenGLCPSwapInterval]; | |||
| return true; | |||
| } | |||
| int getSwapInterval() const | |||
| { | |||
| GLint numFrames = 0; | |||
| [renderContext getValues: &numFrames | |||
| forParameter: NSOpenGLCPSwapInterval]; | |||
| return numFrames; | |||
| } | |||
| void repaint() | |||
| { | |||
| // we need to invalidate the juce view that holds this gl view, to make it | |||
| // cause a repaint callback | |||
| NSView* v = (NSView*) viewHolder->view; | |||
| NSRect r = [v frame]; | |||
| // bit of a bodge here.. if we only invalidate the area of the gl component, | |||
| // it's completely covered by the NSOpenGLView, so the OS throws away the | |||
| // repaint message, thus never causing our paint() callback, and never repainting | |||
| // the comp. So invalidating just a little bit around the edge helps.. | |||
| [[v superview] setNeedsDisplayInRect: NSInsetRect (r, -2.0f, -2.0f)]; | |||
| } | |||
| void* getNativeWindowHandle() const { return viewHolder->view; } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| NSOpenGLContext* renderContext; | |||
| private: | |||
| OpenGLPixelFormat pixelFormat; | |||
| NSViewComponentInternal* viewHolder; | |||
| //============================================================================== | |||
| WindowedGLContext (const WindowedGLContext&); | |||
| const WindowedGLContext& operator= (const WindowedGLContext&); | |||
| }; | |||
| //============================================================================== | |||
| OpenGLContext* OpenGLContext::createContextForWindow (Component* const component, | |||
| const OpenGLPixelFormat& pixelFormat, | |||
| const OpenGLContext* const contextToShareWith) | |||
| { | |||
| WindowedGLContext* c = new WindowedGLContext (component, pixelFormat, | |||
| contextToShareWith != 0 ? (NSOpenGLContext*) contextToShareWith->getRawContext() : 0); | |||
| if (c->renderContext == 0) | |||
| deleteAndZero (c); | |||
| return c; | |||
| } | |||
| void* OpenGLComponent::getNativeWindowHandle() const | |||
| { | |||
| return context != 0 ? ((WindowedGLContext*) context)->getNativeWindowHandle() | |||
| : 0; | |||
| } | |||
| void juce_glViewport (const int w, const int h) | |||
| { | |||
| glViewport (0, 0, w, h); | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||
| OwnedArray <OpenGLPixelFormat>& results) | |||
| { | |||
| /* GLint attribs [64]; | |||
| int n = 0; | |||
| attribs[n++] = AGL_RGBA; | |||
| attribs[n++] = AGL_DOUBLEBUFFER; | |||
| attribs[n++] = AGL_ACCELERATED; | |||
| attribs[n++] = AGL_NO_RECOVERY; | |||
| attribs[n++] = AGL_NONE; | |||
| AGLPixelFormat p = aglChoosePixelFormat (0, 0, attribs); | |||
| while (p != 0) | |||
| { | |||
| OpenGLPixelFormat* const pf = new OpenGLPixelFormat(); | |||
| pf->redBits = getAGLAttribute (p, AGL_RED_SIZE); | |||
| pf->greenBits = getAGLAttribute (p, AGL_GREEN_SIZE); | |||
| pf->blueBits = getAGLAttribute (p, AGL_BLUE_SIZE); | |||
| pf->alphaBits = getAGLAttribute (p, AGL_ALPHA_SIZE); | |||
| pf->depthBufferBits = getAGLAttribute (p, AGL_DEPTH_SIZE); | |||
| pf->stencilBufferBits = getAGLAttribute (p, AGL_STENCIL_SIZE); | |||
| pf->accumulationBufferRedBits = getAGLAttribute (p, AGL_ACCUM_RED_SIZE); | |||
| pf->accumulationBufferGreenBits = getAGLAttribute (p, AGL_ACCUM_GREEN_SIZE); | |||
| pf->accumulationBufferBlueBits = getAGLAttribute (p, AGL_ACCUM_BLUE_SIZE); | |||
| pf->accumulationBufferAlphaBits = getAGLAttribute (p, AGL_ACCUM_ALPHA_SIZE); | |||
| results.add (pf); | |||
| p = aglNextPixelFormat (p); | |||
| }*/ | |||
| //jassertfalse //xxx can't see how you do this in cocoa! | |||
| } | |||
| #endif | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| // (This file gets included by juce_mac_NativeCode.mm, rather than being | |||
| // compiled on its own). | |||
| #if JUCE_INCLUDED_FILE && JUCE_OPENGL | |||
| //============================================================================== | |||
| class WindowedGLContext : public OpenGLContext | |||
| { | |||
| public: | |||
| WindowedGLContext (Component* const component, | |||
| const OpenGLPixelFormat& pixelFormat_, | |||
| NSOpenGLContext* sharedContext) | |||
| : renderContext (0), | |||
| pixelFormat (pixelFormat_) | |||
| { | |||
| jassert (component != 0); | |||
| NSOpenGLPixelFormatAttribute attribs [64]; | |||
| int n = 0; | |||
| attribs[n++] = NSOpenGLPFADoubleBuffer; | |||
| attribs[n++] = NSOpenGLPFAAccelerated; | |||
| attribs[n++] = NSOpenGLPFAColorSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.redBits, | |||
| pixelFormat.greenBits, | |||
| pixelFormat.blueBits); | |||
| attribs[n++] = NSOpenGLPFAAlphaSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.alphaBits; | |||
| attribs[n++] = NSOpenGLPFADepthSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.depthBufferBits; | |||
| attribs[n++] = NSOpenGLPFAStencilSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) pixelFormat.stencilBufferBits; | |||
| attribs[n++] = NSOpenGLPFAAccumSize; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.accumulationBufferRedBits, | |||
| pixelFormat.accumulationBufferGreenBits, | |||
| pixelFormat.accumulationBufferBlueBits, | |||
| pixelFormat.accumulationBufferAlphaBits); | |||
| // xxx not sure how to do fullSceneAntiAliasingNumSamples.. | |||
| attribs[n++] = NSOpenGLPFASampleBuffers; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) 1; | |||
| attribs[n++] = NSOpenGLPFAClosestPolicy; | |||
| attribs[n++] = NSOpenGLPFANoRecovery; | |||
| attribs[n++] = (NSOpenGLPixelFormatAttribute) 0; | |||
| NSOpenGLPixelFormat* format | |||
| = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs]; | |||
| NSOpenGLView* view | |||
| = [[NSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) | |||
| pixelFormat: format]; | |||
| if (sharedContext != 0) | |||
| { | |||
| renderContext = [[NSOpenGLContext alloc] initWithFormat: format | |||
| shareContext: sharedContext]; | |||
| [view setOpenGLContext: renderContext]; | |||
| [renderContext setView: view]; | |||
| } | |||
| else | |||
| { | |||
| renderContext = [view openGLContext]; | |||
| } | |||
| [format release]; | |||
| viewHolder = new NSViewComponentInternal (view, component); | |||
| } | |||
| ~WindowedGLContext() | |||
| { | |||
| makeInactive(); | |||
| [renderContext setView: nil]; | |||
| delete viewHolder; | |||
| } | |||
| bool makeActive() const throw() | |||
| { | |||
| jassert (renderContext != 0); | |||
| [renderContext makeCurrentContext]; | |||
| return renderContext != 0; | |||
| } | |||
| bool makeInactive() const throw() | |||
| { | |||
| if (! isActive()) | |||
| [NSOpenGLContext clearCurrentContext]; | |||
| return true; | |||
| } | |||
| bool isActive() const throw() | |||
| { | |||
| return [NSOpenGLContext currentContext] == renderContext; | |||
| } | |||
| const OpenGLPixelFormat getPixelFormat() const { return pixelFormat; } | |||
| void* getRawContext() const throw() { return renderContext; } | |||
| void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) | |||
| { | |||
| } | |||
| void swapBuffers() | |||
| { | |||
| glFlush(); | |||
| [renderContext flushBuffer]; | |||
| } | |||
| bool setSwapInterval (const int numFramesPerSwap) | |||
| { | |||
| [renderContext setValues: (const GLint*) &numFramesPerSwap | |||
| forParameter: NSOpenGLCPSwapInterval]; | |||
| return true; | |||
| } | |||
| int getSwapInterval() const | |||
| { | |||
| GLint numFrames = 0; | |||
| [renderContext getValues: &numFrames | |||
| forParameter: NSOpenGLCPSwapInterval]; | |||
| return numFrames; | |||
| } | |||
| void repaint() | |||
| { | |||
| // we need to invalidate the juce view that holds this gl view, to make it | |||
| // cause a repaint callback | |||
| NSView* v = (NSView*) viewHolder->view; | |||
| NSRect r = [v frame]; | |||
| // bit of a bodge here.. if we only invalidate the area of the gl component, | |||
| // it's completely covered by the NSOpenGLView, so the OS throws away the | |||
| // repaint message, thus never causing our paint() callback, and never repainting | |||
| // the comp. So invalidating just a little bit around the edge helps.. | |||
| [[v superview] setNeedsDisplayInRect: NSInsetRect (r, -2.0f, -2.0f)]; | |||
| } | |||
| void* getNativeWindowHandle() const { return viewHolder->view; } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| NSOpenGLContext* renderContext; | |||
| private: | |||
| OpenGLPixelFormat pixelFormat; | |||
| NSViewComponentInternal* viewHolder; | |||
| //============================================================================== | |||
| WindowedGLContext (const WindowedGLContext&); | |||
| const WindowedGLContext& operator= (const WindowedGLContext&); | |||
| }; | |||
| //============================================================================== | |||
| OpenGLContext* OpenGLContext::createContextForWindow (Component* const component, | |||
| const OpenGLPixelFormat& pixelFormat, | |||
| const OpenGLContext* const contextToShareWith) | |||
| { | |||
| WindowedGLContext* c = new WindowedGLContext (component, pixelFormat, | |||
| contextToShareWith != 0 ? (NSOpenGLContext*) contextToShareWith->getRawContext() : 0); | |||
| if (c->renderContext == 0) | |||
| deleteAndZero (c); | |||
| return c; | |||
| } | |||
| void* OpenGLComponent::getNativeWindowHandle() const | |||
| { | |||
| return context != 0 ? ((WindowedGLContext*) context)->getNativeWindowHandle() | |||
| : 0; | |||
| } | |||
| void juce_glViewport (const int w, const int h) | |||
| { | |||
| glViewport (0, 0, w, h); | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||
| OwnedArray <OpenGLPixelFormat>& results) | |||
| { | |||
| /* GLint attribs [64]; | |||
| int n = 0; | |||
| attribs[n++] = AGL_RGBA; | |||
| attribs[n++] = AGL_DOUBLEBUFFER; | |||
| attribs[n++] = AGL_ACCELERATED; | |||
| attribs[n++] = AGL_NO_RECOVERY; | |||
| attribs[n++] = AGL_NONE; | |||
| AGLPixelFormat p = aglChoosePixelFormat (0, 0, attribs); | |||
| while (p != 0) | |||
| { | |||
| OpenGLPixelFormat* const pf = new OpenGLPixelFormat(); | |||
| pf->redBits = getAGLAttribute (p, AGL_RED_SIZE); | |||
| pf->greenBits = getAGLAttribute (p, AGL_GREEN_SIZE); | |||
| pf->blueBits = getAGLAttribute (p, AGL_BLUE_SIZE); | |||
| pf->alphaBits = getAGLAttribute (p, AGL_ALPHA_SIZE); | |||
| pf->depthBufferBits = getAGLAttribute (p, AGL_DEPTH_SIZE); | |||
| pf->stencilBufferBits = getAGLAttribute (p, AGL_STENCIL_SIZE); | |||
| pf->accumulationBufferRedBits = getAGLAttribute (p, AGL_ACCUM_RED_SIZE); | |||
| pf->accumulationBufferGreenBits = getAGLAttribute (p, AGL_ACCUM_GREEN_SIZE); | |||
| pf->accumulationBufferBlueBits = getAGLAttribute (p, AGL_ACCUM_BLUE_SIZE); | |||
| pf->accumulationBufferAlphaBits = getAGLAttribute (p, AGL_ACCUM_ALPHA_SIZE); | |||
| results.add (pf); | |||
| p = aglNextPixelFormat (p); | |||
| }*/ | |||
| //jassertfalse //xxx can't see how you do this in cocoa! | |||
| } | |||
| #endif | |||
| @@ -57,18 +57,9 @@ bool QuickTimeMovieComponent::isQuickTimeAvailable() throw() | |||
| return true; | |||
| } | |||
| bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, | |||
| const bool controllerVisible) | |||
| static QTMovie* openMovieFromStream (InputStream* movieStream, File& movieFile) | |||
| { | |||
| closeMovie(); | |||
| if (getPeer() == 0) | |||
| { | |||
| // To open a movie, this component must be visible inside a functioning window, so that | |||
| // the QT control can be assigned to the window. | |||
| jassertfalse | |||
| return false; | |||
| } | |||
| QTMovie* movie = 0; | |||
| FileInputStream* const fin = dynamic_cast <FileInputStream*> (movieStream); | |||
| @@ -82,12 +73,40 @@ bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, | |||
| { | |||
| MemoryBlock temp; | |||
| movieStream->readIntoMemoryBlock (temp); | |||
| const char* const suffixesToTry[] = { ".mov", ".mp3", ".avi", ".m4a" }; | |||
| for (int i = 0; i < numElementsInArray (suffixesToTry); ++i) | |||
| { | |||
| movie = [QTMovie movieWithDataReference: [QTDataReference dataReferenceWithReferenceToData: [NSData dataWithBytes: temp.getData() | |||
| length: temp.getSize()] | |||
| name: [NSString stringWithCString: suffixesToTry[i]] | |||
| MIMEType: @""] | |||
| error: nil]; | |||
| if (movie != 0) | |||
| break; | |||
| } | |||
| } | |||
| return movie; | |||
| } | |||
| movie = [QTMovie movieWithData: [NSData dataWithBytes: temp.getData() | |||
| length: temp.getSize()] | |||
| error: nil]; | |||
| bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, | |||
| const bool controllerVisible) | |||
| { | |||
| closeMovie(); | |||
| if (getPeer() == 0) | |||
| { | |||
| // To open a movie, this component must be visible inside a functioning window, so that | |||
| // the QT control can be assigned to the window. | |||
| jassertfalse | |||
| return false; | |||
| } | |||
| movie = openMovieFromStream (movieStream, movieFile); | |||
| [theMovie retain]; | |||
| QTMovieView* view = (QTMovieView*) getView(); | |||
| [view setMovie: theMovie]; | |||
| @@ -264,24 +283,8 @@ bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, | |||
| if (movieStream == 0) | |||
| return false; | |||
| QTMovie* movie = nil; | |||
| FileInputStream* const fin = dynamic_cast <FileInputStream*> (movieStream); | |||
| if (fin != 0) | |||
| { | |||
| movie = [QTMovie movieWithFile: juceStringToNS (fin->getFile().getFullPathName()) | |||
| error: nil]; | |||
| } | |||
| else | |||
| { | |||
| MemoryBlock temp; | |||
| movieStream->readIntoMemoryBlock (temp); | |||
| movie = [QTMovie movieWithData: [NSData dataWithBytes: temp.getData() | |||
| length: temp.getSize()] | |||
| error: nil]; | |||
| } | |||
| File file; | |||
| QTMovie* movie = openMovieFromStream (movieStream, file); | |||
| if (movie != nil) | |||
| result = [movie quickTimeMovie]; | |||
| @@ -89,7 +89,10 @@ void SystemStats::initialiseStats() throw() | |||
| { | |||
| initialised = true; | |||
| NSApplicationLoad(); | |||
| // etremely annoying: adding this line stops the apple menu items from working. Of | |||
| // course, not adding it means that carbon windows (e.g. in plugins) won't get | |||
| // any events. | |||
| //NSApplicationLoad(); | |||
| [NSApplication sharedApplication]; | |||
| #if JUCE_INTEL | |||
| @@ -36,6 +36,9 @@ | |||
| //============================================================================== | |||
| END_JUCE_NAMESPACE | |||
| #define DownloadClickDetector MakeObjCClassName(DownloadClickDetector) | |||
| @interface DownloadClickDetector : NSObject | |||
| { | |||
| JUCE_NAMESPACE::WebBrowserComponent* ownerComponent; | |||
| @@ -59,11 +62,14 @@ END_JUCE_NAMESPACE | |||
| return self; | |||
| } | |||
| - (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener >)listener | |||
| - (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary*) actionInformation | |||
| request: (NSURLRequest*) request | |||
| frame: (WebFrame*) frame | |||
| decisionListener: (id <WebPolicyDecisionListener>) listener | |||
| { | |||
| NSURL* url = [actionInformation valueForKey: @"WebActionOriginalURLKey"]; | |||
| if (ownerComponent->pageAboutToLoad (JUCE_NAMESPACE::String::fromUTF8 ((const JUCE_NAMESPACE::uint8*) [[url absoluteString] UTF8String]))) | |||
| if (ownerComponent->pageAboutToLoad (nsStringToJuce ([url absoluteString]))) | |||
| [listener use]; | |||
| else | |||
| [listener ignore]; | |||
| @@ -22,7 +22,6 @@ | |||
| //#define JUCE_USE_XSHM 1 | |||
| //#define JUCE_PLUGINHOST_VST 1 | |||
| //#define JUCE_PLUGINHOST_AU 1 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -52,7 +52,6 @@ | |||
| //#define JUCE_ENABLE_REPAINT_DEBUGGING 1 | |||
| //#define JUCE_USE_XINERAMA 1 | |||
| //#define JUCE_USE_XSHM 1 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -22,7 +22,6 @@ | |||
| //#define JUCE_USE_XSHM 1 | |||
| //#define JUCE_PLUGINHOST_VST 1 | |||
| //#define JUCE_PLUGINHOST_AU 1 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -23,7 +23,6 @@ | |||
| //#define JUCE_USE_XSHM 1 | |||
| //#define JUCE_PLUGINHOST_VST 1 | |||
| //#define JUCE_PLUGINHOST_AU 1 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -52,7 +52,6 @@ | |||
| //#define JUCE_USE_XSHM 1 | |||
| #define JUCE_PLUGINHOST_VST 0 | |||
| #define JUCE_PLUGINHOST_AU 0 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -52,7 +52,6 @@ | |||
| //#define JUCE_USE_XSHM 1 | |||
| #define JUCE_PLUGINHOST_VST 0 | |||
| #define JUCE_PLUGINHOST_AU 0 | |||
| //#define JUCE_BUILD_GUI_CLASSES 1 | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| //#define JUCE_STRINGS_ARE_UNICODE 1 | |||
| @@ -171,14 +171,12 @@ | |||
| #endif | |||
| //============================================================================= | |||
| /** Disabling this will avoid linking to any UI code. This is handy for | |||
| /** Enabling this will avoid including any UI code in the build. This is handy for | |||
| writing command-line utilities, e.g. on linux boxes which don't have some | |||
| of the UI libraries installed. | |||
| (On mac and windows, this won't generally make much difference to the build). | |||
| */ | |||
| #ifndef JUCE_BUILD_GUI_CLASSES | |||
| #define JUCE_BUILD_GUI_CLASSES 1 | |||
| #ifndef JUCE_ONLY_BUILD_CORE_LIBRARY | |||
| //#define JUCE_ONLY_BUILD_CORE_LIBRARY 1 | |||
| #endif | |||
| /** This lets you disable building of the WebBrowserComponent, if it's not required. | |||
| @@ -207,14 +207,12 @@ | |||
| // #define JUCE_PLUGINHOST_AU 1 | |||
| #endif | |||
| /** Disabling this will avoid linking to any UI code. This is handy for | |||
| /** Enabling this will avoid including any UI code in the build. This is handy for | |||
| writing command-line utilities, e.g. on linux boxes which don't have some | |||
| of the UI libraries installed. | |||
| (On mac and windows, this won't generally make much difference to the build). | |||
| */ | |||
| #ifndef JUCE_BUILD_GUI_CLASSES | |||
| #define JUCE_BUILD_GUI_CLASSES 1 | |||
| #ifndef JUCE_ONLY_BUILD_CORE_LIBRARY | |||
| //#define JUCE_ONLY_BUILD_CORE_LIBRARY 1 | |||
| #endif | |||
| /** This lets you disable building of the WebBrowserComponent, if it's not required. | |||
| @@ -367,27 +367,29 @@ const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& ne | |||
| return String::empty; | |||
| } | |||
| if (currentSetup.inputDeviceName != newSetup.inputDeviceName | |||
| || currentSetup.outputDeviceName != newSetup.outputDeviceName | |||
| const String newInputDeviceName (numInputChansNeeded == 0 ? String::empty : newSetup.inputDeviceName); | |||
| const String newOutputDeviceName (numOutputChansNeeded == 0 ? String::empty : newSetup.outputDeviceName); | |||
| if (currentSetup.inputDeviceName != newInputDeviceName | |||
| || currentSetup.inputDeviceName != newOutputDeviceName | |||
| || currentAudioDevice == 0) | |||
| { | |||
| deleteCurrentDevice(); | |||
| scanDevicesIfNeeded(); | |||
| if (newSetup.outputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (false).contains (newSetup.outputDeviceName)) | |||
| if (newOutputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (false).contains (newOutputDeviceName)) | |||
| { | |||
| return "No such device: " + newSetup.outputDeviceName; | |||
| return "No such device: " + newOutputDeviceName; | |||
| } | |||
| if (newSetup.inputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (true).contains (newSetup.inputDeviceName)) | |||
| if (newInputDeviceName.isNotEmpty() | |||
| && ! type->getDeviceNames (true).contains (newInputDeviceName)) | |||
| { | |||
| return "No such device: " + newSetup.outputDeviceName; | |||
| return "No such device: " + newInputDeviceName; | |||
| } | |||
| currentAudioDevice = type->createDevice (newSetup.outputDeviceName, | |||
| newSetup.inputDeviceName); | |||
| currentAudioDevice = type->createDevice (newOutputDeviceName, newInputDeviceName); | |||
| if (currentAudioDevice == 0) | |||
| error = "Can't open the audio device!\n\nThis may be because another application is currently using the same device - if so, you should close any other applications and try again!"; | |||
| @@ -412,10 +414,10 @@ const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& ne | |||
| outputChannels.setRange (0, numOutputChansNeeded, true); | |||
| } | |||
| if (newSetup.inputDeviceName.isEmpty()) | |||
| if (newInputDeviceName.isEmpty()) | |||
| inputChannels.clear(); | |||
| if (newSetup.outputDeviceName.isEmpty()) | |||
| if (newOutputDeviceName.isEmpty()) | |||
| outputChannels.clear(); | |||
| } | |||
| @@ -359,6 +359,8 @@ void Slider::lookAndFeelChanged() | |||
| if (style == LinearBar) | |||
| valueBox->addMouseListener (this, false); | |||
| valueBox->setTooltip (getTooltip()); | |||
| } | |||
| if (style == IncDecButtons) | |||