diff --git a/build/linux/platform_specific_code/juce_linux_Audio.cpp b/build/linux/platform_specific_code/juce_linux_Audio.cpp index 3414176133..b8d4c605ce 100644 --- a/build/linux/platform_specific_code/juce_linux_Audio.cpp +++ b/build/linux/platform_specific_code/juce_linux_Audio.cpp @@ -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 diff --git a/build/linux/platform_specific_code/juce_linux_FileChooser.cpp b/build/linux/platform_specific_code/juce_linux_FileChooser.cpp index 6f26b64393..c16c85863f 100644 --- a/build/linux/platform_specific_code/juce_linux_FileChooser.cpp +++ b/build/linux/platform_specific_code/juce_linux_FileChooser.cpp @@ -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& results, } END_JUCE_NAMESPACE - -#endif diff --git a/build/linux/platform_specific_code/juce_linux_Fonts.cpp b/build/linux/platform_specific_code/juce_linux_Fonts.cpp index bde5e95312..bc97bb7227 100644 --- a/build/linux/platform_specific_code/juce_linux_Fonts.cpp +++ b/build/linux/platform_specific_code/juce_linux_Fonts.cpp @@ -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 diff --git a/build/linux/platform_specific_code/juce_linux_Messaging.cpp b/build/linux/platform_specific_code/juce_linux_Messaging.cpp index 87a848e5c2..1097b959fc 100644 --- a/build/linux/platform_specific_code/juce_linux_Messaging.cpp +++ b/build/linux/platform_specific_code/juce_linux_Messaging.cpp @@ -30,7 +30,6 @@ */ #include "../../../juce_Config.h" -#if JUCE_BUILD_GUI_CLASSES #include "linuxincludes.h" #include @@ -419,5 +418,3 @@ bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) } END_JUCE_NAMESPACE - -#endif diff --git a/build/linux/platform_specific_code/juce_linux_Midi.cpp b/build/linux/platform_specific_code/juce_linux_Midi.cpp index 2b60f9d337..ef1f59becb 100644 --- a/build/linux/platform_specific_code/juce_linux_Midi.cpp +++ b/build/linux/platform_specific_code/juce_linux_Midi.cpp @@ -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 diff --git a/build/linux/platform_specific_code/juce_linux_Threads.cpp b/build/linux/platform_specific_code/juce_linux_Threads.cpp index f09002c65b..bcf9708510 100644 --- a/build/linux/platform_specific_code/juce_linux_Threads.cpp +++ b/build/linux/platform_specific_code/juce_linux_Threads.cpp @@ -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 diff --git a/build/linux/platform_specific_code/juce_linux_Windowing.cpp b/build/linux/platform_specific_code/juce_linux_Windowing.cpp index 2e80f6743b..76913dd625 100644 --- a/build/linux/platform_specific_code/juce_linux_Windowing.cpp +++ b/build/linux/platform_specific_code/juce_linux_Windowing.cpp @@ -30,9 +30,6 @@ */ #include "../../../juce_Config.h" - -#if JUCE_BUILD_GUI_CLASSES - #include "linuxincludes.h" #include #include @@ -3354,5 +3351,3 @@ const int KeyPress::rewindKey = (0xffeeff03) | extendedKeyModifier; END_JUCE_NAMESPACE - -#endif diff --git a/build/macosx/platform_specific_code/juce_mac_AudioCDBurner.mm b/build/macosx/platform_specific_code/juce_mac_AudioCDBurner.mm index 5b371ff47a..d13a3b43d3 100644 --- a/build/macosx/platform_specific_code/juce_mac_AudioCDBurner.mm +++ b/build/macosx/platform_specific_code/juce_mac_AudioCDBurner.mm @@ -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; diff --git a/build/macosx/platform_specific_code/juce_mac_FileChooser.mm b/build/macosx/platform_specific_code/juce_mac_FileChooser.mm index 94fafaed2e..273261a4aa 100644 --- a/build/macosx/platform_specific_code/juce_mac_FileChooser.mm +++ b/build/macosx/platform_specific_code/juce_mac_FileChooser.mm @@ -37,6 +37,8 @@ END_JUCE_NAMESPACE using namespace JUCE_NAMESPACE; +#define JuceFileChooserDelegate MakeObjCClassName(JuceFileChooserDelegate) + @interface JuceFileChooserDelegate : NSObject { StringArray* filters; diff --git a/build/macosx/platform_specific_code/juce_mac_MainMenu.mm b/build/macosx/platform_specific_code/juce_mac_MainMenu.mm index c5f5ee7459..06e162486f 100644 --- a/build/macosx/platform_specific_code/juce_mac_MainMenu.mm +++ b/build/macosx/platform_specific_code/juce_mac_MainMenu.mm @@ -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(""), 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 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(""), 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 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 diff --git a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm index 8bbb23e18d..3241c8b0cf 100644 --- a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm +++ b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm @@ -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 diff --git a/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm b/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm index 87003ff9a9..06184674fd 100644 --- a/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm +++ b/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm @@ -35,19 +35,16 @@ class NSViewComponentPeer; -static int currentModifiers = 0; - //============================================================================== END_JUCE_NAMESPACE -static void updateModifiers (NSEvent* e); - -using namespace JUCE_NAMESPACE; +#define JuceNSView MakeObjCClassName(JuceNSView) @interface JuceNSView : NSView { @public NSViewComponentPeer* owner; + NSNotificationCenter* notificationCenter; } - (JuceNSView*) initWithOwner: (NSViewComponentPeer*) owner withFrame: (NSRect) frame; @@ -92,8 +89,11 @@ using namespace JUCE_NAMESPACE; @end //============================================================================== +#define JuceNSWindow MakeObjCClassName(JuceNSWindow) + @interface JuceNSWindow : NSWindow { +@private NSViewComponentPeer* owner; } @@ -139,15 +139,50 @@ public: void toFront (bool makeActiveWindow); void toBehind (ComponentPeer* other); void setIcon (const Image& newIcon); + + /* 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. + */ + virtual void redirectMouseDown (NSEvent* ev); + virtual void redirectMouseUp (NSEvent* ev); + virtual void redirectMouseDrag (NSEvent* ev); + virtual void redirectMouseMove (NSEvent* ev); + virtual void redirectMouseEnter (NSEvent* ev); + virtual void redirectMouseExit (NSEvent* ev); + virtual void redirectMouseWheel (NSEvent* ev); + bool handleKeyEvent (NSEvent* ev, bool isKeyDown); + virtual bool redirectKeyDown (NSEvent* ev); + virtual bool redirectKeyUp (NSEvent* ev); + virtual void redirectModKeyChange (NSEvent* ev); +#if MACOS_10_4_OR_EARLIER + virtual bool redirectPerformKeyEquivalent (NSEvent* ev); +#endif + + virtual BOOL sendDragCallback (int type, id sender); + + virtual bool isOpaque(); + virtual void drawRect (NSRect r); + + virtual bool canBecomeKeyWindow(); + virtual bool windowShouldClose(); + + virtual void redirectMovedOrResized(); + virtual NSRect constrainRect (NSRect r); //============================================================================== - void viewFocusGain(); - void viewFocusLoss(); + virtual void viewFocusGain(); + virtual void viewFocusLoss(); bool isFocused() const; void grabFocus(); void textInputRequired (int x, int y); - NSRect constrainRect (NSRect r); //============================================================================== void repaint (int x, int y, int w, int h); @@ -161,172 +196,6 @@ public: bool isSharedWindow, fullScreen; }; -//============================================================================== -class JuceNSImage -{ -public: - JuceNSImage (const int width, const int height, const bool hasAlpha) - : juceImage (hasAlpha ? Image::ARGB : Image::RGB, - width, height, hasAlpha) - { - lineStride = 0; - pixelStride = 0; - imageData = juceImage.lockPixelDataReadWrite (0, 0, width, height, - lineStride, pixelStride); - - imageRep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: &imageData - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: pixelStride - hasAlpha: hasAlpha - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 - bytesPerRow: lineStride - bitsPerPixel: 8 * pixelStride ]; - - juceImage.releasePixelDataReadWrite (imageData); - } - - ~JuceNSImage() - { - [imageRep release]; - } - - Image& getJuceImage() throw() { return juceImage; } - - void draw (const float x, const float y, - const RectangleList& clip, - const int originX, const int originY) const - { - // Our data is BGRA and the damned image rep only takes RGBA, so - // we need to byte-swap the active areas if there's an alpha channel... - if (juceImage.hasAlphaChannel()) - { - RectangleList::Iterator iter (clip); - while (iter.next()) - { - const Rectangle* const r = iter.getRectangle(); - - swapRGBOrder (r->getX() + originX, - r->getY() + originY, - r->getWidth(), - r->getHeight()); - } - } - - NSPoint p; - p.x = x; - p.y = y; - [imageRep drawAtPoint: p]; - } - - void drawNSImage (NSImage* imageToDraw) - { - const ScopedAutoReleasePool pool; - - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; - - [imageToDraw drawAtPoint: NSZeroPoint - fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) - operation: NSCompositeSourceOver - fraction: 1.0f]; - - [[NSGraphicsContext currentContext] flushGraphics]; - - if (juceImage.hasAlphaChannel()) - swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); - } - -private: - Image juceImage; - NSBitmapImageRep* imageRep; - uint8* imageData; - int pixelStride, lineStride; - - void swapRGBOrder (const int x, const int y, const int w, int h) const - { - jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) - .contains (Rectangle (x, y, w, h))); - - uint8* start = imageData + x * pixelStride + y * lineStride; - - while (--h >= 0) - { - uint8* p = start; - start += lineStride; - - for (int i = w; --i >= 0;) - { - const uint8 temp = p[0]; - p[0] = p[2]; - p[2] = temp; - - p += pixelStride; - } - } - } -}; - -//============================================================================== -static ComponentPeer* currentlyFocusedPeer = 0; -static VoidArray keysCurrentlyDown; - -bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() -{ - if (keysCurrentlyDown.contains ((void*) keyCode)) - return true; - - if (keyCode >= 'A' && keyCode <= 'Z' - && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toLowerCase ((tchar) keyCode))) - return true; - - if (keyCode >= 'a' && keyCode <= 'z' - && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toUpperCase ((tchar) keyCode))) - return true; - - return false; -} - -static int getKeyCodeFromEvent (NSEvent* ev) -{ - String unicode (nsStringToJuce ([ev characters])); - String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); - int keyCode = unmodified[0]; - - if (keyCode == 0x19) // (backwards-tab) - keyCode = 9; - - return keyCode; -} - -static void updateKeysDown (NSEvent* ev, bool isKeyDown) -{ - updateModifiers (ev); - int keyCode = getKeyCodeFromEvent (ev); - - if (keyCode != 0) - { - if (isKeyDown) - keysCurrentlyDown.addIfNotAlreadyThere ((void*) keyCode); - else - keysCurrentlyDown.removeValue ((void*) keyCode); - } -} - -const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() -{ - return ModifierKeys (currentModifiers); -} - -void ModifierKeys::updateCurrentModifiers() throw() -{ - currentModifierFlags = currentModifiers; -} - //============================================================================== END_JUCE_NAMESPACE @@ -338,19 +207,19 @@ END_JUCE_NAMESPACE [super initWithFrame: frame]; owner = owner_; - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector (frameChanged:) - name: NSViewFrameDidChangeNotification - object: self]; + notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter addObserver: self + selector: @selector (frameChanged:) + name: NSViewFrameDidChangeNotification + object: self]; if (! owner_->isSharedWindow) { - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector (frameChanged:) - name: NSWindowDidMoveNotification - object: owner_->window]; + [notificationCenter addObserver: self + selector: @selector (frameChanged:) + name: NSWindowDidMoveNotification + object: owner_->window]; } [self registerForDraggedTypes: [self getSupportedDragTypes]]; @@ -360,157 +229,57 @@ END_JUCE_NAMESPACE - (void) dealloc { - [[NSNotificationCenter defaultCenter] removeObserver: self]; + [notificationCenter removeObserver: self]; [super dealloc]; } //============================================================================== - (void) drawRect: (NSRect) r { - if (r.size.width < 1.0f || r.size.height < 1.0f || owner == 0) - return; - - const float y = [self frame].size.height - (r.origin.y + r.size.height); - - JuceNSImage temp ((int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! owner->getComponent()->isOpaque()); - - LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); - const int originX = -roundFloatToInt (r.origin.x); - const int originY = -roundFloatToInt (y); - context.setOrigin (originX, originY); - - const NSRect* rects = 0; - int numRects = 0; - [self getRectsBeingDrawn: &rects count: &numRects]; - - RectangleList clip; - for (int i = 0; i < numRects; ++i) - { - clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), - roundFloatToInt ([self frame].size.height - (rects[i].origin.y + rects[i].size.height)), - roundFloatToInt (rects[i].size.width), - roundFloatToInt (rects[i].size.height))); - } - - if (context.reduceClipRegion (clip)) - { - owner->handlePaint (context); - temp.draw (r.origin.x, r.origin.y, clip, originX, originY); - } + if (owner != 0) + owner->drawRect (r); } - (BOOL) isOpaque { - if (owner == 0) - return true; - - if (! owner->getComponent()->isValidComponent()) - return false; - - return owner->getComponent()->isOpaque(); + return owner == 0 || owner->isOpaque(); } //============================================================================== -static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } - -static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) -{ - NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; - x = roundFloatToInt (p.x); - y = roundFloatToInt ([view frame].size.height - p.y); -} - -static void updateModifiers (NSEvent* e) -{ - int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier - | ModifierKeys::altModifier | ModifierKeys::commandModifier); - - if (([e modifierFlags] & NSShiftKeyMask) != 0) - m |= ModifierKeys::shiftModifier; - - if (([e modifierFlags] & NSControlKeyMask) != 0) - m |= ModifierKeys::ctrlModifier; - - if (([e modifierFlags] & NSAlternateKeyMask) != 0) - m |= ModifierKeys::altModifier; - - if (([e modifierFlags] & NSCommandKeyMask) != 0) - m |= ModifierKeys::commandModifier; - - currentModifiers = m; -} - -static int getModifierForButtonNumber (const int num) throw() -{ - return num == 0 ? ModifierKeys::leftButtonModifier - : (num == 1 ? ModifierKeys::rightButtonModifier - : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); -} - - (void) mouseDown: (NSEvent*) ev { - updateModifiers (ev); - currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseDown (x, y, getMouseTime (ev)); + owner->redirectMouseDown (ev); } - (void) mouseUp: (NSEvent*) ev { - const int oldMods = currentModifiers; - updateModifiers (ev); - currentModifiers &= ~getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseUp (oldMods, x, y, getMouseTime (ev)); + owner->redirectMouseUp (ev); } - (void) mouseDragged: (NSEvent*) ev { - updateModifiers (ev); - currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseDrag (x, y, getMouseTime (ev)); + owner->redirectMouseDrag (ev); } - (void) mouseMoved: (NSEvent*) ev -{ - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - +{ if (owner != 0) - owner->handleMouseMove (x, y, getMouseTime (ev)); + owner->redirectMouseMove (ev); } - (void) mouseEntered: (NSEvent*) ev { - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseEnter (x, y, getMouseTime (ev)); + owner->redirectMouseEnter (ev); } - (void) mouseExited: (NSEvent*) ev { - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseExit (x, y, getMouseTime (ev)); + owner->redirectMouseExit (ev); } - (void) rightMouseDown: (NSEvent*) ev @@ -530,12 +299,8 @@ static int getModifierForButtonNumber (const int num) throw() - (void) scrollWheel: (NSEvent*) ev { - updateModifiers (ev); - if (owner != 0) - owner->handleMouseWheel (roundFloatToInt ([ev deltaX] * 10.0f), - roundFloatToInt ([ev deltaY] * 10.0f), - getMouseTime (ev)); + owner->redirectMouseWheel (ev); } - (BOOL) acceptsFirstMouse: (NSEvent*) ev @@ -546,61 +311,34 @@ static int getModifierForButtonNumber (const int num) throw() - (void) frameChanged: (NSNotification*) n { if (owner != 0) - owner->handleMovedOrResized(); + owner->redirectMovedOrResized(); } //============================================================================== - (void) keyDown: (NSEvent*) ev { - bool used = false; - - if (owner != 0) - { - updateKeysDown (ev, true); - used = owner->handleKeyEvent (ev, true); - - if (([ev modifierFlags] & NSCommandKeyMask) != 0) - { - // for command keys, the key-up event is thrown away, so simulate one.. - updateKeysDown (ev, false); - used = owner->handleKeyEvent (ev, false) || used; - } - } - - if (! used) + if (owner == 0 || ! owner->redirectKeyDown (ev)) [super keyDown: ev]; } - (void) keyUp: (NSEvent*) ev { - updateKeysDown (ev, false); - - if (owner == 0 || ! owner->handleKeyEvent (ev, false)) + if (owner == 0 || ! owner->redirectKeyUp (ev)) [super keyUp: ev]; } - (void) flagsChanged: (NSEvent*) ev { - updateModifiers (ev); - if (owner != 0) - owner->handleModifierKeysChange(); + owner->redirectModKeyChange (ev); } #if MACOS_10_4_OR_EARLIER - (BOOL) performKeyEquivalent: (NSEvent*) ev { - if (owner != 0) - { - updateKeysDown (ev, true); - const bool used1 = owner->handleKeyEvent (ev, true); - updateKeysDown (ev, false); - const bool used2 = owner->handleKeyEvent (ev, false); - - if (used1 || used2) - return true; - } - + if (owner != 0 && owner->redirectPerformKeyEquivalent (ev)) + return true; + return [super performKeyEquivalent: ev]; } #endif @@ -629,140 +367,297 @@ static int getModifierForButtonNumber (const int num) throw() - (BOOL) sendDragCallback: (int) type sender: (id ) sender { - NSString* bestType - = [[sender draggingPasteboard] availableTypeFromArray: [self getSupportedDragTypes]]; + return owner != 0 && owner->sendDragCallback (type, sender); +} - if (bestType == nil) - return false; +- (NSDragOperation) draggingEntered: (id ) sender +{ + if ([self sendDragCallback: 0 sender: sender]) + return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric; + else + return NSDragOperationNone; +} - NSPoint p = [self convertPoint: [sender draggingLocation] fromView: nil]; - int x = (int) p.x; - int y = (int) ([self frame].size.height - p.y); +- (NSDragOperation) draggingUpdated: (id ) sender +{ + if ([self sendDragCallback: 0 sender: sender]) + return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric; + else + return NSDragOperationNone; +} - StringArray files; +- (void) draggingEnded: (id ) sender +{ + [self sendDragCallback: 1 sender: sender]; +} - id list = [[sender draggingPasteboard] propertyListForType: bestType]; - if (list == nil) - return false; +- (void) draggingExited: (id ) sender +{ + [self sendDragCallback: 1 sender: sender]; +} - if ([list isKindOfClass: [NSArray class]]) +- (BOOL) prepareForDragOperation: (id ) sender +{ + return YES; +} + +- (BOOL) performDragOperation: (id ) sender +{ + return [self sendDragCallback: 2 sender: sender]; +} + +- (void) concludeDragOperation: (id ) sender +{ +} + +@end + +//============================================================================== +@implementation JuceNSWindow + +- (void) setOwner: (NSViewComponentPeer*) owner_ +{ + owner = owner_; +} + +- (BOOL) canBecomeKeyWindow +{ + return owner != 0 && owner->canBecomeKeyWindow(); +} + +- (BOOL) windowShouldClose: (id) window +{ + return owner == 0 || owner->windowShouldClose(); +} + +- (NSRect) constrainFrameRect: (NSRect) frameRect toScreen: (NSScreen*) screen +{ + if (owner != 0) + frameRect = owner->constrainRect (frameRect); + + return frameRect; +} + +- (NSSize) windowWillResize: (NSWindow*) window toSize: (NSSize) proposedFrameSize +{ + NSRect frameRect = [self frame]; + frameRect.size = proposedFrameSize; + + if (owner != 0) + frameRect = owner->constrainRect (frameRect); + + return frameRect.size; +} + +@end + +//============================================================================== +//============================================================================== +BEGIN_JUCE_NAMESPACE + +//============================================================================== +class JuceNSImage +{ +public: + JuceNSImage (const int width, const int height, const bool hasAlpha) + : juceImage (hasAlpha ? Image::ARGB : Image::RGB, + width, height, hasAlpha) { - NSArray* items = (NSArray*) list; + lineStride = 0; + pixelStride = 0; + imageData = juceImage.lockPixelDataReadWrite (0, 0, width, height, + lineStride, pixelStride); - for (int i = 0; i < [items count]; ++i) - files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i])); + imageRep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &imageData + pixelsWide: width + pixelsHigh: height + bitsPerSample: 8 + samplesPerPixel: pixelStride + hasAlpha: hasAlpha + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 + bytesPerRow: lineStride + bitsPerPixel: 8 * pixelStride ]; + + juceImage.releasePixelDataReadWrite (imageData); } - if (files.size() == 0) - return false; + ~JuceNSImage() + { + [imageRep release]; + } - if (type == 0) - owner->handleFileDragMove (files, x, y); - else if (type == 1) - owner->handleFileDragExit (files); - else if (type == 2) - owner->handleFileDragDrop (files, x, y); + Image& getJuceImage() throw() { return juceImage; } - return true; -} + void draw (const float x, const float y, + const RectangleList& clip, + const int originX, const int originY) const + { + // Our data is BGRA and the damned image rep only takes RGBA, so + // we need to byte-swap the active areas if there's an alpha channel... + if (juceImage.hasAlphaChannel()) + { + RectangleList::Iterator iter (clip); + while (iter.next()) + { + const Rectangle* const r = iter.getRectangle(); + + swapRGBOrder (r->getX() + originX, + r->getY() + originY, + r->getWidth(), + r->getHeight()); + } + } + + NSPoint p; + p.x = x; + p.y = y; + [imageRep drawAtPoint: p]; + } + + void drawNSImage (NSImage* imageToDraw) + { + const ScopedAutoReleasePool pool; + + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; + + [imageToDraw drawAtPoint: NSZeroPoint + fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) + operation: NSCompositeSourceOver + fraction: 1.0f]; + + [[NSGraphicsContext currentContext] flushGraphics]; + + if (juceImage.hasAlphaChannel()) + swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); + } + +private: + Image juceImage; + NSBitmapImageRep* imageRep; + uint8* imageData; + int pixelStride, lineStride; + + void swapRGBOrder (const int x, const int y, const int w, int h) const + { + jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) + .contains (Rectangle (x, y, w, h))); + + uint8* start = imageData + x * pixelStride + y * lineStride; + + while (--h >= 0) + { + uint8* p = start; + start += lineStride; + + for (int i = w; --i >= 0;) + { + const uint8 temp = p[0]; + p[0] = p[2]; + p[2] = temp; + + p += pixelStride; + } + } + } +}; + +//============================================================================== +static ComponentPeer* currentlyFocusedPeer = 0; +static VoidArray keysCurrentlyDown; + +bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() +{ + if (keysCurrentlyDown.contains ((void*) keyCode)) + return true; + + if (keyCode >= 'A' && keyCode <= 'Z' + && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toLowerCase ((tchar) keyCode))) + return true; -- (NSDragOperation) draggingEntered: (id ) sender -{ - if ([self sendDragCallback: 0 sender: sender]) - return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric; - else - return NSDragOperationNone; -} + if (keyCode >= 'a' && keyCode <= 'z' + && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toUpperCase ((tchar) keyCode))) + return true; -- (NSDragOperation) draggingUpdated: (id ) sender -{ - if ([self sendDragCallback: 0 sender: sender]) - return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric; - else - return NSDragOperationNone; + return false; } -- (void) draggingEnded: (id ) sender +static int getKeyCodeFromEvent (NSEvent* ev) { - [self sendDragCallback: 1 sender: sender]; -} + String unicode (nsStringToJuce ([ev characters])); + String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); + int keyCode = unmodified[0]; + + if (keyCode == 0x19) // (backwards-tab) + keyCode = 9; -- (void) draggingExited: (id ) sender -{ - [self sendDragCallback: 1 sender: sender]; + return keyCode; } -- (BOOL) prepareForDragOperation: (id ) sender -{ - return YES; -} +static int currentModifiers = 0; -- (BOOL) performDragOperation: (id ) sender +static void updateModifiers (NSEvent* e) { - return [self sendDragCallback: 2 sender: sender]; -} + int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier + | ModifierKeys::altModifier | ModifierKeys::commandModifier); -- (void) concludeDragOperation: (id ) sender -{ -} + if (([e modifierFlags] & NSShiftKeyMask) != 0) + m |= ModifierKeys::shiftModifier; -@end + if (([e modifierFlags] & NSControlKeyMask) != 0) + m |= ModifierKeys::ctrlModifier; -//============================================================================== -@implementation JuceNSWindow + if (([e modifierFlags] & NSAlternateKeyMask) != 0) + m |= ModifierKeys::altModifier; -- (void) setOwner: (NSViewComponentPeer*) owner_ -{ - owner = owner_; -} + if (([e modifierFlags] & NSCommandKeyMask) != 0) + m |= ModifierKeys::commandModifier; -- (BOOL) canBecomeKeyWindow -{ - // If runnin as a plugin, let the component decide whether it's - // going to allow the window to get focused. - return JUCEApplication::getInstance() != 0 - || (ComponentPeer::isValidPeer (owner) - && owner->getComponent()->getWantsKeyboardFocus()); + currentModifiers = m; } -- (BOOL) windowShouldClose: (id) window +static void updateKeysDown (NSEvent* ev, bool isKeyDown) { - if (! ComponentPeer::isValidPeer (owner)) - return YES; + updateModifiers (ev); + int keyCode = getKeyCodeFromEvent (ev); - owner->handleUserClosingWindow(); - return NO; + if (keyCode != 0) + { + if (isKeyDown) + keysCurrentlyDown.addIfNotAlreadyThere ((void*) keyCode); + else + keysCurrentlyDown.removeValue ((void*) keyCode); + } } -- (NSRect) constrainFrameRect: (NSRect) frameRect toScreen: (NSScreen*) screen +const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() { - if (owner == 0) - return frameRect; - -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - frameRect = owner->constrainRect (frameRect); -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - return frameRect; + return ModifierKeys (currentModifiers); } -- (NSSize) windowWillResize: (NSWindow*) window toSize: (NSSize) proposedFrameSize +void ModifierKeys::updateCurrentModifiers() throw() { - if (owner == 0) - return proposedFrameSize; + currentModifierFlags = currentModifiers; +} - NSRect frameRect = [self frame]; - frameRect.size = proposedFrameSize; +static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - frameRect = owner->constrainRect (frameRect); -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - return frameRect.size; +static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) +{ + NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; + x = roundFloatToInt (p.x); + y = roundFloatToInt ([view frame].size.height - p.y); } -@end - -//============================================================================== -BEGIN_JUCE_NAMESPACE +static int getModifierForButtonNumber (const int num) throw() +{ + return num == 0 ? ModifierKeys::leftButtonModifier + : (num == 1 ? ModifierKeys::rightButtonModifier + : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); +} //============================================================================== NSViewComponentPeer::NSViewComponentPeer (Component* const component, @@ -839,7 +734,10 @@ NSViewComponentPeer::~NSViewComponentPeer() [view release]; if (! isSharedWindow) + { + [((JuceNSWindow*) window) setOwner: 0]; [window close]; + } } //============================================================================== @@ -1224,6 +1122,218 @@ bool NSViewComponentPeer::handleKeyEvent (NSEvent* ev, bool isKeyDown) return false; } +//============================================================================== +void NSViewComponentPeer::redirectMouseDown (NSEvent* ev) +{ + updateModifiers (ev); + currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseDown (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseUp (NSEvent* ev) +{ + const int oldMods = currentModifiers; + updateModifiers (ev); + currentModifiers &= ~getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseUp (oldMods, x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseDrag (NSEvent* ev) +{ + updateModifiers (ev); + currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseDrag (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseMove (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseMove (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseEnter (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseEnter (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseExit (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseExit (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseWheel (NSEvent* ev) +{ + updateModifiers (ev); + + handleMouseWheel (roundFloatToInt ([ev deltaX] * 10.0f), + roundFloatToInt ([ev deltaY] * 10.0f), + getMouseTime (ev)); +} + +//============================================================================== +bool NSViewComponentPeer::redirectKeyDown (NSEvent* ev) +{ + updateKeysDown (ev, true); + bool used = handleKeyEvent (ev, true); + + if (([ev modifierFlags] & NSCommandKeyMask) != 0) + { + // for command keys, the key-up event is thrown away, so simulate one.. + updateKeysDown (ev, false); + used = (isValidPeer (this) && handleKeyEvent (ev, false)) || used; + } + + return used; +} + +bool NSViewComponentPeer::redirectKeyUp (NSEvent* ev) +{ + updateKeysDown (ev, false); + return handleKeyEvent (ev, false); +} + +void NSViewComponentPeer::redirectModKeyChange (NSEvent* ev) +{ + updateModifiers (ev); + handleModifierKeysChange(); +} + +#if MACOS_10_4_OR_EARLIER +bool NSViewComponentPeer::redirectPerformKeyEquivalent (NSEvent* ev) +{ + updateKeysDown (ev, true); + const bool used1 = isValidPeer (this) && handleKeyEvent (ev, true); + updateKeysDown (ev, false); + const bool used2 = isValidPeer (this) && handleKeyEvent (ev, false); + + return used1 || used2; +} +#endif + +BOOL NSViewComponentPeer::sendDragCallback (int type, id sender) +{ + NSString* bestType + = [[sender draggingPasteboard] availableTypeFromArray: [view getSupportedDragTypes]]; + + if (bestType == nil) + return false; + + NSPoint p = [view convertPoint: [sender draggingLocation] fromView: nil]; + int x = (int) p.x; + int y = (int) ([view frame].size.height - p.y); + + StringArray files; + + id list = [[sender draggingPasteboard] propertyListForType: bestType]; + if (list == nil) + return false; + + if ([list isKindOfClass: [NSArray class]]) + { + NSArray* items = (NSArray*) list; + + for (int i = 0; i < [items count]; ++i) + files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i])); + } + + if (files.size() == 0) + return false; + + if (type == 0) + handleFileDragMove (files, x, y); + else if (type == 1) + handleFileDragExit (files); + else if (type == 2) + handleFileDragDrop (files, x, y); + + return true; +} + +bool NSViewComponentPeer::isOpaque() +{ + if (! getComponent()->isValidComponent()) + return true; + + return getComponent()->isOpaque(); +} + +void NSViewComponentPeer::drawRect (NSRect r) +{ + if (r.size.width < 1.0f || r.size.height < 1.0f) + return; + + const float y = [view frame].size.height - (r.origin.y + r.size.height); + + JuceNSImage temp ((int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); + + LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); + const int originX = -roundFloatToInt (r.origin.x); + const int originY = -roundFloatToInt (y); + context.setOrigin (originX, originY); + + const NSRect* rects = 0; + int numRects = 0; + [view getRectsBeingDrawn: &rects count: &numRects]; + + RectangleList clip; + for (int i = 0; i < numRects; ++i) + { + clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), + roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), + roundFloatToInt (rects[i].size.width), + roundFloatToInt (rects[i].size.height))); + } + + if (context.reduceClipRegion (clip)) + { + handlePaint (context); + temp.draw (r.origin.x, r.origin.y, clip, originX, originY); + } +} + +bool NSViewComponentPeer::canBecomeKeyWindow() +{ + // If running as a plugin, let the component decide whether it's going to allow the window to get focused. + return JUCEApplication::getInstance() != 0 + || (isValidPeer (this) && getComponent()->getWantsKeyboardFocus()); +} + +bool NSViewComponentPeer::windowShouldClose() +{ + if (! isValidPeer (this)) + return YES; + + handleUserClosingWindow(); + return NO; +} + +void NSViewComponentPeer::redirectMovedOrResized() +{ + handleMovedOrResized(); +} + //============================================================================== void NSViewComponentPeer::repaint (int x, int y, int w, int h) { diff --git a/build/macosx/platform_specific_code/juce_mac_NativeCode.mm b/build/macosx/platform_specific_code/juce_mac_NativeCode.mm index 62201da71e..f9c5d955c1 100644 --- a/build/macosx/platform_specific_code/juce_mac_NativeCode.mm +++ b/build/macosx/platform_specific_code/juce_mac_NativeCode.mm @@ -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 diff --git a/build/macosx/platform_specific_code/juce_mac_Network.mm b/build/macosx/platform_specific_code/juce_mac_Network.mm index d21ecc32e3..51a9dca195 100644 --- a/build/macosx/platform_specific_code/juce_mac_Network.mm +++ b/build/macosx/platform_specific_code/juce_mac_Network.mm @@ -166,6 +166,8 @@ END_JUCE_NAMESPACE using namespace JUCE_NAMESPACE; //============================================================================== +#define JuceURLConnection MakeObjCClassName(JuceURLConnection) + @interface JuceURLConnection : NSObject { NSURLRequest* request; diff --git a/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm b/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm index 7d8221566d..b7716eaff5 100644 --- a/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm +++ b/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm @@ -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 & 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 & 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 diff --git a/build/macosx/platform_specific_code/juce_mac_QuickTimeMovieComponent.mm b/build/macosx/platform_specific_code/juce_mac_QuickTimeMovieComponent.mm index 6c12dfa46f..1b0f32a8e3 100644 --- a/build/macosx/platform_specific_code/juce_mac_QuickTimeMovieComponent.mm +++ b/build/macosx/platform_specific_code/juce_mac_QuickTimeMovieComponent.mm @@ -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 (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 (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]; diff --git a/build/macosx/platform_specific_code/juce_mac_SystemStats.mm b/build/macosx/platform_specific_code/juce_mac_SystemStats.mm index c7e2bbff1b..2132e8ac1d 100644 --- a/build/macosx/platform_specific_code/juce_mac_SystemStats.mm +++ b/build/macosx/platform_specific_code/juce_mac_SystemStats.mm @@ -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 diff --git a/build/macosx/platform_specific_code/juce_mac_WebBrowserComponent.mm b/build/macosx/platform_specific_code/juce_mac_WebBrowserComponent.mm index fe05bf578c..109cb0b25f 100644 --- a/build/macosx/platform_specific_code/juce_mac_WebBrowserComponent.mm +++ b/build/macosx/platform_specific_code/juce_mac_WebBrowserComponent.mm @@ -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 ) 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]; diff --git a/extras/amalgamator/juce_AppConfig.h b/extras/amalgamator/juce_AppConfig.h index fa05cdb520..8095704736 100644 --- a/extras/amalgamator/juce_AppConfig.h +++ b/extras/amalgamator/juce_AppConfig.h @@ -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 diff --git a/extras/audio plugin host/src/juce_AppConfig.h b/extras/audio plugin host/src/juce_AppConfig.h index 08968f08e1..2d28ed0bdf 100644 --- a/extras/audio plugin host/src/juce_AppConfig.h +++ b/extras/audio plugin host/src/juce_AppConfig.h @@ -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 diff --git a/extras/binarybuilder/juce_AppConfig.h b/extras/binarybuilder/juce_AppConfig.h index fa05cdb520..8095704736 100644 --- a/extras/binarybuilder/juce_AppConfig.h +++ b/extras/binarybuilder/juce_AppConfig.h @@ -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 diff --git a/extras/example projects/common/juce_AppConfig.h b/extras/example projects/common/juce_AppConfig.h index fe77e6a598..0a7095627b 100644 --- a/extras/example projects/common/juce_AppConfig.h +++ b/extras/example projects/common/juce_AppConfig.h @@ -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 diff --git a/extras/juce demo/src/juce_AppConfig.h b/extras/juce demo/src/juce_AppConfig.h index 8fce15e0ba..330ec8f9da 100644 --- a/extras/juce demo/src/juce_AppConfig.h +++ b/extras/juce demo/src/juce_AppConfig.h @@ -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 diff --git a/extras/the jucer/src/juce_AppConfig.h b/extras/the jucer/src/juce_AppConfig.h index 8fce15e0ba..330ec8f9da 100644 --- a/extras/the jucer/src/juce_AppConfig.h +++ b/extras/the jucer/src/juce_AppConfig.h @@ -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 diff --git a/juce_Config.h b/juce_Config.h index 57c67807b8..e1b01552ce 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -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. diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index dac5a7599a..b86c917bf3 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -173,14 +173,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. @@ -377,14 +375,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. @@ -18876,14 +18872,12 @@ END_JUCE_NAMESPACE // #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. @@ -21864,27 +21858,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!"; @@ -21909,10 +21905,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(); } @@ -27503,14 +27499,12 @@ END_JUCE_NAMESPACE // #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. @@ -28918,14 +28912,12 @@ END_JUCE_NAMESPACE // #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. @@ -44336,6 +44328,8 @@ void Slider::lookAndFeelChanged() if (style == LinearBar) valueBox->addMouseListener (this, false); + + valueBox->setTooltip (getTooltip()); } if (style == IncDecButtons) @@ -98816,14 +98810,12 @@ END_JUCE_NAMESPACE // #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. @@ -106030,14 +106022,12 @@ done1: // #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. @@ -106378,14 +106368,12 @@ unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v) // #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. @@ -108071,14 +108059,12 @@ FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *v // #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. @@ -109407,14 +109393,12 @@ FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) // #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. @@ -110012,14 +109996,12 @@ void FLAC__cpu_info(FLAC__CPUInfo *info) // #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. @@ -110341,14 +110323,12 @@ unsigned FLAC__crc16(const FLAC__byte *data, unsigned len) // #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. @@ -111110,14 +111090,12 @@ void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, // #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. @@ -111604,14 +111582,12 @@ FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned p // #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. @@ -112386,14 +112362,12 @@ FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_s // #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. @@ -114132,14 +114106,12 @@ unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned m // #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. @@ -114819,14 +114791,12 @@ FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const // #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. @@ -115251,14 +115221,12 @@ FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real * // #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. @@ -118843,14 +118811,12 @@ FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_d // #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. @@ -123508,14 +123474,12 @@ FILE *get_binary_stdout_(void) // #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. @@ -124248,14 +124212,12 @@ FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 // #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. @@ -125156,14 +125118,12 @@ END_JUCE_NAMESPACE // #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. @@ -126122,14 +126082,12 @@ extern int ov_halfrate_p(OggVorbis_File *vf); // #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. @@ -127097,14 +127055,12 @@ int main(void){ // #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. @@ -129074,14 +129030,12 @@ int main(void){ // #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. @@ -130423,14 +130377,12 @@ void _analysis_output(char *base,int i,float *v,int n,int bark,int dB, // #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. @@ -130864,14 +130816,12 @@ int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ // #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. @@ -132046,14 +131996,12 @@ float *vorbis_window(vorbis_dsp_state *v,int W){ // #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. @@ -132843,14 +132791,12 @@ int main(){ // #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. @@ -133405,14 +133351,12 @@ void _ve_envelope_shift(envelope_lookup *e,long shift){ // #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. @@ -133822,14 +133766,12 @@ vorbis_func_floor floor0_exportbundle={ // #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. @@ -135075,14 +135017,12 @@ vorbis_func_floor floor1_exportbundle={ // #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. @@ -135885,14 +135825,12 @@ Carsten Bormann // #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. @@ -136201,14 +136139,12 @@ void vorbis_lpc_predict(float *coeff,float *prime,int m, // #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. @@ -136448,14 +136384,12 @@ extern float vorbis_fromdBlook_i(long a); // #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. @@ -136987,14 +136921,12 @@ void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, // #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. @@ -137805,14 +137737,12 @@ int vorbis_lpc_to_lsp(float *lpc,float *lsp,int m){ // #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. @@ -138829,14 +138759,12 @@ vorbis_func_mapping mapping0_exportbundle={ // #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. @@ -139561,14 +139489,12 @@ void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){ // #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. @@ -141735,14 +141661,12 @@ void hf_reduction(vorbis_info_psy_global *g, // #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. @@ -141976,14 +141900,12 @@ vorbis_func_mapping *_mapping_P[]={ // #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. @@ -143052,14 +142974,12 @@ vorbis_func_residue residue2_exportbundle={ // #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. @@ -143979,14 +143899,12 @@ int main(){ // #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. @@ -145413,14 +145331,12 @@ void drft_clear(drft_lookup *l){ // #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. @@ -145771,14 +145687,12 @@ int vorbis_synthesis_halfrate_p(vorbis_info *vi){ // #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. @@ -184320,14 +184234,12 @@ int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){ // #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. @@ -186489,14 +186401,12 @@ int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){ // #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. @@ -252999,14 +252909,12 @@ END_JUCE_NAMESPACE // #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. @@ -254987,7 +254895,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); @@ -255002,6 +254911,7 @@ void* PlatformUtilities::getProcedureEntryPoint (void* libraryHandle, const Stri { return dlsym (libraryHandle, (const char*) procedureName); } + #endif END_JUCE_NAMESPACE @@ -255140,14 +255050,12 @@ END_JUCE_NAMESPACE // #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. @@ -255207,8 +255115,6 @@ END_JUCE_NAMESPACE #endif /********* End of inlined file: juce_Config.h *********/ -#if JUCE_BUILD_GUI_CLASSES - #if JUCE_ALSA /* Got an include error here? If so, you've either not got ALSA installed, or you've @@ -256178,8 +256084,6 @@ AudioIODeviceType* juce_createDefaultAudioIODeviceType() { return 0; } END_JUCE_NAMESPACE -#endif - #endif /********* End of inlined file: juce_linux_Audio.cpp *********/ @@ -256391,14 +256295,227 @@ END_JUCE_NAMESPACE // #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. +*/ +#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. +*/ +#ifndef JUCE_WEB_BROWSER + #define JUCE_WEB_BROWSER 1 +#endif + +/* These flags let you avoid the direct inclusion of some 3rd-party libs in the + codebase - you might need to use this if you're linking to some of these libraries + yourself. +*/ +#ifndef JUCE_INCLUDE_ZLIB_CODE + #define JUCE_INCLUDE_ZLIB_CODE 1 +#endif + +#ifndef JUCE_INCLUDE_FLAC_CODE + #define JUCE_INCLUDE_FLAC_CODE 1 +#endif + +#ifndef JUCE_INCLUDE_OGGVORBIS_CODE + #define JUCE_INCLUDE_OGGVORBIS_CODE 1 +#endif + +#ifndef JUCE_INCLUDE_PNGLIB_CODE + #define JUCE_INCLUDE_PNGLIB_CODE 1 +#endif + +#ifndef JUCE_INCLUDE_JPEGLIB_CODE + #define JUCE_INCLUDE_JPEGLIB_CODE 1 +#endif + +/** Enable this to add extra memory-leak info to the new and delete operators. + + (Currently, this only affects Windows builds in debug mode). +*/ +#ifndef JUCE_CHECK_MEMORY_LEAKS + #define JUCE_CHECK_MEMORY_LEAKS 1 +#endif + +/** Enable this to turn on juce's internal catching of exceptions. + + Turning it off will avoid any exception catching. With it on, all exceptions + are passed to the JUCEApplication::unhandledException() callback for logging. +*/ +#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS + #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 +#endif + +/** If this macro is set, the Juce String class will use unicode as its + internal representation. If it isn't set, it'll use ANSI. +*/ +#ifndef JUCE_STRINGS_ARE_UNICODE + #define JUCE_STRINGS_ARE_UNICODE 1 +#endif + +#endif +/********* End of inlined file: juce_Config.h *********/ + +BEGIN_JUCE_NAMESPACE + +void FileChooser::showPlatformDialog (OwnedArray& results, + const String& title, + const File& file, + const String& filters, + bool isDirectory, + bool isSave, + bool warnAboutOverwritingExistingFiles, + bool selectMultipleFiles, + FilePreviewComponent* previewComponent) +{ + //xxx ain't got one! + jassertfalse +} + +END_JUCE_NAMESPACE +/********* End of inlined file: juce_linux_FileChooser.cpp *********/ + +/********* Start of inlined file: juce_linux_Fonts.cpp *********/ + +/********* Start of inlined file: juce_Config.h *********/ +#ifndef __JUCE_CONFIG_JUCEHEADER__ +#define __JUCE_CONFIG_JUCEHEADER__ // (this comment is here to force the amalgamator to reinclude this file) + +/* + This file contains macros that enable/disable various JUCE features. +*/ + +/** The name of the namespace that all Juce classes and functions will be + put inside. If this is not defined, no namespace will be used. +*/ +#ifndef JUCE_NAMESPACE + #define JUCE_NAMESPACE juce +#endif + +/** Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings, + but if you define this value, you can override this can force it to be true or + false. +*/ +#ifndef JUCE_FORCE_DEBUG + //#define JUCE_FORCE_DEBUG 1 +#endif + +/** If this flag is enabled, the the jassert and jassertfalse macros will + always use Logger::writeToLog() to write a message when an assertion happens. + + Enabling it will also leave this turned on in release builds. When it's disabled, + however, the jassert and jassertfalse macros will not be compiled in a + release build. + + @see jassert, jassertfalse, Logger +*/ +#ifndef JUCE_LOG_ASSERTIONS +// #define JUCE_LOG_ASSERTIONS 1 +#endif + +/** Comment out this macro if you haven't got the Steinberg ASIO SDK, without + which the ASIOAudioIODevice class can't be built. See the comments in the + ASIOAudioIODevice class's header file for more info about this. + + (This only affects a Win32 build) +*/ +#ifndef JUCE_ASIO + #define JUCE_ASIO 1 +#endif + +/** Comment out this macro to disable building of ALSA device support on Linux. +*/ +#ifndef JUCE_ALSA + #define JUCE_ALSA 1 +#endif + +/** Comment out this macro if you don't want to enable QuickTime or if you don't + have the SDK installed. + + If this flag is not enabled, the QuickTimeMovieComponent and QuickTimeAudioFormat + classes will be unavailable. + + On Windows, if you enable this, you'll need to have the QuickTime SDK + installed, and its header files will need to be on your include path. +*/ +#if ! (defined (JUCE_QUICKTIME) || defined (LINUX) || (defined (_WIN32) && ! defined (_MSC_VER))) + #define JUCE_QUICKTIME 1 +#endif + +/** Comment out this macro if you don't want to enable OpenGL or if you don't + have the appropriate headers and libraries available. If it's not enabled, the + OpenGLComponent class will be unavailable. +*/ +#ifndef JUCE_OPENGL + #define JUCE_OPENGL 1 +#endif + +/** These flags enable the Ogg-Vorbis and Flac audio formats. + + If you're not going to need either of these formats, turn off the flags to + avoid bloating your codebase with them. +*/ +#ifndef JUCE_USE_FLAC + #define JUCE_USE_FLAC 1 +#endif + +#ifndef JUCE_USE_OGGVORBIS + #define JUCE_USE_OGGVORBIS 1 +#endif - (On mac and windows, this won't generally make much difference to the build). +/** This flag lets you enable support for CD-burning. You might want to disable + it to build without the MS SDK under windows. +*/ +#if (! defined (JUCE_USE_CDBURNER)) && ! (defined (_WIN32) && ! defined (_MSC_VER)) + #define JUCE_USE_CDBURNER 1 +#endif + +/** Enabling this macro means that all regions that get repainted will have a coloured + line drawn around them. + + This is handy if you're trying to optimise drawing, because it lets you easily see + when anything is being repainted unnecessarily. +*/ +#ifndef JUCE_ENABLE_REPAINT_DEBUGGING +// #define JUCE_ENABLE_REPAINT_DEBUGGING 1 +#endif + +/** Enable this under Linux to use Xinerama for multi-monitor support. +*/ +#ifndef JUCE_USE_XINERAMA + #define JUCE_USE_XINERAMA 1 +#endif + +/** Enable this under Linux to use XShm for faster shared-memory rendering. +*/ +#ifndef JUCE_USE_XSHM + #define JUCE_USE_XSHM 1 +#endif + +/** Enabling this builds support for VST audio plugins. + @see VSTPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU +*/ +#ifndef JUCE_PLUGINHOST_VST +// #define JUCE_PLUGINHOST_VST 1 +#endif + +/** Enabling this builds support for AudioUnit audio plugins. + @see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST +*/ +#ifndef JUCE_PLUGINHOST_AU +// #define JUCE_PLUGINHOST_AU 1 +#endif + +/** 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. */ -#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. @@ -256458,229 +256575,6 @@ END_JUCE_NAMESPACE #endif /********* End of inlined file: juce_Config.h *********/ -#if JUCE_BUILD_GUI_CLASSES - -BEGIN_JUCE_NAMESPACE - -void FileChooser::showPlatformDialog (OwnedArray& results, - const String& title, - const File& file, - const String& filters, - bool isDirectory, - bool isSave, - bool warnAboutOverwritingExistingFiles, - bool selectMultipleFiles, - FilePreviewComponent* previewComponent) -{ - //xxx ain't got one! - jassertfalse -} - -END_JUCE_NAMESPACE - -#endif -/********* End of inlined file: juce_linux_FileChooser.cpp *********/ - -/********* Start of inlined file: juce_linux_Fonts.cpp *********/ - -/********* Start of inlined file: juce_Config.h *********/ -#ifndef __JUCE_CONFIG_JUCEHEADER__ -#define __JUCE_CONFIG_JUCEHEADER__ // (this comment is here to force the amalgamator to reinclude this file) - -/* - This file contains macros that enable/disable various JUCE features. -*/ - -/** The name of the namespace that all Juce classes and functions will be - put inside. If this is not defined, no namespace will be used. -*/ -#ifndef JUCE_NAMESPACE - #define JUCE_NAMESPACE juce -#endif - -/** Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings, - but if you define this value, you can override this can force it to be true or - false. -*/ -#ifndef JUCE_FORCE_DEBUG - //#define JUCE_FORCE_DEBUG 1 -#endif - -/** If this flag is enabled, the the jassert and jassertfalse macros will - always use Logger::writeToLog() to write a message when an assertion happens. - - Enabling it will also leave this turned on in release builds. When it's disabled, - however, the jassert and jassertfalse macros will not be compiled in a - release build. - - @see jassert, jassertfalse, Logger -*/ -#ifndef JUCE_LOG_ASSERTIONS -// #define JUCE_LOG_ASSERTIONS 1 -#endif - -/** Comment out this macro if you haven't got the Steinberg ASIO SDK, without - which the ASIOAudioIODevice class can't be built. See the comments in the - ASIOAudioIODevice class's header file for more info about this. - - (This only affects a Win32 build) -*/ -#ifndef JUCE_ASIO - #define JUCE_ASIO 1 -#endif - -/** Comment out this macro to disable building of ALSA device support on Linux. -*/ -#ifndef JUCE_ALSA - #define JUCE_ALSA 1 -#endif - -/** Comment out this macro if you don't want to enable QuickTime or if you don't - have the SDK installed. - - If this flag is not enabled, the QuickTimeMovieComponent and QuickTimeAudioFormat - classes will be unavailable. - - On Windows, if you enable this, you'll need to have the QuickTime SDK - installed, and its header files will need to be on your include path. -*/ -#if ! (defined (JUCE_QUICKTIME) || defined (LINUX) || (defined (_WIN32) && ! defined (_MSC_VER))) - #define JUCE_QUICKTIME 1 -#endif - -/** Comment out this macro if you don't want to enable OpenGL or if you don't - have the appropriate headers and libraries available. If it's not enabled, the - OpenGLComponent class will be unavailable. -*/ -#ifndef JUCE_OPENGL - #define JUCE_OPENGL 1 -#endif - -/** These flags enable the Ogg-Vorbis and Flac audio formats. - - If you're not going to need either of these formats, turn off the flags to - avoid bloating your codebase with them. -*/ -#ifndef JUCE_USE_FLAC - #define JUCE_USE_FLAC 1 -#endif - -#ifndef JUCE_USE_OGGVORBIS - #define JUCE_USE_OGGVORBIS 1 -#endif - -/** This flag lets you enable support for CD-burning. You might want to disable - it to build without the MS SDK under windows. -*/ -#if (! defined (JUCE_USE_CDBURNER)) && ! (defined (_WIN32) && ! defined (_MSC_VER)) - #define JUCE_USE_CDBURNER 1 -#endif - -/** Enabling this macro means that all regions that get repainted will have a coloured - line drawn around them. - - This is handy if you're trying to optimise drawing, because it lets you easily see - when anything is being repainted unnecessarily. -*/ -#ifndef JUCE_ENABLE_REPAINT_DEBUGGING -// #define JUCE_ENABLE_REPAINT_DEBUGGING 1 -#endif - -/** Enable this under Linux to use Xinerama for multi-monitor support. -*/ -#ifndef JUCE_USE_XINERAMA - #define JUCE_USE_XINERAMA 1 -#endif - -/** Enable this under Linux to use XShm for faster shared-memory rendering. -*/ -#ifndef JUCE_USE_XSHM - #define JUCE_USE_XSHM 1 -#endif - -/** Enabling this builds support for VST audio plugins. - @see VSTPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU -*/ -#ifndef JUCE_PLUGINHOST_VST -// #define JUCE_PLUGINHOST_VST 1 -#endif - -/** Enabling this builds support for AudioUnit audio plugins. - @see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST -*/ -#ifndef JUCE_PLUGINHOST_AU -// #define JUCE_PLUGINHOST_AU 1 -#endif - -/** Disabling this will avoid linking to any UI code. 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 -#endif - -/** This lets you disable building of the WebBrowserComponent, if it's not required. -*/ -#ifndef JUCE_WEB_BROWSER - #define JUCE_WEB_BROWSER 1 -#endif - -/* These flags let you avoid the direct inclusion of some 3rd-party libs in the - codebase - you might need to use this if you're linking to some of these libraries - yourself. -*/ -#ifndef JUCE_INCLUDE_ZLIB_CODE - #define JUCE_INCLUDE_ZLIB_CODE 1 -#endif - -#ifndef JUCE_INCLUDE_FLAC_CODE - #define JUCE_INCLUDE_FLAC_CODE 1 -#endif - -#ifndef JUCE_INCLUDE_OGGVORBIS_CODE - #define JUCE_INCLUDE_OGGVORBIS_CODE 1 -#endif - -#ifndef JUCE_INCLUDE_PNGLIB_CODE - #define JUCE_INCLUDE_PNGLIB_CODE 1 -#endif - -#ifndef JUCE_INCLUDE_JPEGLIB_CODE - #define JUCE_INCLUDE_JPEGLIB_CODE 1 -#endif - -/** Enable this to add extra memory-leak info to the new and delete operators. - - (Currently, this only affects Windows builds in debug mode). -*/ -#ifndef JUCE_CHECK_MEMORY_LEAKS - #define JUCE_CHECK_MEMORY_LEAKS 1 -#endif - -/** Enable this to turn on juce's internal catching of exceptions. - - Turning it off will avoid any exception catching. With it on, all exceptions - are passed to the JUCEApplication::unhandledException() callback for logging. -*/ -#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS - #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 -#endif - -/** If this macro is set, the Juce String class will use unicode as its - internal representation. If it isn't set, it'll use ANSI. -*/ -#ifndef JUCE_STRINGS_ARE_UNICODE - #define JUCE_STRINGS_ARE_UNICODE 1 -#endif - -#endif -/********* End of inlined file: juce_Config.h *********/ - -#if JUCE_BUILD_GUI_CLASSES - /* Got a build error here? You'll need to install the freetype library... The name of the package to install is "libfreetype6-dev". @@ -257270,8 +257164,6 @@ void Font::getDefaultFontNames (String& defaultSans, String& defaultSerif, Strin } END_JUCE_NAMESPACE - -#endif /********* End of inlined file: juce_linux_Fonts.cpp *********/ /********* Start of inlined file: juce_linux_Messaging.cpp *********/ @@ -257405,14 +257297,12 @@ END_JUCE_NAMESPACE // #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. @@ -257472,8 +257362,6 @@ END_JUCE_NAMESPACE #endif /********* End of inlined file: juce_Config.h *********/ -#if JUCE_BUILD_GUI_CLASSES - #include #include #include @@ -257853,8 +257741,6 @@ bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) } END_JUCE_NAMESPACE - -#endif /********* End of inlined file: juce_linux_Messaging.cpp *********/ /********* Start of inlined file: juce_linux_Midi.cpp *********/ @@ -257988,14 +257874,12 @@ END_JUCE_NAMESPACE // #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. @@ -258055,8 +257939,6 @@ END_JUCE_NAMESPACE #endif /********* End of inlined file: juce_Config.h *********/ -#if JUCE_BUILD_GUI_CLASSES - #if JUCE_ALSA #include @@ -258486,8 +258368,6 @@ MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { re END_JUCE_NAMESPACE -#endif - #endif /********* End of inlined file: juce_linux_Midi.cpp *********/ @@ -258719,14 +258599,12 @@ END_JUCE_NAMESPACE // #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. @@ -258786,8 +258664,6 @@ END_JUCE_NAMESPACE #endif /********* End of inlined file: juce_Config.h *********/ -#if JUCE_BUILD_GUI_CLASSES - #include #include #include @@ -262039,8 +261915,6 @@ const int KeyPress::fastForwardKey = (0xffeeff02) | extendedKeyModifier; const int KeyPress::rewindKey = (0xffeeff03) | extendedKeyModifier; END_JUCE_NAMESPACE - -#endif /********* End of inlined file: juce_linux_Windowing.cpp *********/ #endif @@ -262062,6 +261936,11 @@ BEGIN_JUCE_NAMESPACE #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 // Now include the actual code files.. @@ -262279,7 +262158,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 @@ -262625,6 +262507,8 @@ END_JUCE_NAMESPACE using namespace JUCE_NAMESPACE; +#define JuceURLConnection MakeObjCClassName(JuceURLConnection) + @interface JuceURLConnection : NSObject { NSURLRequest* request; @@ -264176,18 +264060,15 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw() class NSViewComponentPeer; -static int currentModifiers = 0; - END_JUCE_NAMESPACE -static void updateModifiers (NSEvent* e); - -using namespace JUCE_NAMESPACE; +#define JuceNSView MakeObjCClassName(JuceNSView) @interface JuceNSView : NSView { @public NSViewComponentPeer* owner; + NSNotificationCenter* notificationCenter; } - (JuceNSView*) initWithOwner: (NSViewComponentPeer*) owner withFrame: (NSRect) frame; @@ -264231,8 +264112,11 @@ using namespace JUCE_NAMESPACE; @end +#define JuceNSWindow MakeObjCClassName(JuceNSWindow) + @interface JuceNSWindow : NSWindow { +@private NSViewComponentPeer* owner; } @@ -264276,14 +264160,49 @@ public: void toFront (bool makeActiveWindow); void toBehind (ComponentPeer* other); void setIcon (const Image& newIcon); + + /* 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. + */ + virtual void redirectMouseDown (NSEvent* ev); + virtual void redirectMouseUp (NSEvent* ev); + virtual void redirectMouseDrag (NSEvent* ev); + virtual void redirectMouseMove (NSEvent* ev); + virtual void redirectMouseEnter (NSEvent* ev); + virtual void redirectMouseExit (NSEvent* ev); + virtual void redirectMouseWheel (NSEvent* ev); + bool handleKeyEvent (NSEvent* ev, bool isKeyDown); + virtual bool redirectKeyDown (NSEvent* ev); + virtual bool redirectKeyUp (NSEvent* ev); + virtual void redirectModKeyChange (NSEvent* ev); +#if MACOS_10_4_OR_EARLIER + virtual bool redirectPerformKeyEquivalent (NSEvent* ev); +#endif + + virtual BOOL sendDragCallback (int type, id sender); + + virtual bool isOpaque(); + virtual void drawRect (NSRect r); - void viewFocusGain(); - void viewFocusLoss(); + virtual bool canBecomeKeyWindow(); + virtual bool windowShouldClose(); + + virtual void redirectMovedOrResized(); + virtual NSRect constrainRect (NSRect r); + + virtual void viewFocusGain(); + virtual void viewFocusLoss(); bool isFocused() const; void grabFocus(); void textInputRequired (int x, int y); - NSRect constrainRect (NSRect r); void repaint (int x, int y, int w, int h); void performAnyPendingRepaintsNow(); @@ -264295,170 +264214,6 @@ public: bool isSharedWindow, fullScreen; }; -class JuceNSImage -{ -public: - JuceNSImage (const int width, const int height, const bool hasAlpha) - : juceImage (hasAlpha ? Image::ARGB : Image::RGB, - width, height, hasAlpha) - { - lineStride = 0; - pixelStride = 0; - imageData = juceImage.lockPixelDataReadWrite (0, 0, width, height, - lineStride, pixelStride); - - imageRep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: &imageData - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: pixelStride - hasAlpha: hasAlpha - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 - bytesPerRow: lineStride - bitsPerPixel: 8 * pixelStride ]; - - juceImage.releasePixelDataReadWrite (imageData); - } - - ~JuceNSImage() - { - [imageRep release]; - } - - Image& getJuceImage() throw() { return juceImage; } - - void draw (const float x, const float y, - const RectangleList& clip, - const int originX, const int originY) const - { - // Our data is BGRA and the damned image rep only takes RGBA, so - // we need to byte-swap the active areas if there's an alpha channel... - if (juceImage.hasAlphaChannel()) - { - RectangleList::Iterator iter (clip); - while (iter.next()) - { - const Rectangle* const r = iter.getRectangle(); - - swapRGBOrder (r->getX() + originX, - r->getY() + originY, - r->getWidth(), - r->getHeight()); - } - } - - NSPoint p; - p.x = x; - p.y = y; - [imageRep drawAtPoint: p]; - } - - void drawNSImage (NSImage* imageToDraw) - { - const ScopedAutoReleasePool pool; - - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; - - [imageToDraw drawAtPoint: NSZeroPoint - fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) - operation: NSCompositeSourceOver - fraction: 1.0f]; - - [[NSGraphicsContext currentContext] flushGraphics]; - - if (juceImage.hasAlphaChannel()) - swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); - } - -private: - Image juceImage; - NSBitmapImageRep* imageRep; - uint8* imageData; - int pixelStride, lineStride; - - void swapRGBOrder (const int x, const int y, const int w, int h) const - { - jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) - .contains (Rectangle (x, y, w, h))); - - uint8* start = imageData + x * pixelStride + y * lineStride; - - while (--h >= 0) - { - uint8* p = start; - start += lineStride; - - for (int i = w; --i >= 0;) - { - const uint8 temp = p[0]; - p[0] = p[2]; - p[2] = temp; - - p += pixelStride; - } - } - } -}; - -static ComponentPeer* currentlyFocusedPeer = 0; -static VoidArray keysCurrentlyDown; - -bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() -{ - if (keysCurrentlyDown.contains ((void*) keyCode)) - return true; - - if (keyCode >= 'A' && keyCode <= 'Z' - && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toLowerCase ((tchar) keyCode))) - return true; - - if (keyCode >= 'a' && keyCode <= 'z' - && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toUpperCase ((tchar) keyCode))) - return true; - - return false; -} - -static int getKeyCodeFromEvent (NSEvent* ev) -{ - String unicode (nsStringToJuce ([ev characters])); - String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); - int keyCode = unmodified[0]; - - if (keyCode == 0x19) // (backwards-tab) - keyCode = 9; - - return keyCode; -} - -static void updateKeysDown (NSEvent* ev, bool isKeyDown) -{ - updateModifiers (ev); - int keyCode = getKeyCodeFromEvent (ev); - - if (keyCode != 0) - { - if (isKeyDown) - keysCurrentlyDown.addIfNotAlreadyThere ((void*) keyCode); - else - keysCurrentlyDown.removeValue ((void*) keyCode); - } -} - -const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() -{ - return ModifierKeys (currentModifiers); -} - -void ModifierKeys::updateCurrentModifiers() throw() -{ - currentModifierFlags = currentModifiers; -} - END_JUCE_NAMESPACE @implementation JuceNSView @@ -264469,19 +264224,19 @@ END_JUCE_NAMESPACE [super initWithFrame: frame]; owner = owner_; - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector (frameChanged:) - name: NSViewFrameDidChangeNotification - object: self]; + notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter addObserver: self + selector: @selector (frameChanged:) + name: NSViewFrameDidChangeNotification + object: self]; if (! owner_->isSharedWindow) { - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector (frameChanged:) - name: NSWindowDidMoveNotification - object: owner_->window]; + [notificationCenter addObserver: self + selector: @selector (frameChanged:) + name: NSWindowDidMoveNotification + object: owner_->window]; } [self registerForDraggedTypes: [self getSupportedDragTypes]]; @@ -264491,155 +264246,55 @@ END_JUCE_NAMESPACE - (void) dealloc { - [[NSNotificationCenter defaultCenter] removeObserver: self]; + [notificationCenter removeObserver: self]; [super dealloc]; } - (void) drawRect: (NSRect) r { - if (r.size.width < 1.0f || r.size.height < 1.0f || owner == 0) - return; - - const float y = [self frame].size.height - (r.origin.y + r.size.height); - - JuceNSImage temp ((int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! owner->getComponent()->isOpaque()); - - LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); - const int originX = -roundFloatToInt (r.origin.x); - const int originY = -roundFloatToInt (y); - context.setOrigin (originX, originY); - - const NSRect* rects = 0; - int numRects = 0; - [self getRectsBeingDrawn: &rects count: &numRects]; - - RectangleList clip; - for (int i = 0; i < numRects; ++i) - { - clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), - roundFloatToInt ([self frame].size.height - (rects[i].origin.y + rects[i].size.height)), - roundFloatToInt (rects[i].size.width), - roundFloatToInt (rects[i].size.height))); - } - - if (context.reduceClipRegion (clip)) - { - owner->handlePaint (context); - temp.draw (r.origin.x, r.origin.y, clip, originX, originY); - } + if (owner != 0) + owner->drawRect (r); } - (BOOL) isOpaque { - if (owner == 0) - return true; - - if (! owner->getComponent()->isValidComponent()) - return false; - - return owner->getComponent()->isOpaque(); -} - -static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } - -static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) -{ - NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; - x = roundFloatToInt (p.x); - y = roundFloatToInt ([view frame].size.height - p.y); -} - -static void updateModifiers (NSEvent* e) -{ - int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier - | ModifierKeys::altModifier | ModifierKeys::commandModifier); - - if (([e modifierFlags] & NSShiftKeyMask) != 0) - m |= ModifierKeys::shiftModifier; - - if (([e modifierFlags] & NSControlKeyMask) != 0) - m |= ModifierKeys::ctrlModifier; - - if (([e modifierFlags] & NSAlternateKeyMask) != 0) - m |= ModifierKeys::altModifier; - - if (([e modifierFlags] & NSCommandKeyMask) != 0) - m |= ModifierKeys::commandModifier; - - currentModifiers = m; -} - -static int getModifierForButtonNumber (const int num) throw() -{ - return num == 0 ? ModifierKeys::leftButtonModifier - : (num == 1 ? ModifierKeys::rightButtonModifier - : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); + return owner == 0 || owner->isOpaque(); } - (void) mouseDown: (NSEvent*) ev { - updateModifiers (ev); - currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseDown (x, y, getMouseTime (ev)); + owner->redirectMouseDown (ev); } - (void) mouseUp: (NSEvent*) ev { - const int oldMods = currentModifiers; - updateModifiers (ev); - currentModifiers &= ~getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseUp (oldMods, x, y, getMouseTime (ev)); + owner->redirectMouseUp (ev); } - (void) mouseDragged: (NSEvent*) ev { - updateModifiers (ev); - currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseDrag (x, y, getMouseTime (ev)); + owner->redirectMouseDrag (ev); } - (void) mouseMoved: (NSEvent*) ev { - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseMove (x, y, getMouseTime (ev)); + owner->redirectMouseMove (ev); } - (void) mouseEntered: (NSEvent*) ev { - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseEnter (x, y, getMouseTime (ev)); + owner->redirectMouseEnter (ev); } - (void) mouseExited: (NSEvent*) ev { - updateModifiers (ev); - int x, y; - getMousePos (ev, self, x, y); - if (owner != 0) - owner->handleMouseExit (x, y, getMouseTime (ev)); + owner->redirectMouseExit (ev); } - (void) rightMouseDown: (NSEvent*) ev @@ -264659,12 +264314,8 @@ static int getModifierForButtonNumber (const int num) throw() - (void) scrollWheel: (NSEvent*) ev { - updateModifiers (ev); - if (owner != 0) - owner->handleMouseWheel (roundFloatToInt ([ev deltaX] * 10.0f), - roundFloatToInt ([ev deltaY] * 10.0f), - getMouseTime (ev)); + owner->redirectMouseWheel (ev); } - (BOOL) acceptsFirstMouse: (NSEvent*) ev @@ -264675,59 +264326,32 @@ static int getModifierForButtonNumber (const int num) throw() - (void) frameChanged: (NSNotification*) n { if (owner != 0) - owner->handleMovedOrResized(); + owner->redirectMovedOrResized(); } - (void) keyDown: (NSEvent*) ev { - bool used = false; - - if (owner != 0) - { - updateKeysDown (ev, true); - used = owner->handleKeyEvent (ev, true); - - if (([ev modifierFlags] & NSCommandKeyMask) != 0) - { - // for command keys, the key-up event is thrown away, so simulate one.. - updateKeysDown (ev, false); - used = owner->handleKeyEvent (ev, false) || used; - } - } - - if (! used) + if (owner == 0 || ! owner->redirectKeyDown (ev)) [super keyDown: ev]; } - (void) keyUp: (NSEvent*) ev { - updateKeysDown (ev, false); - - if (owner == 0 || ! owner->handleKeyEvent (ev, false)) + if (owner == 0 || ! owner->redirectKeyUp (ev)) [super keyUp: ev]; } - (void) flagsChanged: (NSEvent*) ev { - updateModifiers (ev); - if (owner != 0) - owner->handleModifierKeysChange(); + owner->redirectModKeyChange (ev); } #if MACOS_10_4_OR_EARLIER - (BOOL) performKeyEquivalent: (NSEvent*) ev { - if (owner != 0) - { - updateKeysDown (ev, true); - const bool used1 = owner->handleKeyEvent (ev, true); - updateKeysDown (ev, false); - const bool used2 = owner->handleKeyEvent (ev, false); - - if (used1 || used2) - return true; - } + if (owner != 0 && owner->redirectPerformKeyEquivalent (ev)) + return true; return [super performKeyEquivalent: ev]; } @@ -264756,41 +264380,7 @@ static int getModifierForButtonNumber (const int num) throw() - (BOOL) sendDragCallback: (int) type sender: (id ) sender { - NSString* bestType - = [[sender draggingPasteboard] availableTypeFromArray: [self getSupportedDragTypes]]; - - if (bestType == nil) - return false; - - NSPoint p = [self convertPoint: [sender draggingLocation] fromView: nil]; - int x = (int) p.x; - int y = (int) ([self frame].size.height - p.y); - - StringArray files; - - id list = [[sender draggingPasteboard] propertyListForType: bestType]; - if (list == nil) - return false; - - if ([list isKindOfClass: [NSArray class]]) - { - NSArray* items = (NSArray*) list; - - for (int i = 0; i < [items count]; ++i) - files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i])); - } - - if (files.size() == 0) - return false; - - if (type == 0) - owner->handleFileDragMove (files, x, y); - else if (type == 1) - owner->handleFileDragExit (files); - else if (type == 2) - owner->handleFileDragDrop (files, x, y); - - return true; + return owner != 0 && owner->sendDragCallback (type, sender); } - (NSDragOperation) draggingEntered: (id ) sender @@ -264844,44 +264434,30 @@ static int getModifierForButtonNumber (const int num) throw() - (BOOL) canBecomeKeyWindow { - // If runnin as a plugin, let the component decide whether it's - // going to allow the window to get focused. - return JUCEApplication::getInstance() != 0 - || (ComponentPeer::isValidPeer (owner) - && owner->getComponent()->getWantsKeyboardFocus()); + return owner != 0 && owner->canBecomeKeyWindow(); } - (BOOL) windowShouldClose: (id) window { - if (! ComponentPeer::isValidPeer (owner)) - return YES; - - owner->handleUserClosingWindow(); - return NO; + return owner == 0 || owner->windowShouldClose(); } - (NSRect) constrainFrameRect: (NSRect) frameRect toScreen: (NSScreen*) screen { - if (owner == 0) - return frameRect; + if (owner != 0) + frameRect = owner->constrainRect (frameRect); -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - frameRect = owner->constrainRect (frameRect); -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); return frameRect; } - (NSSize) windowWillResize: (NSWindow*) window toSize: (NSSize) proposedFrameSize { - if (owner == 0) - return proposedFrameSize; - NSRect frameRect = [self frame]; frameRect.size = proposedFrameSize; -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); - frameRect = owner->constrainRect (frameRect); -DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + String (frameRect.size.width) + " " + String (frameRect.size.height)); + if (owner != 0) + frameRect = owner->constrainRect (frameRect); + return frameRect.size; } @@ -264889,6 +264465,208 @@ DBG (String (frameRect.origin.x) + " " + String (frameRect.origin.y) + " " + Str BEGIN_JUCE_NAMESPACE +class JuceNSImage +{ +public: + JuceNSImage (const int width, const int height, const bool hasAlpha) + : juceImage (hasAlpha ? Image::ARGB : Image::RGB, + width, height, hasAlpha) + { + lineStride = 0; + pixelStride = 0; + imageData = juceImage.lockPixelDataReadWrite (0, 0, width, height, + lineStride, pixelStride); + + imageRep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &imageData + pixelsWide: width + pixelsHigh: height + bitsPerSample: 8 + samplesPerPixel: pixelStride + hasAlpha: hasAlpha + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 + bytesPerRow: lineStride + bitsPerPixel: 8 * pixelStride ]; + + juceImage.releasePixelDataReadWrite (imageData); + } + + ~JuceNSImage() + { + [imageRep release]; + } + + Image& getJuceImage() throw() { return juceImage; } + + void draw (const float x, const float y, + const RectangleList& clip, + const int originX, const int originY) const + { + // Our data is BGRA and the damned image rep only takes RGBA, so + // we need to byte-swap the active areas if there's an alpha channel... + if (juceImage.hasAlphaChannel()) + { + RectangleList::Iterator iter (clip); + while (iter.next()) + { + const Rectangle* const r = iter.getRectangle(); + + swapRGBOrder (r->getX() + originX, + r->getY() + originY, + r->getWidth(), + r->getHeight()); + } + } + + NSPoint p; + p.x = x; + p.y = y; + [imageRep drawAtPoint: p]; + } + + void drawNSImage (NSImage* imageToDraw) + { + const ScopedAutoReleasePool pool; + + [NSGraphicsContext setCurrentContext: + [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; + + [imageToDraw drawAtPoint: NSZeroPoint + fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) + operation: NSCompositeSourceOver + fraction: 1.0f]; + + [[NSGraphicsContext currentContext] flushGraphics]; + + if (juceImage.hasAlphaChannel()) + swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); + } + +private: + Image juceImage; + NSBitmapImageRep* imageRep; + uint8* imageData; + int pixelStride, lineStride; + + void swapRGBOrder (const int x, const int y, const int w, int h) const + { + jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) + .contains (Rectangle (x, y, w, h))); + + uint8* start = imageData + x * pixelStride + y * lineStride; + + while (--h >= 0) + { + uint8* p = start; + start += lineStride; + + for (int i = w; --i >= 0;) + { + const uint8 temp = p[0]; + p[0] = p[2]; + p[2] = temp; + + p += pixelStride; + } + } + } +}; + +static ComponentPeer* currentlyFocusedPeer = 0; +static VoidArray keysCurrentlyDown; + +bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() +{ + if (keysCurrentlyDown.contains ((void*) keyCode)) + return true; + + if (keyCode >= 'A' && keyCode <= 'Z' + && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toLowerCase ((tchar) keyCode))) + return true; + + if (keyCode >= 'a' && keyCode <= 'z' + && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toUpperCase ((tchar) keyCode))) + return true; + + return false; +} + +static int getKeyCodeFromEvent (NSEvent* ev) +{ + String unicode (nsStringToJuce ([ev characters])); + String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers])); + int keyCode = unmodified[0]; + + if (keyCode == 0x19) // (backwards-tab) + keyCode = 9; + + return keyCode; +} + +static int currentModifiers = 0; + +static void updateModifiers (NSEvent* e) +{ + int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier + | ModifierKeys::altModifier | ModifierKeys::commandModifier); + + if (([e modifierFlags] & NSShiftKeyMask) != 0) + m |= ModifierKeys::shiftModifier; + + if (([e modifierFlags] & NSControlKeyMask) != 0) + m |= ModifierKeys::ctrlModifier; + + if (([e modifierFlags] & NSAlternateKeyMask) != 0) + m |= ModifierKeys::altModifier; + + if (([e modifierFlags] & NSCommandKeyMask) != 0) + m |= ModifierKeys::commandModifier; + + currentModifiers = m; +} + +static void updateKeysDown (NSEvent* ev, bool isKeyDown) +{ + updateModifiers (ev); + int keyCode = getKeyCodeFromEvent (ev); + + if (keyCode != 0) + { + if (isKeyDown) + keysCurrentlyDown.addIfNotAlreadyThere ((void*) keyCode); + else + keysCurrentlyDown.removeValue ((void*) keyCode); + } +} + +const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() +{ + return ModifierKeys (currentModifiers); +} + +void ModifierKeys::updateCurrentModifiers() throw() +{ + currentModifierFlags = currentModifiers; +} + +static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } + +static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) +{ + NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; + x = roundFloatToInt (p.x); + y = roundFloatToInt ([view frame].size.height - p.y); +} + +static int getModifierForButtonNumber (const int num) throw() +{ + return num == 0 ? ModifierKeys::leftButtonModifier + : (num == 1 ? ModifierKeys::rightButtonModifier + : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); +} + NSViewComponentPeer::NSViewComponentPeer (Component* const component, const int windowStyleFlags, NSView* viewToAttachTo) @@ -264963,7 +264741,10 @@ NSViewComponentPeer::~NSViewComponentPeer() [view release]; if (! isSharedWindow) + { + [((JuceNSWindow*) window) setOwner: 0]; [window close]; + } } void* NSViewComponentPeer::getNativeHandle() const @@ -265346,6 +265127,216 @@ bool NSViewComponentPeer::handleKeyEvent (NSEvent* ev, bool isKeyDown) return false; } +void NSViewComponentPeer::redirectMouseDown (NSEvent* ev) +{ + updateModifiers (ev); + currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseDown (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseUp (NSEvent* ev) +{ + const int oldMods = currentModifiers; + updateModifiers (ev); + currentModifiers &= ~getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseUp (oldMods, x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseDrag (NSEvent* ev) +{ + updateModifiers (ev); + currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseDrag (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseMove (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseMove (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseEnter (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseEnter (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseExit (NSEvent* ev) +{ + updateModifiers (ev); + int x, y; + getMousePos (ev, view, x, y); + + handleMouseExit (x, y, getMouseTime (ev)); +} + +void NSViewComponentPeer::redirectMouseWheel (NSEvent* ev) +{ + updateModifiers (ev); + + handleMouseWheel (roundFloatToInt ([ev deltaX] * 10.0f), + roundFloatToInt ([ev deltaY] * 10.0f), + getMouseTime (ev)); +} + +bool NSViewComponentPeer::redirectKeyDown (NSEvent* ev) +{ + updateKeysDown (ev, true); + bool used = handleKeyEvent (ev, true); + + if (([ev modifierFlags] & NSCommandKeyMask) != 0) + { + // for command keys, the key-up event is thrown away, so simulate one.. + updateKeysDown (ev, false); + used = (isValidPeer (this) && handleKeyEvent (ev, false)) || used; + } + + return used; +} + +bool NSViewComponentPeer::redirectKeyUp (NSEvent* ev) +{ + updateKeysDown (ev, false); + return handleKeyEvent (ev, false); +} + +void NSViewComponentPeer::redirectModKeyChange (NSEvent* ev) +{ + updateModifiers (ev); + handleModifierKeysChange(); +} + +#if MACOS_10_4_OR_EARLIER +bool NSViewComponentPeer::redirectPerformKeyEquivalent (NSEvent* ev) +{ + updateKeysDown (ev, true); + const bool used1 = isValidPeer (this) && handleKeyEvent (ev, true); + updateKeysDown (ev, false); + const bool used2 = isValidPeer (this) && handleKeyEvent (ev, false); + + return used1 || used2; +} +#endif + +BOOL NSViewComponentPeer::sendDragCallback (int type, id sender) +{ + NSString* bestType + = [[sender draggingPasteboard] availableTypeFromArray: [view getSupportedDragTypes]]; + + if (bestType == nil) + return false; + + NSPoint p = [view convertPoint: [sender draggingLocation] fromView: nil]; + int x = (int) p.x; + int y = (int) ([view frame].size.height - p.y); + + StringArray files; + + id list = [[sender draggingPasteboard] propertyListForType: bestType]; + if (list == nil) + return false; + + if ([list isKindOfClass: [NSArray class]]) + { + NSArray* items = (NSArray*) list; + + for (int i = 0; i < [items count]; ++i) + files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i])); + } + + if (files.size() == 0) + return false; + + if (type == 0) + handleFileDragMove (files, x, y); + else if (type == 1) + handleFileDragExit (files); + else if (type == 2) + handleFileDragDrop (files, x, y); + + return true; +} + +bool NSViewComponentPeer::isOpaque() +{ + if (! getComponent()->isValidComponent()) + return true; + + return getComponent()->isOpaque(); +} + +void NSViewComponentPeer::drawRect (NSRect r) +{ + if (r.size.width < 1.0f || r.size.height < 1.0f) + return; + + const float y = [view frame].size.height - (r.origin.y + r.size.height); + + JuceNSImage temp ((int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); + + LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); + const int originX = -roundFloatToInt (r.origin.x); + const int originY = -roundFloatToInt (y); + context.setOrigin (originX, originY); + + const NSRect* rects = 0; + int numRects = 0; + [view getRectsBeingDrawn: &rects count: &numRects]; + + RectangleList clip; + for (int i = 0; i < numRects; ++i) + { + clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), + roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), + roundFloatToInt (rects[i].size.width), + roundFloatToInt (rects[i].size.height))); + } + + if (context.reduceClipRegion (clip)) + { + handlePaint (context); + temp.draw (r.origin.x, r.origin.y, clip, originX, originY); + } +} + +bool NSViewComponentPeer::canBecomeKeyWindow() +{ + // If running as a plugin, let the component decide whether it's going to allow the window to get focused. + return JUCEApplication::getInstance() != 0 + || (isValidPeer (this) && getComponent()->getWantsKeyboardFocus()); +} + +bool NSViewComponentPeer::windowShouldClose() +{ + if (! isValidPeer (this)) + return YES; + + handleUserClosingWindow(); + return NO; +} + +void NSViewComponentPeer::redirectMovedOrResized() +{ + handleMovedOrResized(); +} + void NSViewComponentPeer::repaint (int x, int y, int w, int h) { [view setNeedsDisplayInRect: @@ -266021,7 +266012,18 @@ public: = [[NSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) pixelFormat: format]; - renderContext = [view openGLContext]; + 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); @@ -266182,6 +266184,8 @@ class JuceMainMenuHandler; END_JUCE_NAMESPACE using namespace JUCE_NAMESPACE; +#define JuceMenuCallback MakeObjCClassName(JuceMenuCallback) + @interface JuceMenuCallback : NSObject { JuceMainMenuHandler* owner; @@ -266478,9 +266482,8 @@ MenuBarModel* MenuBarModel::getMacMainMenu() throw() ? JuceMainMenuHandler::instance->currentModel : 0; } -static NSMenu* createStandardAppMenu (const String& appName) +static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName) { - NSMenu* menu = [[NSMenu alloc] initWithTitle: @"Apple"]; NSMenuItem* item; // xxx should allow the 'about' and 'preferences' items to be turned on programatically... @@ -266496,8 +266499,10 @@ static NSMenu* createStandardAppMenu (const String& appName) */ // Services... - item = [menu addItemWithTitle: NSLocalizedString (@"Services", nil) - action: nil keyEquivalent: @""]; + 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]; @@ -266505,24 +266510,34 @@ static NSMenu* createStandardAppMenu (const String& appName) [menu addItem: [NSMenuItem separatorItem]]; // Hide + Show stuff... - item = [menu addItemWithTitle: juceStringToNS ("Hide " + appName) - action: @selector (hide:) keyEquivalent: @"h"]; + item = [[NSMenuItem alloc] initWithTitle: juceStringToNS ("Hide " + appName) + action: @selector (hide:) keyEquivalent: @"h"]; [item setTarget: NSApp]; + [menu addItem: item]; + [item release]; - item = [menu addItemWithTitle: NSLocalizedString (@"Hide Others", nil) - action: @selector (hideOtherApplications:) keyEquivalent: @"h"]; + 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 = [menu addItemWithTitle: NSLocalizedString (@"Show All", nil) - action: @selector (unhideAllApplications:) keyEquivalent: @""]; + 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 = [menu addItemWithTitle: juceStringToNS ("Quit " + appName) - action: @selector (terminate:) keyEquivalent: @"q"]; + item = [[NSMenuItem alloc] initWithTitle: juceStringToNS ("Quit " + appName) + action: @selector (terminate:) keyEquivalent: @"q"]; + [item setTarget: NSApp]; + [menu addItem: item]; + [item release]; return menu; } @@ -266537,12 +266552,14 @@ void initialiseMainMenu() NSMenu* mainMenu = [[NSMenu alloc] initWithTitle: @"MainMenu"]; NSMenuItem* item = [mainMenu addItemWithTitle: @"Apple" action: nil keyEquivalent: @""]; - NSMenu* appMenu = createStandardAppMenu (JUCEApplication::getInstance()->getApplicationName()); + 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]; } @@ -266559,6 +266576,8 @@ void initialiseMainMenu() END_JUCE_NAMESPACE using namespace JUCE_NAMESPACE; +#define JuceFileChooserDelegate MakeObjCClassName(JuceFileChooserDelegate) + @interface JuceFileChooserDelegate : NSObject { StringArray* filters; @@ -266699,18 +266718,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 (movieStream); @@ -266725,11 +266735,39 @@ bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream, MemoryBlock temp; movieStream->readIntoMemoryBlock (temp); - movie = [QTMovie movieWithData: [NSData dataWithBytes: temp.getData() - length: temp.getSize()] - error: nil]; + 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; +} + +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]; @@ -266903,24 +266941,8 @@ bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, if (movieStream == 0) return false; - QTMovie* movie = nil; - - FileInputStream* const fin = dynamic_cast (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]; @@ -266940,6 +266962,8 @@ bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, END_JUCE_NAMESPACE +#define OpenDiskDevice MakeObjCClassName(OpenDiskDevice) + @interface OpenDiskDevice : NSObject { DRDevice* device; @@ -266956,6 +266980,8 @@ END_JUCE_NAMESPACE ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting; @end +#define AudioTrackProducer MakeObjCClassName(AudioTrackProducer) + @interface AudioTrackProducer : NSObject { JUCE_NAMESPACE::AudioSource* source; @@ -267843,12 +267869,84 @@ struct CallbackMessagePayload 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; @@ -267870,6 +267968,8 @@ using namespace JUCE_NAMESPACE; { [super init]; + redirector = new AppDelegateRedirector(); + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; if (JUCEApplication::getInstance() != 0) @@ -267899,56 +267999,38 @@ using namespace JUCE_NAMESPACE; if (oldDelegate != 0) [NSApp setDelegate: oldDelegate]; + redirector->deleteSelf(); [super dealloc]; } - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app { - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->systemRequestedQuit(); - - if (! MessageManager::getInstance()->hasStopMessageBeenSent()) - return NSTerminateCancel; - } - - return NSTerminateNow; + return redirector->shouldTerminate(); } - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename { - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); - return YES; - } - - return NO; + return redirector->openFile (filename); } - (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(" "))); + return redirector->openFiles (filenames); } - (void) applicationDidBecomeActive: (NSNotification*) aNotification { - juce_HandleProcessFocusChange(); + redirector->focusChanged(); } - (void) applicationDidResignActive: (NSNotification*) aNotification { - juce_HandleProcessFocusChange(); + redirector->focusChanged(); } - (void) applicationWillUnhide: (NSNotification*) aNotification { - juce_HandleProcessFocusChange(); + redirector->focusChanged(); } - (void) customEvent: (id) n @@ -267958,7 +268040,7 @@ using namespace JUCE_NAMESPACE; [data getBytes: &message length: sizeof (message)]; if (message != 0) - MessageManager::getInstance()->deliverMessage (message); + redirector->deliverMessage (message); [data release]; } @@ -268093,6 +268175,8 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call END_JUCE_NAMESPACE +#define DownloadClickDetector MakeObjCClassName(DownloadClickDetector) + @interface DownloadClickDetector : NSObject { JUCE_NAMESPACE::WebBrowserComponent* ownerComponent; @@ -268115,11 +268199,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 ) 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]; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index f6f614ad75..8df4da09ba 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -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. diff --git a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp index e2535d660f..ab06b16f9a 100644 --- a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp @@ -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(); } diff --git a/src/juce_appframework/gui/components/controls/juce_Slider.cpp b/src/juce_appframework/gui/components/controls/juce_Slider.cpp index c8665f268b..28c8db80cd 100644 --- a/src/juce_appframework/gui/components/controls/juce_Slider.cpp +++ b/src/juce_appframework/gui/components/controls/juce_Slider.cpp @@ -359,6 +359,8 @@ void Slider::lookAndFeelChanged() if (style == LinearBar) valueBox->addMouseListener (this, false); + + valueBox->setTooltip (getTooltip()); } if (style == IncDecButtons) diff --git a/src/juce_appframework/gui/components/juce_Component.cpp b/src/juce_appframework/gui/components/juce_Component.cpp index 8cc599ff45..76816cac92 100644 --- a/src/juce_appframework/gui/components/juce_Component.cpp +++ b/src/juce_appframework/gui/components/juce_Component.cpp @@ -1,3661 +1,3661 @@ -/* - ============================================================================== - - 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. - - ============================================================================== -*/ - -#include "../../../juce_core/basics/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_Component.h" -#include "juce_ComponentDeletionWatcher.h" -#include "juce_Desktop.h" -#include "keyboard/juce_KeyListener.h" -#include "lookandfeel/juce_LookAndFeel.h" -#include "../../application/juce_Application.h" -#include "../graphics/geometry/juce_RectangleList.h" -#include "../graphics/imaging/juce_Image.h" -#include "../graphics/contexts/juce_LowLevelGraphicsContext.h" -#include "../../events/juce_MessageManager.h" -#include "../../events/juce_Timer.h" -#include "../../../juce_core/basics/juce_Time.h" -#include "../../../juce_core/misc/juce_PlatformUtilities.h" - - -//============================================================================== -Component* Component::componentUnderMouse = 0; -Component* Component::currentlyFocusedComponent = 0; - -static Array modalComponentStack (4), modalComponentReturnValueKeys (4); -static Array modalReturnValues (4); - -static const int customCommandMessage = 0x7fff0001; -static const int exitModalStateMessage = 0x7fff0002; - -//============================================================================== -// these are also used by ComponentPeer -int64 juce_recentMouseDownTimes [4] = { 0, 0, 0, 0 }; -int juce_recentMouseDownX [4] = { 0, 0, 0, 0 }; -int juce_recentMouseDownY [4] = { 0, 0, 0, 0 }; -Component* juce_recentMouseDownComponent [4] = { 0, 0, 0, 0 }; -int juce_LastMousePosX = 0; -int juce_LastMousePosY = 0; -int juce_MouseClickCounter = 0; -bool juce_MouseHasMovedSignificantlySincePressed = false; - -static int countMouseClicks() throw() -{ - int numClicks = 0; - - if (juce_recentMouseDownTimes[0] != 0) - { - if (! juce_MouseHasMovedSignificantlySincePressed) - ++numClicks; - - for (int i = 1; i < numElementsInArray (juce_recentMouseDownTimes); ++i) - { - if (juce_recentMouseDownTimes[0] - juce_recentMouseDownTimes [i] - < (int) (MouseEvent::getDoubleClickTimeout() * (1.0 + 0.25 * (i - 1))) - && abs (juce_recentMouseDownX[0] - juce_recentMouseDownX[i]) < 8 - && abs (juce_recentMouseDownY[0] - juce_recentMouseDownY[i]) < 8 - && juce_recentMouseDownComponent[0] == juce_recentMouseDownComponent [i]) - { - ++numClicks; - } - else - { - break; - } - } - } - - return numClicks; -} - -static int unboundedMouseOffsetX = 0; -static int unboundedMouseOffsetY = 0; -static bool isUnboundedMouseModeOn = false; -static bool isCursorVisibleUntilOffscreen; - -//============================================================================== -#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - -static uint32 nextComponentUID = 0; - - -//============================================================================== -Component::Component() throw() - : parentComponent_ (0), - componentUID (++nextComponentUID), - numDeepMouseListeners (0), - childComponentList_ (16), - lookAndFeel_ (0), - effect_ (0), - bufferedImage_ (0), - mouseListeners_ (0), - keyListeners_ (0), - componentListeners_ (0), - propertySet_ (0), - componentFlags_ (0) -{ -} - -Component::Component (const String& name) throw() - : componentName_ (name), - parentComponent_ (0), - componentUID (++nextComponentUID), - numDeepMouseListeners (0), - childComponentList_ (16), - lookAndFeel_ (0), - effect_ (0), - bufferedImage_ (0), - mouseListeners_ (0), - keyListeners_ (0), - componentListeners_ (0), - propertySet_ (0), - componentFlags_ (0) -{ -} - -Component::~Component() -{ - if (parentComponent_ != 0) - { - parentComponent_->removeChildComponent (this); - } - else if ((currentlyFocusedComponent == this) - || isParentOf (currentlyFocusedComponent)) - { - giveAwayFocus(); - } - - if (componentUnderMouse == this) - componentUnderMouse = 0; - - if (flags.hasHeavyweightPeerFlag) - removeFromDesktop(); - - modalComponentStack.removeValue (this); - - for (int i = childComponentList_.size(); --i >= 0;) - childComponentList_.getUnchecked(i)->parentComponent_ = 0; - - delete bufferedImage_; - delete mouseListeners_; - delete keyListeners_; - delete componentListeners_; - delete propertySet_; -} - -//============================================================================== -void Component::setName (const String& name) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (componentName_ != name) - { - componentName_ = name; - - if (flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = getPeer(); - - jassert (peer != 0); - if (peer != 0) - peer->setTitle (name); - } - - if (componentListeners_ != 0) - { - const ComponentDeletionWatcher deletionChecker (this); - - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentNameChanged (*this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } - - } -} - -void Component::setVisible (bool shouldBeVisible) -{ - if (flags.visibleFlag != shouldBeVisible) - { - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - const ComponentDeletionWatcher deletionChecker (this); - - flags.visibleFlag = shouldBeVisible; - - internalRepaint (0, 0, getWidth(), getHeight()); - - sendFakeMouseMove(); - - if (! shouldBeVisible) - { - if (currentlyFocusedComponent == this - || isParentOf (currentlyFocusedComponent)) - { - if (parentComponent_ != 0) - parentComponent_->grabKeyboardFocus(); - else - giveAwayFocus(); - } - } - - sendVisibilityChangeMessage(); - - if ((! deletionChecker.hasBeenDeleted()) && flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = getPeer(); - - jassert (peer != 0); - if (peer != 0) - { - peer->setVisible (shouldBeVisible); - internalHierarchyChanged(); - } - } - } -} - -void Component::visibilityChanged() -{ -} - -void Component::sendVisibilityChangeMessage() -{ - const ComponentDeletionWatcher deletionChecker (this); - - visibilityChanged(); - - if ((! deletionChecker.hasBeenDeleted()) && componentListeners_ != 0) - { - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentVisibilityChanged (*this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } -} - -bool Component::isShowing() const throw() -{ - if (flags.visibleFlag) - { - if (parentComponent_ != 0) - { - return parentComponent_->isShowing(); - } - else - { - const ComponentPeer* const peer = getPeer(); - - return peer != 0 && ! peer->isMinimised(); - } - } - - return false; -} - -//============================================================================== -class FadeOutProxyComponent : public Component, - public Timer -{ -public: - FadeOutProxyComponent (Component* comp, - const int fadeLengthMs, - const int deltaXToMove, - const int deltaYToMove, - const float scaleFactorAtEnd) - : lastTime (0), - alpha (1.0f), - scale (1.0f) - { - image = comp->createComponentSnapshot (Rectangle (0, 0, comp->getWidth(), comp->getHeight())); - setBounds (comp->getBounds()); - comp->getParentComponent()->addAndMakeVisible (this); - toBehind (comp); - - alphaChangePerMs = -1.0f / (float)fadeLengthMs; - - centreX = comp->getX() + comp->getWidth() * 0.5f; - xChangePerMs = deltaXToMove / (float)fadeLengthMs; - - centreY = comp->getY() + comp->getHeight() * 0.5f; - yChangePerMs = deltaYToMove / (float)fadeLengthMs; - - scaleChangePerMs = (scaleFactorAtEnd - 1.0f) / (float)fadeLengthMs; - - setInterceptsMouseClicks (false, false); - - // 30 fps is enough for a fade, but we need a higher rate if it's moving as well.. - startTimer (1000 / ((deltaXToMove == 0 && deltaYToMove == 0) ? 30 : 50)); - } - - ~FadeOutProxyComponent() - { - delete image; - } - - void paint (Graphics& g) - { - g.setOpacity (alpha); - - g.drawImage (image, - 0, 0, getWidth(), getHeight(), - 0, 0, image->getWidth(), image->getHeight()); - } - - void timerCallback() - { - const uint32 now = Time::getMillisecondCounter(); - - if (lastTime == 0) - lastTime = now; - - const int msPassed = (now > lastTime) ? now - lastTime : 0; - lastTime = now; - - alpha += alphaChangePerMs * msPassed; - - if (alpha > 0) - { - if (xChangePerMs != 0.0f || yChangePerMs != 0.0f || scaleChangePerMs != 0.0f) - { - centreX += xChangePerMs * msPassed; - centreY += yChangePerMs * msPassed; - scale += scaleChangePerMs * msPassed; - - const int w = roundFloatToInt (image->getWidth() * scale); - const int h = roundFloatToInt (image->getHeight() * scale); - - setBounds (roundFloatToInt (centreX) - w / 2, - roundFloatToInt (centreY) - h / 2, - w, h); - } - - repaint(); - } - else - { - delete this; - } - } - - juce_UseDebuggingNewOperator - -private: - Image* image; - uint32 lastTime; - float alpha, alphaChangePerMs; - float centreX, xChangePerMs; - float centreY, yChangePerMs; - float scale, scaleChangePerMs; - - FadeOutProxyComponent (const FadeOutProxyComponent&); - const FadeOutProxyComponent& operator= (const FadeOutProxyComponent&); -}; - -void Component::fadeOutComponent (const int millisecondsToFade, - const int deltaXToMove, - const int deltaYToMove, - const float scaleFactorAtEnd) -{ - //xxx won't work for comps without parents - if (isShowing() && millisecondsToFade > 0) - new FadeOutProxyComponent (this, millisecondsToFade, - deltaXToMove, deltaYToMove, scaleFactorAtEnd); - - setVisible (false); -} - - -//============================================================================== -bool Component::isValidComponent() const throw() -{ - return (this != 0) && isValidMessageListener(); -} - -void* Component::getWindowHandle() const throw() -{ - const ComponentPeer* const peer = getPeer(); - - if (peer != 0) - return peer->getNativeHandle(); - - return 0; -} - -//============================================================================== -void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (! isOpaque()) - styleWanted |= ComponentPeer::windowIsSemiTransparent; - - int currentStyleFlags = 0; - - // don't use getPeer(), so that we only get the peer that's specifically - // for this comp, and not for one of its parents. - ComponentPeer* peer = ComponentPeer::getPeerFor (this); - - if (peer != 0) - currentStyleFlags = peer->getStyleFlags(); - - if (styleWanted != currentStyleFlags || ! flags.hasHeavyweightPeerFlag) - { - const ComponentDeletionWatcher deletionChecker (this); - -#if JUCE_LINUX - // it's wise to give the component a non-zero size before - // putting it on the desktop, as X windows get confused by this, and - // a (1, 1) minimum size is enforced here. - setSize (jmax (1, getWidth()), - jmax (1, getHeight())); -#endif - - int x = 0, y = 0; - relativePositionToGlobal (x, y); - - bool wasFullscreen = false; - bool wasMinimised = false; - ComponentBoundsConstrainer* currentConstainer = 0; - Rectangle oldNonFullScreenBounds; - - if (peer != 0) - { - wasFullscreen = peer->isFullScreen(); - wasMinimised = peer->isMinimised(); - currentConstainer = peer->getConstrainer(); - oldNonFullScreenBounds = peer->getNonFullScreenBounds(); - - removeFromDesktop(); - - setTopLeftPosition (x, y); - } - - if (parentComponent_ != 0) - parentComponent_->removeChildComponent (this); - - if (! deletionChecker.hasBeenDeleted()) - { - flags.hasHeavyweightPeerFlag = true; - - peer = createNewPeer (styleWanted, nativeWindowToAttachTo); - - Desktop::getInstance().addDesktopComponent (this); - - bounds_.setPosition (x, y); - peer->setBounds (x, y, getWidth(), getHeight(), false); - - peer->setVisible (isVisible()); - - if (wasFullscreen) - { - peer->setFullScreen (true); - peer->setNonFullScreenBounds (oldNonFullScreenBounds); - } - - if (wasMinimised) - peer->setMinimised (true); - - if (isAlwaysOnTop()) - peer->setAlwaysOnTop (true); - - peer->setConstrainer (currentConstainer); - - repaint(); - } - - internalHierarchyChanged(); - } -} - -void Component::removeFromDesktop() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = ComponentPeer::getPeerFor (this); - - flags.hasHeavyweightPeerFlag = false; - - jassert (peer != 0); - delete peer; - - Desktop::getInstance().removeDesktopComponent (this); - } -} - -bool Component::isOnDesktop() const throw() -{ - return flags.hasHeavyweightPeerFlag; -} - -void Component::userTriedToCloseWindow() -{ - /* This means that the user's trying to get rid of your window with the 'close window' system - menu option (on windows) or possibly the task manager - you should really handle this - and delete or hide your component in an appropriate way. - - If you want to ignore the event and don't want to trigger this assertion, just override - this method and do nothing. - */ - jassertfalse -} - -void Component::minimisationStateChanged (bool) -{ -} - -//============================================================================== -void Component::setOpaque (const bool shouldBeOpaque) throw() -{ - if (shouldBeOpaque != flags.opaqueFlag) - { - flags.opaqueFlag = shouldBeOpaque; - - if (flags.hasHeavyweightPeerFlag) - { - const ComponentPeer* const peer = ComponentPeer::getPeerFor (this); - - if (peer != 0) - { - // to make it recreate the heavyweight window - addToDesktop (peer->getStyleFlags()); - } - } - - repaint(); - } -} - -bool Component::isOpaque() const throw() -{ - return flags.opaqueFlag; -} - -//============================================================================== -void Component::setBufferedToImage (const bool shouldBeBuffered) throw() -{ - if (shouldBeBuffered != flags.bufferToImageFlag) - { - deleteAndZero (bufferedImage_); - flags.bufferToImageFlag = shouldBeBuffered; - } -} - -//============================================================================== -void Component::toFront (const bool setAsForeground) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - peer->toFront (setAsForeground); - - if (setAsForeground && ! hasKeyboardFocus (true)) - grabKeyboardFocus(); - } - } - else if (parentComponent_ != 0) - { - if (parentComponent_->childComponentList_.getLast() != this) - { - const int index = parentComponent_->childComponentList_.indexOf (this); - - if (index >= 0) - { - int insertIndex = -1; - - if (! flags.alwaysOnTopFlag) - { - insertIndex = parentComponent_->childComponentList_.size() - 1; - - while (insertIndex > 0 - && parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) - { - --insertIndex; - } - } - - if (index != insertIndex) - { - parentComponent_->childComponentList_.move (index, insertIndex); - sendFakeMouseMove(); - - repaintParent(); - } - } - } - - if (setAsForeground) - { - internalBroughtToFront(); - grabKeyboardFocus(); - } - } -} - -void Component::toBehind (Component* const other) -{ - if (other != 0) - { - // the two components must belong to the same parent.. - jassert (parentComponent_ == other->parentComponent_); - - if (parentComponent_ != 0) - { - const int index = parentComponent_->childComponentList_.indexOf (this); - int otherIndex = parentComponent_->childComponentList_.indexOf (other); - - if (index >= 0 - && otherIndex >= 0 - && index != otherIndex - 1 - && other != this) - { - if (index < otherIndex) - --otherIndex; - - parentComponent_->childComponentList_.move (index, otherIndex); - - sendFakeMouseMove(); - repaintParent(); - } - } - else if (isOnDesktop()) - { - jassert (other->isOnDesktop()); - - if (other->isOnDesktop()) - { - ComponentPeer* const us = getPeer(); - ComponentPeer* const them = other->getPeer(); - - jassert (us != 0 && them != 0); - if (us != 0 && them != 0) - us->toBehind (them); - } - } - } -} - -void Component::toBack() -{ - if (isOnDesktop()) - { - jassertfalse //xxx need to add this to native window - } - else if (parentComponent_ != 0 - && parentComponent_->childComponentList_.getFirst() != this) - { - const int index = parentComponent_->childComponentList_.indexOf (this); - - if (index > 0) - { - int insertIndex = 0; - - if (flags.alwaysOnTopFlag) - { - while (insertIndex < parentComponent_->childComponentList_.size() - && ! parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) - { - ++insertIndex; - } - } - - if (index != insertIndex) - { - parentComponent_->childComponentList_.move (index, insertIndex); - - sendFakeMouseMove(); - repaintParent(); - } - } - } -} - -void Component::setAlwaysOnTop (const bool shouldStayOnTop) -{ - if (shouldStayOnTop != flags.alwaysOnTopFlag) - { - flags.alwaysOnTopFlag = shouldStayOnTop; - - if (isOnDesktop()) - { - ComponentPeer* const peer = getPeer(); - - jassert (peer != 0); - if (peer != 0) - { - if (! peer->setAlwaysOnTop (shouldStayOnTop)) - { - // some kinds of peer can't change their always-on-top status, so - // for these, we'll need to create a new window - const int oldFlags = peer->getStyleFlags(); - removeFromDesktop(); - addToDesktop (oldFlags); - } - } - } - - if (shouldStayOnTop) - toFront (false); - - internalHierarchyChanged(); - } -} - -bool Component::isAlwaysOnTop() const throw() -{ - return flags.alwaysOnTopFlag; -} - -//============================================================================== -int Component::proportionOfWidth (const float proportion) const throw() -{ - return roundDoubleToInt (proportion * bounds_.getWidth()); -} - -int Component::proportionOfHeight (const float proportion) const throw() -{ - return roundDoubleToInt (proportion * bounds_.getHeight()); -} - -int Component::getParentWidth() const throw() -{ - return (parentComponent_ != 0) ? parentComponent_->getWidth() - : getParentMonitorArea().getWidth(); -} - -int Component::getParentHeight() const throw() -{ - return (parentComponent_ != 0) ? parentComponent_->getHeight() - : getParentMonitorArea().getHeight(); -} - -int Component::getScreenX() const throw() -{ - return (parentComponent_ != 0) ? parentComponent_->getScreenX() + getX() - : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenX() - : getX()); -} - -int Component::getScreenY() const throw() -{ - return (parentComponent_ != 0) ? parentComponent_->getScreenY() + getY() - : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenY() - : getY()); -} - -void Component::relativePositionToGlobal (int& x, int& y) const throw() -{ - const Component* c = this; - - do - { - if (c->flags.hasHeavyweightPeerFlag) - { - c->getPeer()->relativePositionToGlobal (x, y); - break; - } - - x += c->getX(); - y += c->getY(); - c = c->parentComponent_; - } - while (c != 0); -} - -void Component::globalPositionToRelative (int& x, int& y) const throw() -{ - if (flags.hasHeavyweightPeerFlag) - { - getPeer()->globalPositionToRelative (x, y); - } - else - { - if (parentComponent_ != 0) - parentComponent_->globalPositionToRelative (x, y); - - x -= getX(); - y -= getY(); - } -} - -void Component::relativePositionToOtherComponent (const Component* const targetComponent, int& x, int& y) const throw() -{ - if (targetComponent != 0) - { - const Component* c = this; - - do - { - if (c == targetComponent) - return; - - if (c->flags.hasHeavyweightPeerFlag) - { - c->getPeer()->relativePositionToGlobal (x, y); - break; - } - - x += c->getX(); - y += c->getY(); - c = c->parentComponent_; - } - while (c != 0); - - targetComponent->globalPositionToRelative (x, y); - } -} - -//============================================================================== -void Component::setBounds (int x, int y, int w, int h) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (w < 0) w = 0; - if (h < 0) h = 0; - - const bool wasResized = (getWidth() != w || getHeight() != h); - const bool wasMoved = (getX() != x || getY() != y); - -#ifdef JUCE_DEBUG - // It's a very bad idea to try to resize a window during its paint() method! - jassert (! (flags.isInsidePaintCall && wasResized && isOnDesktop())); -#endif - - if (wasMoved || wasResized) - { - if (flags.visibleFlag) - { - // send a fake mouse move to trigger enter/exit messages if needed.. - sendFakeMouseMove(); - - if (! flags.hasHeavyweightPeerFlag) - repaintParent(); - } - - bounds_.setBounds (x, y, w, h); - - if (wasResized) - repaint(); - else if (! flags.hasHeavyweightPeerFlag) - repaintParent(); - - if (flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - if (wasMoved && wasResized) - peer->setBounds (getX(), getY(), getWidth(), getHeight(), false); - else if (wasMoved) - peer->setPosition (getX(), getY()); - else if (wasResized) - peer->setSize (getWidth(), getHeight()); - } - } - - sendMovedResizedMessages (wasMoved, wasResized); - } -} - -void Component::sendMovedResizedMessages (const bool wasMoved, const bool wasResized) -{ - JUCE_TRY - { - if (wasMoved) - moved(); - - if (wasResized) - { - resized(); - - for (int i = childComponentList_.size(); --i >= 0;) - { - childComponentList_.getUnchecked(i)->parentSizeChanged(); - - i = jmin (i, childComponentList_.size()); - } - } - - if (parentComponent_ != 0) - parentComponent_->childBoundsChanged (this); - - if (componentListeners_ != 0) - { - const ComponentDeletionWatcher deletionChecker (this); - - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentMovedOrResized (*this, wasMoved, wasResized); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } - } - JUCE_CATCH_EXCEPTION -} - -void Component::setSize (const int w, const int h) -{ - setBounds (getX(), getY(), w, h); -} - -void Component::setTopLeftPosition (const int x, const int y) -{ - setBounds (x, y, getWidth(), getHeight()); -} - -void Component::setTopRightPosition (const int x, const int y) -{ - setTopLeftPosition (x - getWidth(), y); -} - -void Component::setBounds (const Rectangle& r) -{ - setBounds (r.getX(), - r.getY(), - r.getWidth(), - r.getHeight()); -} - -void Component::setBoundsRelative (const float x, const float y, - const float w, const float h) -{ - const int pw = getParentWidth(); - const int ph = getParentHeight(); - - setBounds (roundFloatToInt (x * pw), - roundFloatToInt (y * ph), - roundFloatToInt (w * pw), - roundFloatToInt (h * ph)); -} - -void Component::setCentrePosition (const int x, const int y) -{ - setTopLeftPosition (x - getWidth() / 2, - y - getHeight() / 2); -} - -void Component::setCentreRelative (const float x, const float y) -{ - setCentrePosition (roundFloatToInt (getParentWidth() * x), - roundFloatToInt (getParentHeight() * y)); -} - -void Component::centreWithSize (const int width, const int height) -{ - setBounds ((getParentWidth() - width) / 2, - (getParentHeight() - height) / 2, - width, - height); -} - -void Component::setBoundsInset (const BorderSize& borders) -{ - setBounds (borders.getLeft(), - borders.getTop(), - getParentWidth() - (borders.getLeftAndRight()), - getParentHeight() - (borders.getTopAndBottom())); -} - -void Component::setBoundsToFit (int x, int y, int width, int height, - const Justification& justification, - const bool onlyReduceInSize) -{ - // it's no good calling this method unless both the component and - // target rectangle have a finite size. - jassert (getWidth() > 0 && getHeight() > 0 && width > 0 && height > 0); - - if (getWidth() > 0 && getHeight() > 0 - && width > 0 && height > 0) - { - int newW, newH; - - if (onlyReduceInSize && getWidth() <= width && getHeight() <= height) - { - newW = getWidth(); - newH = getHeight(); - } - else - { - const double imageRatio = getHeight() / (double) getWidth(); - const double targetRatio = height / (double) width; - - if (imageRatio <= targetRatio) - { - newW = width; - newH = jmin (height, roundDoubleToInt (newW * imageRatio)); - } - else - { - newH = height; - newW = jmin (width, roundDoubleToInt (newH / imageRatio)); - } - } - - if (newW > 0 && newH > 0) - { - int newX, newY; - justification.applyToRectangle (newX, newY, newW, newH, - x, y, width, height); - - setBounds (newX, newY, newW, newH); - } - } -} - -//============================================================================== -bool Component::hitTest (int x, int y) -{ - if (! flags.ignoresMouseClicksFlag) - return true; - - if (flags.allowChildMouseClicksFlag) - { - for (int i = getNumChildComponents(); --i >= 0;) - { - Component* const c = getChildComponent (i); - - if (c->isVisible() - && c->bounds_.contains (x, y) - && c->hitTest (x - c->getX(), - y - c->getY())) - { - return true; - } - } - } - - return false; -} - -void Component::setInterceptsMouseClicks (const bool allowClicks, - const bool allowClicksOnChildComponents) throw() -{ - flags.ignoresMouseClicksFlag = ! allowClicks; - flags.allowChildMouseClicksFlag = allowClicksOnChildComponents; -} - -void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, - bool& allowsClicksOnChildComponents) const throw() -{ - allowsClicksOnThisComponent = ! flags.ignoresMouseClicksFlag; - allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag; -} - -bool Component::contains (const int x, const int y) -{ - if (((unsigned int) x) < (unsigned int) getWidth() - && ((unsigned int) y) < (unsigned int) getHeight() - && hitTest (x, y)) - { - if (parentComponent_ != 0) - { - return parentComponent_->contains (x + getX(), - y + getY()); - } - else if (flags.hasHeavyweightPeerFlag) - { - const ComponentPeer* const peer = getPeer(); - - if (peer != 0) - return peer->contains (x, y, true); - } - } - - return false; -} - -bool Component::reallyContains (int x, int y, const bool returnTrueIfWithinAChild) -{ - if (! contains (x, y)) - return false; - - Component* p = this; - - while (p->parentComponent_ != 0) - { - x += p->getX(); - y += p->getY(); - - p = p->parentComponent_; - } - - const Component* const c = p->getComponentAt (x, y); - - return (c == this) || (returnTrueIfWithinAChild && isParentOf (c)); -} - -Component* Component::getComponentAt (const int x, const int y) -{ - if (flags.visibleFlag - && ((unsigned int) x) < (unsigned int) getWidth() - && ((unsigned int) y) < (unsigned int) getHeight() - && hitTest (x, y)) - { - for (int i = childComponentList_.size(); --i >= 0;) - { - Component* const child = childComponentList_.getUnchecked(i); - - Component* const c = child->getComponentAt (x - child->getX(), - y - child->getY()); - - if (c != 0) - return c; - } - - return this; - } - - return 0; -} - -//============================================================================== -void Component::addChildComponent (Component* const child, int zOrder) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (child != 0 && child->parentComponent_ != this) - { - if (child->parentComponent_ != 0) - child->parentComponent_->removeChildComponent (child); - else - child->removeFromDesktop(); - - child->parentComponent_ = this; - - if (child->isVisible()) - child->repaintParent(); - - if (! child->isAlwaysOnTop()) - { - if (zOrder < 0 || zOrder > childComponentList_.size()) - zOrder = childComponentList_.size(); - - while (zOrder > 0) - { - if (! childComponentList_.getUnchecked (zOrder - 1)->isAlwaysOnTop()) - break; - - --zOrder; - } - } - - childComponentList_.insert (zOrder, child); - - child->internalHierarchyChanged(); - internalChildrenChanged(); - } -} - -void Component::addAndMakeVisible (Component* const child, int zOrder) -{ - if (child != 0) - { - child->setVisible (true); - addChildComponent (child, zOrder); - } -} - -void Component::removeChildComponent (Component* const child) -{ - removeChildComponent (childComponentList_.indexOf (child)); -} - -Component* Component::removeChildComponent (const int index) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - Component* const child = childComponentList_ [index]; - - if (child != 0) - { - sendFakeMouseMove(); - child->repaintParent(); - - childComponentList_.remove (index); - child->parentComponent_ = 0; - - JUCE_TRY - { - if ((currentlyFocusedComponent == child) - || child->isParentOf (currentlyFocusedComponent)) - { - // get rid first to force the grabKeyboardFocus to change to us. - giveAwayFocus(); - grabKeyboardFocus(); - } - } -#if JUCE_CATCH_UNHANDLED_EXCEPTIONS - catch (const std::exception& e) - { - currentlyFocusedComponent = 0; - Desktop::getInstance().triggerFocusCallback(); - JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); - } - catch (...) - { - currentlyFocusedComponent = 0; - Desktop::getInstance().triggerFocusCallback(); - JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); - } -#endif - - child->internalHierarchyChanged(); - internalChildrenChanged(); - } - - return child; -} - -//============================================================================== -void Component::removeAllChildren() -{ - for (int i = childComponentList_.size(); --i >= 0;) - removeChildComponent (i); -} - -void Component::deleteAllChildren() -{ - for (int i = childComponentList_.size(); --i >= 0;) - delete (removeChildComponent (i)); -} - -//============================================================================== -int Component::getNumChildComponents() const throw() -{ - return childComponentList_.size(); -} - -Component* Component::getChildComponent (const int index) const throw() -{ - return childComponentList_ [index]; -} - -int Component::getIndexOfChildComponent (const Component* const child) const throw() -{ - return childComponentList_.indexOf (const_cast (child)); -} - -Component* Component::getTopLevelComponent() const throw() -{ - const Component* comp = this; - - while (comp->parentComponent_ != 0) - comp = comp->parentComponent_; - - return (Component*) comp; -} - -bool Component::isParentOf (const Component* possibleChild) const throw() -{ - while (possibleChild->isValidComponent()) - { - possibleChild = possibleChild->parentComponent_; - - if (possibleChild == this) - return true; - } - - return false; -} - -//============================================================================== -void Component::parentHierarchyChanged() -{ -} - -void Component::childrenChanged() -{ -} - -void Component::internalChildrenChanged() -{ - const ComponentDeletionWatcher deletionChecker (this); - const bool hasListeners = componentListeners_ != 0; - - childrenChanged(); - - if (hasListeners) - { - if (deletionChecker.hasBeenDeleted()) - return; - - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentChildrenChanged (*this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } -} - -void Component::internalHierarchyChanged() -{ - parentHierarchyChanged(); - - const ComponentDeletionWatcher deletionChecker (this); - - if (componentListeners_ != 0) - { - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentParentHierarchyChanged (*this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } - - for (int i = childComponentList_.size(); --i >= 0;) - { - childComponentList_.getUnchecked (i)->internalHierarchyChanged(); - - // you really shouldn't delete the parent component during a callback telling you - // that it's changed.. - jassert (! deletionChecker.hasBeenDeleted()); - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, childComponentList_.size()); - } -} - -//============================================================================== -void* Component::runModalLoopCallback (void* userData) -{ - return (void*) (pointer_sized_int) ((Component*) userData)->runModalLoop(); -} - -int Component::runModalLoop() -{ - if (! MessageManager::getInstance()->isThisTheMessageThread()) - { - // use a callback so this can be called from non-gui threads - return (int) (pointer_sized_int) - MessageManager::getInstance() - ->callFunctionOnMessageThread (&runModalLoopCallback, (void*) this); - } - - Component* const prevFocused = getCurrentlyFocusedComponent(); - - ComponentDeletionWatcher* deletionChecker = 0; - if (prevFocused != 0) - deletionChecker = new ComponentDeletionWatcher (prevFocused); - - if (! isCurrentlyModal()) - enterModalState(); - - JUCE_TRY - { - while (flags.currentlyModalFlag && flags.visibleFlag) - { - if (! MessageManager::getInstance()->runDispatchLoopUntil (20)) - break; - - // check whether this component was deleted during the last message - if (! isValidMessageListener()) - break; - } - } -#if JUCE_CATCH_UNHANDLED_EXCEPTIONS - catch (const std::exception& e) - { - JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); - return 0; - } - catch (...) - { - JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); - return 0; - } -#endif - - const int modalIndex = modalComponentReturnValueKeys.indexOf (this); - int returnValue = 0; - - if (modalIndex >= 0) - { - modalComponentReturnValueKeys.remove (modalIndex); - returnValue = modalReturnValues.remove (modalIndex); - } - - modalComponentStack.removeValue (this); - - if (deletionChecker != 0) - { - if (! deletionChecker->hasBeenDeleted()) - prevFocused->grabKeyboardFocus(); - - delete deletionChecker; - } - - return returnValue; -} - -void Component::enterModalState (const bool takeKeyboardFocus) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - // Check for an attempt to make a component modal when it already is! - // This can cause nasty problems.. - jassert (! flags.currentlyModalFlag); - - if (! isCurrentlyModal()) - { - modalComponentStack.add (this); - modalComponentReturnValueKeys.add (this); - modalReturnValues.add (0); - - flags.currentlyModalFlag = true; - setVisible (true); - - if (takeKeyboardFocus) - grabKeyboardFocus(); - } -} - -void Component::exitModalState (const int returnValue) -{ - if (isCurrentlyModal()) - { - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - const int modalIndex = modalComponentReturnValueKeys.indexOf (this); - - if (modalIndex >= 0) - { - modalReturnValues.set (modalIndex, returnValue); - } - else - { - modalComponentReturnValueKeys.add (this); - modalReturnValues.add (returnValue); - } - - modalComponentStack.removeValue (this); - - flags.currentlyModalFlag = false; - } - else - { - postMessage (new Message (exitModalStateMessage, returnValue, 0, 0)); - } - } -} - -bool Component::isCurrentlyModal() const throw() -{ - return flags.currentlyModalFlag - && getCurrentlyModalComponent() == this; -} - -bool Component::isCurrentlyBlockedByAnotherModalComponent() const throw() -{ - Component* const mc = getCurrentlyModalComponent(); - - return mc != 0 - && mc != this - && (! mc->isParentOf (this)) - && ! mc->canModalEventBeSentToComponent (this); -} - -Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent() throw() -{ - Component* const c = (Component*) modalComponentStack.getLast(); - - return c->isValidComponent() ? c : 0; -} - -//============================================================================== -void Component::setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) throw() -{ - flags.bringToFrontOnClickFlag = shouldBeBroughtToFront; -} - -bool Component::isBroughtToFrontOnMouseClick() const throw() -{ - return flags.bringToFrontOnClickFlag; -} - -//============================================================================== -void Component::setMouseCursor (const MouseCursor& cursor) throw() -{ - cursor_ = cursor; - - if (flags.visibleFlag) - { - int mx, my; - getMouseXYRelative (mx, my); - - if (flags.draggingFlag || reallyContains (mx, my, false)) - { - internalUpdateMouseCursor (false); - } - } -} - -const MouseCursor Component::getMouseCursor() -{ - return cursor_; -} - -void Component::updateMouseCursor() const throw() -{ - sendFakeMouseMove(); -} - -void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() -{ - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - MouseCursor mc (getMouseCursor()); - - if (isUnboundedMouseModeOn && (unboundedMouseOffsetX != 0 - || unboundedMouseOffsetY != 0 - || ! isCursorVisibleUntilOffscreen)) - { - mc = MouseCursor::NoCursor; - } - - static void* currentCursorHandle = 0; - - if (forcedUpdate || mc.getHandle() != currentCursorHandle) - { - currentCursorHandle = mc.getHandle(); - mc.showInWindow (peer); - } - } -} - -//============================================================================== -void Component::setRepaintsOnMouseActivity (const bool shouldRepaint) throw() -{ - flags.repaintOnMouseActivityFlag = shouldRepaint; -} - -//============================================================================== -void Component::repaintParent() throw() -{ - if (flags.visibleFlag) - internalRepaint (0, 0, getWidth(), getHeight()); -} - -void Component::repaint() throw() -{ - repaint (0, 0, getWidth(), getHeight()); -} - -void Component::repaint (const int x, const int y, - const int w, const int h) throw() -{ - deleteAndZero (bufferedImage_); - - if (flags.visibleFlag) - internalRepaint (x, y, w, h); -} - -void Component::internalRepaint (int x, int y, int w, int h) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (x < 0) - { - w += x; - x = 0; - } - - if (x + w > getWidth()) - w = getWidth() - x; - - if (w > 0) - { - if (y < 0) - { - h += y; - y = 0; - } - - if (y + h > getHeight()) - h = getHeight() - y; - - if (h > 0) - { - if (parentComponent_ != 0) - { - x += getX(); - y += getY(); - - if (parentComponent_->flags.visibleFlag) - parentComponent_->internalRepaint (x, y, w, h); - } - else if (flags.hasHeavyweightPeerFlag) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - peer->repaint (x, y, w, h); - } - } - } -} - -//============================================================================== -void Component::paintEntireComponent (Graphics& originalContext) -{ - jassert (! originalContext.isClipEmpty()); - -#ifdef JUCE_DEBUG - flags.isInsidePaintCall = true; -#endif - - Graphics* g = &originalContext; - Image* effectImage = 0; - - if (effect_ != 0) - { - effectImage = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, - getWidth(), getHeight(), - ! flags.opaqueFlag); - - g = new Graphics (*effectImage); - } - - g->saveState(); - clipObscuredRegions (*g, g->getClipBounds(), 0, 0); - - if (! g->isClipEmpty()) - { - if (bufferedImage_ != 0) - { - g->setColour (Colours::black); - g->drawImageAt (bufferedImage_, 0, 0); - } - else - { - if (flags.bufferToImageFlag) - { - if (bufferedImage_ == 0) - { - bufferedImage_ = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, - getWidth(), getHeight(), ! flags.opaqueFlag); - - Graphics imG (*bufferedImage_); - paint (imG); - } - - g->setColour (Colours::black); - g->drawImageAt (bufferedImage_, 0, 0); - } - else - { - paint (*g); - g->resetToDefaultState(); - } - } - } - - g->restoreState(); - - for (int i = 0; i < childComponentList_.size(); ++i) - { - Component* const child = childComponentList_.getUnchecked (i); - - if (child->isVisible()) - { - g->saveState(); - - if (g->reduceClipRegion (child->getX(), child->getY(), - child->getWidth(), child->getHeight())) - { - for (int j = i + 1; j < childComponentList_.size(); ++j) - { - const Component* const sibling = childComponentList_.getUnchecked (j); - - if (sibling->flags.opaqueFlag && sibling->isVisible()) - g->excludeClipRegion (sibling->getX(), sibling->getY(), - sibling->getWidth(), sibling->getHeight()); - } - - if (! g->isClipEmpty()) - { - g->setOrigin (child->getX(), child->getY()); - - child->paintEntireComponent (*g); - } - } - - g->restoreState(); - } - } - - JUCE_TRY - { - g->saveState(); - paintOverChildren (*g); - g->restoreState(); - } - JUCE_CATCH_EXCEPTION - - if (effect_ != 0) - { - delete g; - - effect_->applyEffect (*effectImage, originalContext); - delete effectImage; - } - -#ifdef JUCE_DEBUG - flags.isInsidePaintCall = false; -#endif -} - -//============================================================================== -Image* Component::createComponentSnapshot (const Rectangle& areaToGrab, - const bool clipImageToComponentBounds) -{ - Rectangle r (areaToGrab); - - if (clipImageToComponentBounds) - r = r.getIntersection (Rectangle (0, 0, getWidth(), getHeight())); - - Image* const componentImage = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, - jmax (1, r.getWidth()), - jmax (1, r.getHeight()), - true); - - Graphics imageContext (*componentImage); - imageContext.setOrigin (-r.getX(), - -r.getY()); - - paintEntireComponent (imageContext); - - return componentImage; -} - -void Component::setComponentEffect (ImageEffectFilter* const effect) -{ - if (effect_ != effect) - { - effect_ = effect; - repaint(); - } -} - -//============================================================================== -LookAndFeel& Component::getLookAndFeel() const throw() -{ - const Component* c = this; - - do - { - if (c->lookAndFeel_ != 0) - return *(c->lookAndFeel_); - - c = c->parentComponent_; - } - while (c != 0); - - return LookAndFeel::getDefaultLookAndFeel(); -} - -void Component::setLookAndFeel (LookAndFeel* const newLookAndFeel) -{ - if (lookAndFeel_ != newLookAndFeel) - { - lookAndFeel_ = newLookAndFeel; - - sendLookAndFeelChange(); - } -} - -void Component::lookAndFeelChanged() -{ -} - -void Component::sendLookAndFeelChange() -{ - repaint(); - - lookAndFeelChanged(); - - // (it's not a great idea to do anything that would delete this component - // during the lookAndFeelChanged() callback) - jassert (isValidComponent()); - - const ComponentDeletionWatcher deletionChecker (this); - - for (int i = childComponentList_.size(); --i >= 0;) - { - childComponentList_.getUnchecked (i)->sendLookAndFeelChange(); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, childComponentList_.size()); - } -} - -static const String getColourPropertyName (const int colourId) throw() -{ - String s; - s.preallocateStorage (18); - s << T("jcclr_") << colourId; - return s; -} - -const Colour Component::findColour (const int colourId, const bool inheritFromParent) const throw() -{ - const String customColour (getComponentProperty (getColourPropertyName (colourId), - inheritFromParent, - String::empty)); - - if (customColour.isNotEmpty()) - return Colour (customColour.getIntValue()); - - return getLookAndFeel().findColour (colourId); -} - -bool Component::isColourSpecified (const int colourId) const throw() -{ - return getComponentProperty (getColourPropertyName (colourId), - false, - String::empty).isNotEmpty(); -} - -void Component::removeColour (const int colourId) -{ - if (isColourSpecified (colourId)) - { - removeComponentProperty (getColourPropertyName (colourId)); - colourChanged(); - } -} - -void Component::setColour (const int colourId, const Colour& colour) -{ - const String colourName (getColourPropertyName (colourId)); - const String customColour (getComponentProperty (colourName, false, String::empty)); - - if (customColour.isEmpty() || Colour (customColour.getIntValue()) != colour) - { - setComponentProperty (colourName, colour); - colourChanged(); - } -} - -void Component::copyAllExplicitColoursTo (Component& target) const throw() -{ - if (propertySet_ != 0) - { - const StringPairArray& props = propertySet_->getAllProperties(); - const StringArray& keys = props.getAllKeys(); - - for (int i = 0; i < keys.size(); ++i) - { - if (keys[i].startsWith (T("jcclr_"))) - { - target.setComponentProperty (keys[i], - props.getAllValues() [i]); - } - } - - target.colourChanged(); - } -} - -void Component::colourChanged() -{ -} - -//============================================================================== -const Rectangle Component::getUnclippedArea() const -{ - int x = 0, y = 0, w = getWidth(), h = getHeight(); - - Component* p = parentComponent_; - int px = getX(); - int py = getY(); - - while (p != 0) - { - if (! Rectangle::intersectRectangles (x, y, w, h, -px, -py, p->getWidth(), p->getHeight())) - return Rectangle(); - - px += p->getX(); - py += p->getY(); - p = p->parentComponent_; - } - - return Rectangle (x, y, w, h); -} - -void Component::clipObscuredRegions (Graphics& g, const Rectangle& clipRect, - const int deltaX, const int deltaY) const throw() -{ - for (int i = childComponentList_.size(); --i >= 0;) - { - const Component* const c = childComponentList_.getUnchecked(i); - - if (c->isVisible()) - { - Rectangle newClip (clipRect.getIntersection (c->bounds_)); - - if (! newClip.isEmpty()) - { - if (c->isOpaque()) - { - g.excludeClipRegion (deltaX + newClip.getX(), - deltaY + newClip.getY(), - newClip.getWidth(), - newClip.getHeight()); - } - else - { - newClip.translate (-c->getX(), -c->getY()); - c->clipObscuredRegions (g, newClip, - c->getX() + deltaX, - c->getY() + deltaY); - } - } - } - } -} - -void Component::getVisibleArea (RectangleList& result, - const bool includeSiblings) const -{ - result.clear(); - const Rectangle unclipped (getUnclippedArea()); - - if (! unclipped.isEmpty()) - { - result.add (unclipped); - - if (includeSiblings) - { - const Component* const c = getTopLevelComponent(); - - int x = 0, y = 0; - c->relativePositionToOtherComponent (this, x, y); - - c->subtractObscuredRegions (result, x, y, - Rectangle (0, 0, c->getWidth(), c->getHeight()), - this); - } - - subtractObscuredRegions (result, 0, 0, unclipped, 0); - result.consolidate(); - } -} - -void Component::subtractObscuredRegions (RectangleList& result, - const int deltaX, - const int deltaY, - const Rectangle& clipRect, - const Component* const compToAvoid) const throw() -{ - for (int i = childComponentList_.size(); --i >= 0;) - { - const Component* const c = childComponentList_.getUnchecked(i); - - if (c != compToAvoid && c->isVisible()) - { - if (c->isOpaque()) - { - Rectangle childBounds (c->bounds_.getIntersection (clipRect)); - childBounds.translate (deltaX, deltaY); - - result.subtract (childBounds); - } - else - { - Rectangle newClip (clipRect.getIntersection (c->bounds_)); - newClip.translate (-c->getX(), -c->getY()); - - c->subtractObscuredRegions (result, - c->getX() + deltaX, - c->getY() + deltaY, - newClip, - compToAvoid); - } - } - } -} - -//============================================================================== -void Component::mouseEnter (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseExit (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseDown (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseUp (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseDrag (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseMove (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseDoubleClick (const MouseEvent&) -{ - // base class does nothing -} - -void Component::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) -{ - // the base class just passes this event up to its parent.. - - if (parentComponent_ != 0) - parentComponent_->mouseWheelMove (e.getEventRelativeTo (parentComponent_), - wheelIncrementX, wheelIncrementY); -} - - -//============================================================================== -void Component::resized() -{ - // base class does nothing -} - -void Component::moved() -{ - // base class does nothing -} - -void Component::childBoundsChanged (Component*) -{ - // base class does nothing -} - -void Component::parentSizeChanged() -{ - // base class does nothing -} - -void Component::addComponentListener (ComponentListener* const newListener) throw() -{ - if (componentListeners_ == 0) - componentListeners_ = new VoidArray (4); - - componentListeners_->addIfNotAlreadyThere (newListener); -} - -void Component::removeComponentListener (ComponentListener* const listenerToRemove) throw() -{ - jassert (isValidComponent()); - - if (componentListeners_ != 0) - componentListeners_->removeValue (listenerToRemove); -} - -//============================================================================== -void Component::inputAttemptWhenModal() -{ - getTopLevelComponent()->toFront (true); - - getLookAndFeel().playAlertSound(); -} - -bool Component::canModalEventBeSentToComponent (const Component*) -{ - return false; -} - -void Component::internalModalInputAttempt() -{ - Component* const current = getCurrentlyModalComponent(); - - if (current != 0) - current->inputAttemptWhenModal(); -} - - -//============================================================================== -void Component::paint (Graphics&) -{ - // all painting is done in the subclasses - - jassert (! isOpaque()); // if your component's opaque, you've gotta paint it! -} - -void Component::paintOverChildren (Graphics&) -{ - // all painting is done in the subclasses -} - -//============================================================================== -void Component::handleMessage (const Message& message) -{ - if (message.intParameter1 == exitModalStateMessage) - { - exitModalState (message.intParameter2); - } - else if (message.intParameter1 == customCommandMessage) - { - handleCommandMessage (message.intParameter2); - } -} - -//============================================================================== -void Component::postCommandMessage (const int commandId) throw() -{ - postMessage (new Message (customCommandMessage, commandId, 0, 0)); -} - -void Component::handleCommandMessage (int) -{ - // used by subclasses -} - -//============================================================================== -void Component::addMouseListener (MouseListener* const newListener, - const bool wantsEventsForAllNestedChildComponents) throw() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (mouseListeners_ == 0) - mouseListeners_ = new VoidArray (4); - - if (! mouseListeners_->contains (newListener)) - { - if (wantsEventsForAllNestedChildComponents) - { - mouseListeners_->insert (0, newListener); - ++numDeepMouseListeners; - } - else - { - mouseListeners_->add (newListener); - } - } -} - -void Component::removeMouseListener (MouseListener* const listenerToRemove) throw() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (mouseListeners_ != 0) - { - const int index = mouseListeners_->indexOf (listenerToRemove); - - if (index >= 0) - { - if (index < numDeepMouseListeners) - --numDeepMouseListeners; - - mouseListeners_->remove (index); - } - } -} - -//============================================================================== -void Component::internalMouseEnter (int x, int y, int64 time) -{ - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // if something else is modal, always just show a normal mouse cursor - if (componentUnderMouse == this) - { - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - MouseCursor mc (MouseCursor::NormalCursor); - mc.showInWindow (peer); - } - } - - return; - } - - if (! flags.mouseInsideFlag) - { - flags.mouseInsideFlag = true; - flags.mouseOverFlag = true; - flags.draggingFlag = false; - - if (isValidComponent()) - { - const ComponentDeletionWatcher deletionChecker (this); - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (time), - x, y, - Time (time), - 0, false); - - mouseEnter (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseEnter (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked(i))->mouseEnter (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked(i)))->mouseEnter (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } - } - - if (componentUnderMouse == this) - internalUpdateMouseCursor (true); -} - -void Component::internalMouseExit (int x, int y, int64 time) -{ - const ComponentDeletionWatcher deletionChecker (this); - - if (flags.draggingFlag) - { - internalMouseUp (ModifierKeys::getCurrentModifiers().getRawFlags(), x, y, time); - - if (deletionChecker.hasBeenDeleted()) - return; - } - - enableUnboundedMouseMovement (false); - - if (flags.mouseInsideFlag || flags.mouseOverFlag) - { - flags.mouseInsideFlag = false; - flags.mouseOverFlag = false; - flags.draggingFlag = false; - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (time), - x, y, - Time (time), - 0, false); - mouseExit (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseExit (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseExit (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseExit (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } -} - -//============================================================================== -class InternalDragRepeater : public Timer -{ -public: - InternalDragRepeater() - {} - - ~InternalDragRepeater() - {} - - void timerCallback() - { - Component* const c = Component::getComponentUnderMouse(); - - if (c != 0 && c->isMouseButtonDown()) - { - int x, y; - c->getMouseXYRelative (x, y); - - // the offsets have been added on, so must be taken off before calling the - // drag.. otherwise they'll be added twice - x -= unboundedMouseOffsetX; - y -= unboundedMouseOffsetY; - - c->internalMouseDrag (x, y, Time::currentTimeMillis()); - } - } - - juce_UseDebuggingNewOperator -}; - -static InternalDragRepeater* dragRepeater = 0; - -void Component::beginDragAutoRepeat (const int interval) -{ - if (interval > 0) - { - if (dragRepeater == 0) - dragRepeater = new InternalDragRepeater(); - - if (dragRepeater->getTimerInterval() != interval) - dragRepeater->startTimer (interval); - } - else - { - deleteAndZero (dragRepeater); - } -} - -//============================================================================== -void Component::internalMouseDown (const int x, const int y) -{ - const ComponentDeletionWatcher deletionChecker (this); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - internalModalInputAttempt(); - - if (deletionChecker.hasBeenDeleted()) - return; - - // If processing the input attempt has exited the modal loop, we'll allow the event - // to be delivered.. - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (juce_recentMouseDownTimes[0]), - x, y, - Time (juce_recentMouseDownTimes[0]), - countMouseClicks(), - false); - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - return; - } - } - - { - Component* c = this; - - while (c != 0) - { - if (c->isBroughtToFrontOnMouseClick()) - { - c->toFront (true); - - if (deletionChecker.hasBeenDeleted()) - return; - } - - c = c->parentComponent_; - } - } - - if (! flags.dontFocusOnMouseClickFlag) - grabFocusInternal (focusChangedByMouseClick); - - if (! deletionChecker.hasBeenDeleted()) - { - flags.draggingFlag = true; - flags.mouseOverFlag = true; - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (juce_recentMouseDownTimes[0]), - x, y, - Time (juce_recentMouseDownTimes[0]), - countMouseClicks(), - false); - mouseDown (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDown (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDown (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } -} - -//============================================================================== -void Component::internalMouseUp (const int oldModifiers, int x, int y, const int64 time) -{ - if (isValidComponent() && flags.draggingFlag) - { - flags.draggingFlag = false; - deleteAndZero (dragRepeater); - - x += unboundedMouseOffsetX; - y += unboundedMouseOffsetY; - juce_LastMousePosX = x; - juce_LastMousePosY = y; - relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY); - - const ComponentDeletionWatcher deletionChecker (this); - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - int mdx = juce_recentMouseDownX[0]; - int mdy = juce_recentMouseDownY[0]; - globalPositionToRelative (mdx, mdy); - - const MouseEvent me (x, y, - oldModifiers, - this, - Time (time), - mdx, mdy, - Time (juce_recentMouseDownTimes [0]), - countMouseClicks(), - juce_MouseHasMovedSignificantlySincePressed - || juce_recentMouseDownTimes[0] + 300 < time); - - mouseUp (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseUp (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseUp (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - { - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseUp (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } - - // check for double-click - if (me.getNumberOfClicks() >= 2) - { - const int numListeners = (mouseListeners_ != 0) ? mouseListeners_->size() : 0; - - mouseDoubleClick (me); - - int i; - for (i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDoubleClick (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - for (i = numListeners; --i >= 0;) - { - if (deletionChecker.hasBeenDeleted() || mouseListeners_ == 0) - return; - - MouseListener* const ml = (MouseListener*)((*mouseListeners_)[i]); - if (ml != 0) - ml->mouseDoubleClick (me); - } - - if (deletionChecker.hasBeenDeleted()) - return; - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDoubleClick (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } - } - - enableUnboundedMouseMovement (false); -} - -void Component::internalMouseDrag (int x, int y, const int64 time) -{ - if (isValidComponent() && flags.draggingFlag) - { - flags.mouseOverFlag = reallyContains (x, y, false); - - x += unboundedMouseOffsetX; - y += unboundedMouseOffsetY; - juce_LastMousePosX = x; - juce_LastMousePosY = y; - relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY); - - juce_MouseHasMovedSignificantlySincePressed - = juce_MouseHasMovedSignificantlySincePressed - || abs (juce_recentMouseDownX[0] - juce_LastMousePosX) >= 4 - || abs (juce_recentMouseDownY[0] - juce_LastMousePosY) >= 4; - - const ComponentDeletionWatcher deletionChecker (this); - - int mdx = juce_recentMouseDownX[0]; - int mdy = juce_recentMouseDownY[0]; - globalPositionToRelative (mdx, mdy); - - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (time), - mdx, mdy, - Time (juce_recentMouseDownTimes[0]), - countMouseClicks(), - juce_MouseHasMovedSignificantlySincePressed - || juce_recentMouseDownTimes[0] + 300 < time); - - mouseDrag (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDrag (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDrag (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDrag (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - - if (this == componentUnderMouse) - { - if (isUnboundedMouseModeOn) - { - Rectangle screenArea (getParentMonitorArea().expanded (-2, -2)); - - int mx, my; - Desktop::getMousePosition (mx, my); - - if (! screenArea.contains (mx, my)) - { - int deltaX = 0, deltaY = 0; - - if (mx <= screenArea.getX() || mx >= screenArea.getRight()) - deltaX = getScreenX() + getWidth() / 2 - mx; - - if (my <= screenArea.getY() || my >= screenArea.getBottom()) - deltaY = getScreenY() + getHeight() / 2 - my; - - unboundedMouseOffsetX -= deltaX; - unboundedMouseOffsetY -= deltaY; - - Desktop::setMousePosition (mx + deltaX, - my + deltaY); - } - else if (isCursorVisibleUntilOffscreen - && (unboundedMouseOffsetX != 0 || unboundedMouseOffsetY != 0) - && screenArea.contains (mx + unboundedMouseOffsetX, - my + unboundedMouseOffsetY)) - { - mx += unboundedMouseOffsetX; - my += unboundedMouseOffsetY; - unboundedMouseOffsetX = 0; - unboundedMouseOffsetY = 0; - - Desktop::setMousePosition (mx, my); - } - } - - internalUpdateMouseCursor (false); - } - } -} - -void Component::internalMouseMove (const int x, const int y, const int64 time) -{ - const ComponentDeletionWatcher deletionChecker (this); - - if (isValidComponent()) - { - const MouseEvent me (x, y, - ModifierKeys::getCurrentModifiers(), - this, - Time (time), - x, y, - Time (time), - 0, false); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - Desktop::getInstance().sendMouseMove(); - } - else - { - if (this == componentUnderMouse) - internalUpdateMouseCursor (false); - - flags.mouseOverFlag = true; - - mouseMove (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - Desktop::getInstance().resetTimer(); - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseMove (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseMove (me); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseMove (me); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - } - } -} - -void Component::internalMouseWheel (const int intAmountX, const int intAmountY, const int64 time) -{ - const ComponentDeletionWatcher deletionChecker (this); - - const float wheelIncrementX = intAmountX * (1.0f / 256.0f); - const float wheelIncrementY = intAmountY * (1.0f / 256.0f); - - int mx, my; - getMouseXYRelative (mx, my); - - const MouseEvent me (mx, my, - ModifierKeys::getCurrentModifiers(), - this, - Time (time), - mx, my, - Time (time), - 0, false); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - } - else - { - mouseWheelMove (me, wheelIncrementX, wheelIncrementY); - - if (deletionChecker.hasBeenDeleted()) - return; - - for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) - { - ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, Desktop::getInstance().mouseListeners.size()); - } - - if (mouseListeners_ != 0) - { - for (int i = mouseListeners_->size(); --i >= 0;) - { - ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, mouseListeners_->size()); - } - } - - const Component* p = parentComponent_; - - while (p != 0) - { - const ComponentDeletionWatcher parentDeletionChecker (p); - - for (int i = p->numDeepMouseListeners; --i >= 0;) - { - ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); - - if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, p->numDeepMouseListeners); - } - - p = p->parentComponent_; - } - - sendFakeMouseMove(); - } -} - -void Component::sendFakeMouseMove() const -{ - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - peer->sendFakeMouseMove(); -} - -void Component::broughtToFront() -{ -} - -void Component::internalBroughtToFront() -{ - if (isValidComponent()) - { - if (flags.hasHeavyweightPeerFlag) - Desktop::getInstance().componentBroughtToFront (this); - - const ComponentDeletionWatcher deletionChecker (this); - broughtToFront(); - - if (deletionChecker.hasBeenDeleted()) - return; - - if (componentListeners_ != 0) - { - for (int i = componentListeners_->size(); --i >= 0;) - { - ((ComponentListener*) componentListeners_->getUnchecked (i)) - ->componentBroughtToFront (*this); - - if (deletionChecker.hasBeenDeleted()) - return; - - i = jmin (i, componentListeners_->size()); - } - } - - // when brought to the front and there's a modal component blocking this one, - // we need to bring the modal one to the front instead.. - - Component* const cm = getCurrentlyModalComponent(); - - if (cm != 0 && cm->getTopLevelComponent() != getTopLevelComponent()) - { - cm->getTopLevelComponent()->toFront (true); - } - } -} - -void Component::focusGained (FocusChangeType) -{ - // base class does nothing -} - -void Component::internalFocusGain (const FocusChangeType cause) -{ - const ComponentDeletionWatcher deletionChecker (this); - - focusGained (cause); - - if (! deletionChecker.hasBeenDeleted()) - internalChildFocusChange (cause); -} - -void Component::focusLost (FocusChangeType) -{ - // base class does nothing -} - -void Component::internalFocusLoss (const FocusChangeType cause) -{ - const ComponentDeletionWatcher deletionChecker (this); - - focusLost (focusChangedDirectly); - - if (! deletionChecker.hasBeenDeleted()) - internalChildFocusChange (cause); -} - -void Component::focusOfChildComponentChanged (FocusChangeType /*cause*/) -{ - // base class does nothing -} - -void Component::internalChildFocusChange (FocusChangeType cause) -{ - const bool childIsNowFocused = hasKeyboardFocus (true); - - if (flags.childCompFocusedFlag != childIsNowFocused) - { - flags.childCompFocusedFlag = childIsNowFocused; - - const ComponentDeletionWatcher deletionChecker (this); - focusOfChildComponentChanged (cause); - - if (deletionChecker.hasBeenDeleted()) - return; - } - - if (parentComponent_ != 0) - parentComponent_->internalChildFocusChange (cause); -} - -//============================================================================== -bool Component::isEnabled() const throw() -{ - return (! flags.isDisabledFlag) - && (parentComponent_ == 0 || parentComponent_->isEnabled()); -} - -void Component::setEnabled (const bool shouldBeEnabled) -{ - if (flags.isDisabledFlag == shouldBeEnabled) - { - flags.isDisabledFlag = ! shouldBeEnabled; - - // if any parent components are disabled, setting our flag won't make a difference, - // so no need to send a change message - if (parentComponent_ == 0 || parentComponent_->isEnabled()) - sendEnablementChangeMessage(); - } -} - -void Component::sendEnablementChangeMessage() -{ - const ComponentDeletionWatcher deletionChecker (this); - - enablementChanged(); - - if (deletionChecker.hasBeenDeleted()) - return; - - for (int i = getNumChildComponents(); --i >= 0;) - { - Component* const c = getChildComponent (i); - - if (c != 0) - { - c->sendEnablementChangeMessage(); - - if (deletionChecker.hasBeenDeleted()) - return; - } - } -} - -void Component::enablementChanged() -{ -} - -//============================================================================== -void Component::setWantsKeyboardFocus (const bool wantsFocus) throw() -{ - flags.wantsFocusFlag = wantsFocus; -} - -void Component::setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus) -{ - flags.dontFocusOnMouseClickFlag = ! shouldGrabFocus; -} - -bool Component::getMouseClickGrabsKeyboardFocus() const throw() -{ - return ! flags.dontFocusOnMouseClickFlag; -} - -bool Component::getWantsKeyboardFocus() const throw() -{ - return flags.wantsFocusFlag && ! flags.isDisabledFlag; -} - -void Component::setFocusContainer (const bool isFocusContainer) throw() -{ - flags.isFocusContainerFlag = isFocusContainer; -} - -bool Component::isFocusContainer() const throw() -{ - return flags.isFocusContainerFlag; -} - -int Component::getExplicitFocusOrder() const throw() -{ - return getComponentPropertyInt (T("_jexfo"), false, 0); -} - -void Component::setExplicitFocusOrder (const int newFocusOrderIndex) throw() -{ - setComponentProperty (T("_jexfo"), newFocusOrderIndex); -} - -KeyboardFocusTraverser* Component::createFocusTraverser() -{ - if (flags.isFocusContainerFlag || parentComponent_ == 0) - return new KeyboardFocusTraverser(); - - return parentComponent_->createFocusTraverser(); -} - -void Component::takeKeyboardFocus (const FocusChangeType cause) -{ - // give the focus to this component - if (currentlyFocusedComponent != this) - { - JUCE_TRY - { - // get the focus onto our desktop window - ComponentPeer* const peer = getPeer(); - - if (peer != 0) - { - const ComponentDeletionWatcher deletionChecker (this); - - peer->grabFocus(); - - if (peer->isFocused() && currentlyFocusedComponent != this) - { - Component* const componentLosingFocus = currentlyFocusedComponent; - - currentlyFocusedComponent = this; - - Desktop::getInstance().triggerFocusCallback(); - - // call this after setting currentlyFocusedComponent so that the one that's - // losing it has a chance to see where focus is going - if (componentLosingFocus->isValidComponent()) - componentLosingFocus->internalFocusLoss (cause); - - if (currentlyFocusedComponent == this) - { - focusGained (cause); - - if (! deletionChecker.hasBeenDeleted()) - internalChildFocusChange (cause); - } - } - } - } -#if JUCE_CATCH_UNHANDLED_EXCEPTIONS - catch (const std::exception& e) - { - currentlyFocusedComponent = 0; - Desktop::getInstance().triggerFocusCallback(); - JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); - } - catch (...) - { - currentlyFocusedComponent = 0; - Desktop::getInstance().triggerFocusCallback(); - JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); - } -#endif - } -} - -void Component::grabFocusInternal (const FocusChangeType cause, const bool canTryParent) -{ - if (isShowing()) - { - if (flags.wantsFocusFlag && (isEnabled() || parentComponent_ == 0)) - { - takeKeyboardFocus (cause); - } - else - { - if (isParentOf (currentlyFocusedComponent) - && currentlyFocusedComponent->isShowing()) - { - // do nothing if the focused component is actually a child of ours.. - } - else - { - // find the default child component.. - KeyboardFocusTraverser* const traverser = createFocusTraverser(); - - if (traverser != 0) - { - Component* const defaultComp = traverser->getDefaultComponent (this); - delete traverser; - - if (defaultComp != 0) - { - defaultComp->grabFocusInternal (cause, false); - return; - } - } - - if (canTryParent && parentComponent_ != 0) - { - // if no children want it and we're allowed to try our parent comp, - // then pass up to parent, which will try our siblings. - parentComponent_->grabFocusInternal (cause, true); - } - } - } - } -} - -void Component::grabKeyboardFocus() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - grabFocusInternal (focusChangedDirectly); -} - -void Component::moveKeyboardFocusToSibling (const bool moveToNext) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - checkMessageManagerIsLocked - - if (parentComponent_ != 0) - { - KeyboardFocusTraverser* const traverser = createFocusTraverser(); - - if (traverser != 0) - { - Component* const nextComp = moveToNext ? traverser->getNextComponent (this) - : traverser->getPreviousComponent (this); - delete traverser; - - if (nextComp != 0) - { - if (nextComp->isCurrentlyBlockedByAnotherModalComponent()) - { - const ComponentDeletionWatcher deletionChecker (nextComp); - internalModalInputAttempt(); - - if (deletionChecker.hasBeenDeleted() - || nextComp->isCurrentlyBlockedByAnotherModalComponent()) - return; - } - - nextComp->grabFocusInternal (focusChangedByTabKey); - return; - } - } - - parentComponent_->moveKeyboardFocusToSibling (moveToNext); - } -} - -bool Component::hasKeyboardFocus (const bool trueIfChildIsFocused) const throw() -{ - return (currentlyFocusedComponent == this) - || (trueIfChildIsFocused && isParentOf (currentlyFocusedComponent)); -} - -Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() -{ - return currentlyFocusedComponent; -} - -void Component::giveAwayFocus() -{ - // use a copy so we can clear the value before the call - Component* const componentLosingFocus = currentlyFocusedComponent; - currentlyFocusedComponent = 0; - Desktop::getInstance().triggerFocusCallback(); - - if (componentLosingFocus->isValidComponent()) - componentLosingFocus->internalFocusLoss (focusChangedDirectly); -} - -//============================================================================== -bool Component::isMouseOver() const throw() -{ - return flags.mouseOverFlag; -} - -bool Component::isMouseButtonDown() const throw() -{ - return flags.draggingFlag; -} - -bool Component::isMouseOverOrDragging() const throw() -{ - return flags.mouseOverFlag || flags.draggingFlag; -} - -bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw() -{ - return ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(); -} - -void Component::getMouseXYRelative (int& mx, int& my) const throw() -{ - Desktop::getMousePosition (mx, my); - globalPositionToRelative (mx, my); - - mx += unboundedMouseOffsetX; - my += unboundedMouseOffsetY; -} - -void Component::enableUnboundedMouseMovement (bool enable, - bool keepCursorVisibleUntilOffscreen) throw() -{ - enable = enable && isMouseButtonDown(); - isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen; - - if (enable != isUnboundedMouseModeOn) - { - if ((! enable) && ((! isCursorVisibleUntilOffscreen) - || unboundedMouseOffsetX != 0 - || unboundedMouseOffsetY != 0)) - { - // when released, return the mouse to within the component's bounds - - int mx, my; - getMouseXYRelative (mx, my); - - mx = jlimit (0, getWidth(), mx); - my = jlimit (0, getHeight(), my); - - relativePositionToGlobal (mx, my); - - Desktop::setMousePosition (mx, my); - } - - isUnboundedMouseModeOn = enable; - unboundedMouseOffsetX = 0; - unboundedMouseOffsetY = 0; - - internalUpdateMouseCursor (true); - } -} - -Component* JUCE_CALLTYPE Component::getComponentUnderMouse() throw() -{ - return componentUnderMouse; -} - -//============================================================================== -const Rectangle Component::getParentMonitorArea() const throw() -{ - int centreX = getWidth() / 2; - int centreY = getHeight() / 2; - relativePositionToGlobal (centreX, centreY); - - return Desktop::getInstance().getMonitorAreaContaining (centreX, centreY); -} - -//============================================================================== -void Component::addKeyListener (KeyListener* const newListener) throw() -{ - if (keyListeners_ == 0) - keyListeners_ = new VoidArray (4); - - keyListeners_->addIfNotAlreadyThere (newListener); -} - -void Component::removeKeyListener (KeyListener* const listenerToRemove) throw() -{ - if (keyListeners_ != 0) - keyListeners_->removeValue (listenerToRemove); -} - -bool Component::keyPressed (const KeyPress&) -{ - return false; -} - -bool Component::keyStateChanged() -{ - return false; -} - -void Component::modifierKeysChanged (const ModifierKeys& modifiers) -{ - if (parentComponent_ != 0) - parentComponent_->modifierKeysChanged (modifiers); -} - -void Component::internalModifierKeysChanged() -{ - sendFakeMouseMove(); - - modifierKeysChanged (ModifierKeys::getCurrentModifiers()); -} - -//============================================================================== -ComponentPeer* Component::getPeer() const throw() -{ - if (flags.hasHeavyweightPeerFlag) - return ComponentPeer::getPeerFor (this); - else if (parentComponent_ != 0) - return parentComponent_->getPeer(); - else - return 0; -} - -//============================================================================== -const String Component::getComponentProperty (const String& keyName, - const bool useParentComponentIfNotFound, - const String& defaultReturnValue) const throw() -{ - if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) - return propertySet_->getValue (keyName, defaultReturnValue); - - if (useParentComponentIfNotFound && (parentComponent_ != 0)) - return parentComponent_->getComponentProperty (keyName, true, defaultReturnValue); - - return defaultReturnValue; -} - -int Component::getComponentPropertyInt (const String& keyName, - const bool useParentComponentIfNotFound, - const int defaultReturnValue) const throw() -{ - if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) - return propertySet_->getIntValue (keyName, defaultReturnValue); - - if (useParentComponentIfNotFound && (parentComponent_ != 0)) - return parentComponent_->getComponentPropertyInt (keyName, true, defaultReturnValue); - - return defaultReturnValue; -} - -double Component::getComponentPropertyDouble (const String& keyName, - const bool useParentComponentIfNotFound, - const double defaultReturnValue) const throw() -{ - if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) - return propertySet_->getDoubleValue (keyName, defaultReturnValue); - - if (useParentComponentIfNotFound && (parentComponent_ != 0)) - return parentComponent_->getComponentPropertyDouble (keyName, true, defaultReturnValue); - - return defaultReturnValue; -} - -bool Component::getComponentPropertyBool (const String& keyName, - const bool useParentComponentIfNotFound, - const bool defaultReturnValue) const throw() -{ - if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) - return propertySet_->getBoolValue (keyName, defaultReturnValue); - - if (useParentComponentIfNotFound && (parentComponent_ != 0)) - return parentComponent_->getComponentPropertyBool (keyName, true, defaultReturnValue); - - return defaultReturnValue; -} - -const Colour Component::getComponentPropertyColour (const String& keyName, - const bool useParentComponentIfNotFound, - const Colour& defaultReturnValue) const throw() -{ - return Colour ((uint32) getComponentPropertyInt (keyName, - useParentComponentIfNotFound, - defaultReturnValue.getARGB())); -} - -void Component::setComponentProperty (const String& keyName, const String& value) throw() -{ - if (propertySet_ == 0) - propertySet_ = new PropertySet(); - - propertySet_->setValue (keyName, value); -} - -void Component::setComponentProperty (const String& keyName, const int value) throw() -{ - if (propertySet_ == 0) - propertySet_ = new PropertySet(); - - propertySet_->setValue (keyName, value); -} - -void Component::setComponentProperty (const String& keyName, const double value) throw() -{ - if (propertySet_ == 0) - propertySet_ = new PropertySet(); - - propertySet_->setValue (keyName, value); -} - -void Component::setComponentProperty (const String& keyName, const bool value) throw() -{ - if (propertySet_ == 0) - propertySet_ = new PropertySet(); - - propertySet_->setValue (keyName, value); -} - -void Component::setComponentProperty (const String& keyName, const Colour& colour) throw() -{ - setComponentProperty (keyName, (int) colour.getARGB()); -} - -void Component::removeComponentProperty (const String& keyName) throw() -{ - if (propertySet_ != 0) - propertySet_->removeValue (keyName); -} - -//============================================================================== -ComponentDeletionWatcher::ComponentDeletionWatcher (const Component* const componentToWatch_) throw() - : componentToWatch (componentToWatch_), - componentUID (componentToWatch_->getComponentUID()) -{ - // not possible to check on an already-deleted object.. - jassert (componentToWatch_->isValidComponent()); -} - -ComponentDeletionWatcher::~ComponentDeletionWatcher() throw() {} - -bool ComponentDeletionWatcher::hasBeenDeleted() const throw() -{ - return ! (componentToWatch->isValidComponent() - && componentToWatch->getComponentUID() == componentUID); -} - -const Component* ComponentDeletionWatcher::getComponent() const throw() -{ - return hasBeenDeleted() ? 0 : componentToWatch; -} - - -END_JUCE_NAMESPACE +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#include "../../../juce_core/basics/juce_StandardHeader.h" + +BEGIN_JUCE_NAMESPACE + +#include "juce_Component.h" +#include "juce_ComponentDeletionWatcher.h" +#include "juce_Desktop.h" +#include "keyboard/juce_KeyListener.h" +#include "lookandfeel/juce_LookAndFeel.h" +#include "../../application/juce_Application.h" +#include "../graphics/geometry/juce_RectangleList.h" +#include "../graphics/imaging/juce_Image.h" +#include "../graphics/contexts/juce_LowLevelGraphicsContext.h" +#include "../../events/juce_MessageManager.h" +#include "../../events/juce_Timer.h" +#include "../../../juce_core/basics/juce_Time.h" +#include "../../../juce_core/misc/juce_PlatformUtilities.h" + + +//============================================================================== +Component* Component::componentUnderMouse = 0; +Component* Component::currentlyFocusedComponent = 0; + +static Array modalComponentStack (4), modalComponentReturnValueKeys (4); +static Array modalReturnValues (4); + +static const int customCommandMessage = 0x7fff0001; +static const int exitModalStateMessage = 0x7fff0002; + +//============================================================================== +// these are also used by ComponentPeer +int64 juce_recentMouseDownTimes [4] = { 0, 0, 0, 0 }; +int juce_recentMouseDownX [4] = { 0, 0, 0, 0 }; +int juce_recentMouseDownY [4] = { 0, 0, 0, 0 }; +Component* juce_recentMouseDownComponent [4] = { 0, 0, 0, 0 }; +int juce_LastMousePosX = 0; +int juce_LastMousePosY = 0; +int juce_MouseClickCounter = 0; +bool juce_MouseHasMovedSignificantlySincePressed = false; + +static int countMouseClicks() throw() +{ + int numClicks = 0; + + if (juce_recentMouseDownTimes[0] != 0) + { + if (! juce_MouseHasMovedSignificantlySincePressed) + ++numClicks; + + for (int i = 1; i < numElementsInArray (juce_recentMouseDownTimes); ++i) + { + if (juce_recentMouseDownTimes[0] - juce_recentMouseDownTimes [i] + < (int) (MouseEvent::getDoubleClickTimeout() * (1.0 + 0.25 * (i - 1))) + && abs (juce_recentMouseDownX[0] - juce_recentMouseDownX[i]) < 8 + && abs (juce_recentMouseDownY[0] - juce_recentMouseDownY[i]) < 8 + && juce_recentMouseDownComponent[0] == juce_recentMouseDownComponent [i]) + { + ++numClicks; + } + else + { + break; + } + } + } + + return numClicks; +} + +static int unboundedMouseOffsetX = 0; +static int unboundedMouseOffsetY = 0; +static bool isUnboundedMouseModeOn = false; +static bool isCursorVisibleUntilOffscreen; + +//============================================================================== +#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + +static uint32 nextComponentUID = 0; + + +//============================================================================== +Component::Component() throw() + : parentComponent_ (0), + componentUID (++nextComponentUID), + numDeepMouseListeners (0), + childComponentList_ (16), + lookAndFeel_ (0), + effect_ (0), + bufferedImage_ (0), + mouseListeners_ (0), + keyListeners_ (0), + componentListeners_ (0), + propertySet_ (0), + componentFlags_ (0) +{ +} + +Component::Component (const String& name) throw() + : componentName_ (name), + parentComponent_ (0), + componentUID (++nextComponentUID), + numDeepMouseListeners (0), + childComponentList_ (16), + lookAndFeel_ (0), + effect_ (0), + bufferedImage_ (0), + mouseListeners_ (0), + keyListeners_ (0), + componentListeners_ (0), + propertySet_ (0), + componentFlags_ (0) +{ +} + +Component::~Component() +{ + if (parentComponent_ != 0) + { + parentComponent_->removeChildComponent (this); + } + else if ((currentlyFocusedComponent == this) + || isParentOf (currentlyFocusedComponent)) + { + giveAwayFocus(); + } + + if (componentUnderMouse == this) + componentUnderMouse = 0; + + if (flags.hasHeavyweightPeerFlag) + removeFromDesktop(); + + modalComponentStack.removeValue (this); + + for (int i = childComponentList_.size(); --i >= 0;) + childComponentList_.getUnchecked(i)->parentComponent_ = 0; + + delete bufferedImage_; + delete mouseListeners_; + delete keyListeners_; + delete componentListeners_; + delete propertySet_; +} + +//============================================================================== +void Component::setName (const String& name) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (componentName_ != name) + { + componentName_ = name; + + if (flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = getPeer(); + + jassert (peer != 0); + if (peer != 0) + peer->setTitle (name); + } + + if (componentListeners_ != 0) + { + const ComponentDeletionWatcher deletionChecker (this); + + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentNameChanged (*this); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } + + } +} + +void Component::setVisible (bool shouldBeVisible) +{ + if (flags.visibleFlag != shouldBeVisible) + { + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + const ComponentDeletionWatcher deletionChecker (this); + + flags.visibleFlag = shouldBeVisible; + + internalRepaint (0, 0, getWidth(), getHeight()); + + sendFakeMouseMove(); + + if (! shouldBeVisible) + { + if (currentlyFocusedComponent == this + || isParentOf (currentlyFocusedComponent)) + { + if (parentComponent_ != 0) + parentComponent_->grabKeyboardFocus(); + else + giveAwayFocus(); + } + } + + sendVisibilityChangeMessage(); + + if ((! deletionChecker.hasBeenDeleted()) && flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = getPeer(); + + jassert (peer != 0); + if (peer != 0) + { + peer->setVisible (shouldBeVisible); + internalHierarchyChanged(); + } + } + } +} + +void Component::visibilityChanged() +{ +} + +void Component::sendVisibilityChangeMessage() +{ + const ComponentDeletionWatcher deletionChecker (this); + + visibilityChanged(); + + if ((! deletionChecker.hasBeenDeleted()) && componentListeners_ != 0) + { + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentVisibilityChanged (*this); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } +} + +bool Component::isShowing() const throw() +{ + if (flags.visibleFlag) + { + if (parentComponent_ != 0) + { + return parentComponent_->isShowing(); + } + else + { + const ComponentPeer* const peer = getPeer(); + + return peer != 0 && ! peer->isMinimised(); + } + } + + return false; +} + +//============================================================================== +class FadeOutProxyComponent : public Component, + public Timer +{ +public: + FadeOutProxyComponent (Component* comp, + const int fadeLengthMs, + const int deltaXToMove, + const int deltaYToMove, + const float scaleFactorAtEnd) + : lastTime (0), + alpha (1.0f), + scale (1.0f) + { + image = comp->createComponentSnapshot (Rectangle (0, 0, comp->getWidth(), comp->getHeight())); + setBounds (comp->getBounds()); + comp->getParentComponent()->addAndMakeVisible (this); + toBehind (comp); + + alphaChangePerMs = -1.0f / (float)fadeLengthMs; + + centreX = comp->getX() + comp->getWidth() * 0.5f; + xChangePerMs = deltaXToMove / (float)fadeLengthMs; + + centreY = comp->getY() + comp->getHeight() * 0.5f; + yChangePerMs = deltaYToMove / (float)fadeLengthMs; + + scaleChangePerMs = (scaleFactorAtEnd - 1.0f) / (float)fadeLengthMs; + + setInterceptsMouseClicks (false, false); + + // 30 fps is enough for a fade, but we need a higher rate if it's moving as well.. + startTimer (1000 / ((deltaXToMove == 0 && deltaYToMove == 0) ? 30 : 50)); + } + + ~FadeOutProxyComponent() + { + delete image; + } + + void paint (Graphics& g) + { + g.setOpacity (alpha); + + g.drawImage (image, + 0, 0, getWidth(), getHeight(), + 0, 0, image->getWidth(), image->getHeight()); + } + + void timerCallback() + { + const uint32 now = Time::getMillisecondCounter(); + + if (lastTime == 0) + lastTime = now; + + const int msPassed = (now > lastTime) ? now - lastTime : 0; + lastTime = now; + + alpha += alphaChangePerMs * msPassed; + + if (alpha > 0) + { + if (xChangePerMs != 0.0f || yChangePerMs != 0.0f || scaleChangePerMs != 0.0f) + { + centreX += xChangePerMs * msPassed; + centreY += yChangePerMs * msPassed; + scale += scaleChangePerMs * msPassed; + + const int w = roundFloatToInt (image->getWidth() * scale); + const int h = roundFloatToInt (image->getHeight() * scale); + + setBounds (roundFloatToInt (centreX) - w / 2, + roundFloatToInt (centreY) - h / 2, + w, h); + } + + repaint(); + } + else + { + delete this; + } + } + + juce_UseDebuggingNewOperator + +private: + Image* image; + uint32 lastTime; + float alpha, alphaChangePerMs; + float centreX, xChangePerMs; + float centreY, yChangePerMs; + float scale, scaleChangePerMs; + + FadeOutProxyComponent (const FadeOutProxyComponent&); + const FadeOutProxyComponent& operator= (const FadeOutProxyComponent&); +}; + +void Component::fadeOutComponent (const int millisecondsToFade, + const int deltaXToMove, + const int deltaYToMove, + const float scaleFactorAtEnd) +{ + //xxx won't work for comps without parents + if (isShowing() && millisecondsToFade > 0) + new FadeOutProxyComponent (this, millisecondsToFade, + deltaXToMove, deltaYToMove, scaleFactorAtEnd); + + setVisible (false); +} + + +//============================================================================== +bool Component::isValidComponent() const throw() +{ + return (this != 0) && isValidMessageListener(); +} + +void* Component::getWindowHandle() const throw() +{ + const ComponentPeer* const peer = getPeer(); + + if (peer != 0) + return peer->getNativeHandle(); + + return 0; +} + +//============================================================================== +void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (! isOpaque()) + styleWanted |= ComponentPeer::windowIsSemiTransparent; + + int currentStyleFlags = 0; + + // don't use getPeer(), so that we only get the peer that's specifically + // for this comp, and not for one of its parents. + ComponentPeer* peer = ComponentPeer::getPeerFor (this); + + if (peer != 0) + currentStyleFlags = peer->getStyleFlags(); + + if (styleWanted != currentStyleFlags || ! flags.hasHeavyweightPeerFlag) + { + const ComponentDeletionWatcher deletionChecker (this); + +#if JUCE_LINUX + // it's wise to give the component a non-zero size before + // putting it on the desktop, as X windows get confused by this, and + // a (1, 1) minimum size is enforced here. + setSize (jmax (1, getWidth()), + jmax (1, getHeight())); +#endif + + int x = 0, y = 0; + relativePositionToGlobal (x, y); + + bool wasFullscreen = false; + bool wasMinimised = false; + ComponentBoundsConstrainer* currentConstainer = 0; + Rectangle oldNonFullScreenBounds; + + if (peer != 0) + { + wasFullscreen = peer->isFullScreen(); + wasMinimised = peer->isMinimised(); + currentConstainer = peer->getConstrainer(); + oldNonFullScreenBounds = peer->getNonFullScreenBounds(); + + removeFromDesktop(); + + setTopLeftPosition (x, y); + } + + if (parentComponent_ != 0) + parentComponent_->removeChildComponent (this); + + if (! deletionChecker.hasBeenDeleted()) + { + flags.hasHeavyweightPeerFlag = true; + + peer = createNewPeer (styleWanted, nativeWindowToAttachTo); + + Desktop::getInstance().addDesktopComponent (this); + + bounds_.setPosition (x, y); + peer->setBounds (x, y, getWidth(), getHeight(), false); + + peer->setVisible (isVisible()); + + if (wasFullscreen) + { + peer->setFullScreen (true); + peer->setNonFullScreenBounds (oldNonFullScreenBounds); + } + + if (wasMinimised) + peer->setMinimised (true); + + if (isAlwaysOnTop()) + peer->setAlwaysOnTop (true); + + peer->setConstrainer (currentConstainer); + + repaint(); + } + + internalHierarchyChanged(); + } +} + +void Component::removeFromDesktop() +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = ComponentPeer::getPeerFor (this); + + flags.hasHeavyweightPeerFlag = false; + + jassert (peer != 0); + delete peer; + + Desktop::getInstance().removeDesktopComponent (this); + } +} + +bool Component::isOnDesktop() const throw() +{ + return flags.hasHeavyweightPeerFlag; +} + +void Component::userTriedToCloseWindow() +{ + /* This means that the user's trying to get rid of your window with the 'close window' system + menu option (on windows) or possibly the task manager - you should really handle this + and delete or hide your component in an appropriate way. + + If you want to ignore the event and don't want to trigger this assertion, just override + this method and do nothing. + */ + jassertfalse +} + +void Component::minimisationStateChanged (bool) +{ +} + +//============================================================================== +void Component::setOpaque (const bool shouldBeOpaque) throw() +{ + if (shouldBeOpaque != flags.opaqueFlag) + { + flags.opaqueFlag = shouldBeOpaque; + + if (flags.hasHeavyweightPeerFlag) + { + const ComponentPeer* const peer = ComponentPeer::getPeerFor (this); + + if (peer != 0) + { + // to make it recreate the heavyweight window + addToDesktop (peer->getStyleFlags()); + } + } + + repaint(); + } +} + +bool Component::isOpaque() const throw() +{ + return flags.opaqueFlag; +} + +//============================================================================== +void Component::setBufferedToImage (const bool shouldBeBuffered) throw() +{ + if (shouldBeBuffered != flags.bufferToImageFlag) + { + deleteAndZero (bufferedImage_); + flags.bufferToImageFlag = shouldBeBuffered; + } +} + +//============================================================================== +void Component::toFront (const bool setAsForeground) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + peer->toFront (setAsForeground); + + if (setAsForeground && ! hasKeyboardFocus (true)) + grabKeyboardFocus(); + } + } + else if (parentComponent_ != 0) + { + if (parentComponent_->childComponentList_.getLast() != this) + { + const int index = parentComponent_->childComponentList_.indexOf (this); + + if (index >= 0) + { + int insertIndex = -1; + + if (! flags.alwaysOnTopFlag) + { + insertIndex = parentComponent_->childComponentList_.size() - 1; + + while (insertIndex > 0 + && parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) + { + --insertIndex; + } + } + + if (index != insertIndex) + { + parentComponent_->childComponentList_.move (index, insertIndex); + sendFakeMouseMove(); + + repaintParent(); + } + } + } + + if (setAsForeground) + { + internalBroughtToFront(); + grabKeyboardFocus(); + } + } +} + +void Component::toBehind (Component* const other) +{ + if (other != 0) + { + // the two components must belong to the same parent.. + jassert (parentComponent_ == other->parentComponent_); + + if (parentComponent_ != 0) + { + const int index = parentComponent_->childComponentList_.indexOf (this); + int otherIndex = parentComponent_->childComponentList_.indexOf (other); + + if (index >= 0 + && otherIndex >= 0 + && index != otherIndex - 1 + && other != this) + { + if (index < otherIndex) + --otherIndex; + + parentComponent_->childComponentList_.move (index, otherIndex); + + sendFakeMouseMove(); + repaintParent(); + } + } + else if (isOnDesktop()) + { + jassert (other->isOnDesktop()); + + if (other->isOnDesktop()) + { + ComponentPeer* const us = getPeer(); + ComponentPeer* const them = other->getPeer(); + + jassert (us != 0 && them != 0); + if (us != 0 && them != 0) + us->toBehind (them); + } + } + } +} + +void Component::toBack() +{ + if (isOnDesktop()) + { + jassertfalse //xxx need to add this to native window + } + else if (parentComponent_ != 0 + && parentComponent_->childComponentList_.getFirst() != this) + { + const int index = parentComponent_->childComponentList_.indexOf (this); + + if (index > 0) + { + int insertIndex = 0; + + if (flags.alwaysOnTopFlag) + { + while (insertIndex < parentComponent_->childComponentList_.size() + && ! parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) + { + ++insertIndex; + } + } + + if (index != insertIndex) + { + parentComponent_->childComponentList_.move (index, insertIndex); + + sendFakeMouseMove(); + repaintParent(); + } + } + } +} + +void Component::setAlwaysOnTop (const bool shouldStayOnTop) +{ + if (shouldStayOnTop != flags.alwaysOnTopFlag) + { + flags.alwaysOnTopFlag = shouldStayOnTop; + + if (isOnDesktop()) + { + ComponentPeer* const peer = getPeer(); + + jassert (peer != 0); + if (peer != 0) + { + if (! peer->setAlwaysOnTop (shouldStayOnTop)) + { + // some kinds of peer can't change their always-on-top status, so + // for these, we'll need to create a new window + const int oldFlags = peer->getStyleFlags(); + removeFromDesktop(); + addToDesktop (oldFlags); + } + } + } + + if (shouldStayOnTop) + toFront (false); + + internalHierarchyChanged(); + } +} + +bool Component::isAlwaysOnTop() const throw() +{ + return flags.alwaysOnTopFlag; +} + +//============================================================================== +int Component::proportionOfWidth (const float proportion) const throw() +{ + return roundDoubleToInt (proportion * bounds_.getWidth()); +} + +int Component::proportionOfHeight (const float proportion) const throw() +{ + return roundDoubleToInt (proportion * bounds_.getHeight()); +} + +int Component::getParentWidth() const throw() +{ + return (parentComponent_ != 0) ? parentComponent_->getWidth() + : getParentMonitorArea().getWidth(); +} + +int Component::getParentHeight() const throw() +{ + return (parentComponent_ != 0) ? parentComponent_->getHeight() + : getParentMonitorArea().getHeight(); +} + +int Component::getScreenX() const throw() +{ + return (parentComponent_ != 0) ? parentComponent_->getScreenX() + getX() + : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenX() + : getX()); +} + +int Component::getScreenY() const throw() +{ + return (parentComponent_ != 0) ? parentComponent_->getScreenY() + getY() + : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenY() + : getY()); +} + +void Component::relativePositionToGlobal (int& x, int& y) const throw() +{ + const Component* c = this; + + do + { + if (c->flags.hasHeavyweightPeerFlag) + { + c->getPeer()->relativePositionToGlobal (x, y); + break; + } + + x += c->getX(); + y += c->getY(); + c = c->parentComponent_; + } + while (c != 0); +} + +void Component::globalPositionToRelative (int& x, int& y) const throw() +{ + if (flags.hasHeavyweightPeerFlag) + { + getPeer()->globalPositionToRelative (x, y); + } + else + { + if (parentComponent_ != 0) + parentComponent_->globalPositionToRelative (x, y); + + x -= getX(); + y -= getY(); + } +} + +void Component::relativePositionToOtherComponent (const Component* const targetComponent, int& x, int& y) const throw() +{ + if (targetComponent != 0) + { + const Component* c = this; + + do + { + if (c == targetComponent) + return; + + if (c->flags.hasHeavyweightPeerFlag) + { + c->getPeer()->relativePositionToGlobal (x, y); + break; + } + + x += c->getX(); + y += c->getY(); + c = c->parentComponent_; + } + while (c != 0); + + targetComponent->globalPositionToRelative (x, y); + } +} + +//============================================================================== +void Component::setBounds (int x, int y, int w, int h) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (w < 0) w = 0; + if (h < 0) h = 0; + + const bool wasResized = (getWidth() != w || getHeight() != h); + const bool wasMoved = (getX() != x || getY() != y); + +#ifdef JUCE_DEBUG + // It's a very bad idea to try to resize a window during its paint() method! + jassert (! (flags.isInsidePaintCall && wasResized && isOnDesktop())); +#endif + + if (wasMoved || wasResized) + { + if (flags.visibleFlag) + { + // send a fake mouse move to trigger enter/exit messages if needed.. + sendFakeMouseMove(); + + if (! flags.hasHeavyweightPeerFlag) + repaintParent(); + } + + bounds_.setBounds (x, y, w, h); + + if (wasResized) + repaint(); + else if (! flags.hasHeavyweightPeerFlag) + repaintParent(); + + if (flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + if (wasMoved && wasResized) + peer->setBounds (getX(), getY(), getWidth(), getHeight(), false); + else if (wasMoved) + peer->setPosition (getX(), getY()); + else if (wasResized) + peer->setSize (getWidth(), getHeight()); + } + } + + sendMovedResizedMessages (wasMoved, wasResized); + } +} + +void Component::sendMovedResizedMessages (const bool wasMoved, const bool wasResized) +{ + JUCE_TRY + { + if (wasMoved) + moved(); + + if (wasResized) + { + resized(); + + for (int i = childComponentList_.size(); --i >= 0;) + { + childComponentList_.getUnchecked(i)->parentSizeChanged(); + + i = jmin (i, childComponentList_.size()); + } + } + + if (parentComponent_ != 0) + parentComponent_->childBoundsChanged (this); + + if (componentListeners_ != 0) + { + const ComponentDeletionWatcher deletionChecker (this); + + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentMovedOrResized (*this, wasMoved, wasResized); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } + } + JUCE_CATCH_EXCEPTION +} + +void Component::setSize (const int w, const int h) +{ + setBounds (getX(), getY(), w, h); +} + +void Component::setTopLeftPosition (const int x, const int y) +{ + setBounds (x, y, getWidth(), getHeight()); +} + +void Component::setTopRightPosition (const int x, const int y) +{ + setTopLeftPosition (x - getWidth(), y); +} + +void Component::setBounds (const Rectangle& r) +{ + setBounds (r.getX(), + r.getY(), + r.getWidth(), + r.getHeight()); +} + +void Component::setBoundsRelative (const float x, const float y, + const float w, const float h) +{ + const int pw = getParentWidth(); + const int ph = getParentHeight(); + + setBounds (roundFloatToInt (x * pw), + roundFloatToInt (y * ph), + roundFloatToInt (w * pw), + roundFloatToInt (h * ph)); +} + +void Component::setCentrePosition (const int x, const int y) +{ + setTopLeftPosition (x - getWidth() / 2, + y - getHeight() / 2); +} + +void Component::setCentreRelative (const float x, const float y) +{ + setCentrePosition (roundFloatToInt (getParentWidth() * x), + roundFloatToInt (getParentHeight() * y)); +} + +void Component::centreWithSize (const int width, const int height) +{ + setBounds ((getParentWidth() - width) / 2, + (getParentHeight() - height) / 2, + width, + height); +} + +void Component::setBoundsInset (const BorderSize& borders) +{ + setBounds (borders.getLeft(), + borders.getTop(), + getParentWidth() - (borders.getLeftAndRight()), + getParentHeight() - (borders.getTopAndBottom())); +} + +void Component::setBoundsToFit (int x, int y, int width, int height, + const Justification& justification, + const bool onlyReduceInSize) +{ + // it's no good calling this method unless both the component and + // target rectangle have a finite size. + jassert (getWidth() > 0 && getHeight() > 0 && width > 0 && height > 0); + + if (getWidth() > 0 && getHeight() > 0 + && width > 0 && height > 0) + { + int newW, newH; + + if (onlyReduceInSize && getWidth() <= width && getHeight() <= height) + { + newW = getWidth(); + newH = getHeight(); + } + else + { + const double imageRatio = getHeight() / (double) getWidth(); + const double targetRatio = height / (double) width; + + if (imageRatio <= targetRatio) + { + newW = width; + newH = jmin (height, roundDoubleToInt (newW * imageRatio)); + } + else + { + newH = height; + newW = jmin (width, roundDoubleToInt (newH / imageRatio)); + } + } + + if (newW > 0 && newH > 0) + { + int newX, newY; + justification.applyToRectangle (newX, newY, newW, newH, + x, y, width, height); + + setBounds (newX, newY, newW, newH); + } + } +} + +//============================================================================== +bool Component::hitTest (int x, int y) +{ + if (! flags.ignoresMouseClicksFlag) + return true; + + if (flags.allowChildMouseClicksFlag) + { + for (int i = getNumChildComponents(); --i >= 0;) + { + Component* const c = getChildComponent (i); + + if (c->isVisible() + && c->bounds_.contains (x, y) + && c->hitTest (x - c->getX(), + y - c->getY())) + { + return true; + } + } + } + + return false; +} + +void Component::setInterceptsMouseClicks (const bool allowClicks, + const bool allowClicksOnChildComponents) throw() +{ + flags.ignoresMouseClicksFlag = ! allowClicks; + flags.allowChildMouseClicksFlag = allowClicksOnChildComponents; +} + +void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, + bool& allowsClicksOnChildComponents) const throw() +{ + allowsClicksOnThisComponent = ! flags.ignoresMouseClicksFlag; + allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag; +} + +bool Component::contains (const int x, const int y) +{ + if (((unsigned int) x) < (unsigned int) getWidth() + && ((unsigned int) y) < (unsigned int) getHeight() + && hitTest (x, y)) + { + if (parentComponent_ != 0) + { + return parentComponent_->contains (x + getX(), + y + getY()); + } + else if (flags.hasHeavyweightPeerFlag) + { + const ComponentPeer* const peer = getPeer(); + + if (peer != 0) + return peer->contains (x, y, true); + } + } + + return false; +} + +bool Component::reallyContains (int x, int y, const bool returnTrueIfWithinAChild) +{ + if (! contains (x, y)) + return false; + + Component* p = this; + + while (p->parentComponent_ != 0) + { + x += p->getX(); + y += p->getY(); + + p = p->parentComponent_; + } + + const Component* const c = p->getComponentAt (x, y); + + return (c == this) || (returnTrueIfWithinAChild && isParentOf (c)); +} + +Component* Component::getComponentAt (const int x, const int y) +{ + if (flags.visibleFlag + && ((unsigned int) x) < (unsigned int) getWidth() + && ((unsigned int) y) < (unsigned int) getHeight() + && hitTest (x, y)) + { + for (int i = childComponentList_.size(); --i >= 0;) + { + Component* const child = childComponentList_.getUnchecked(i); + + Component* const c = child->getComponentAt (x - child->getX(), + y - child->getY()); + + if (c != 0) + return c; + } + + return this; + } + + return 0; +} + +//============================================================================== +void Component::addChildComponent (Component* const child, int zOrder) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (child != 0 && child->parentComponent_ != this) + { + if (child->parentComponent_ != 0) + child->parentComponent_->removeChildComponent (child); + else + child->removeFromDesktop(); + + child->parentComponent_ = this; + + if (child->isVisible()) + child->repaintParent(); + + if (! child->isAlwaysOnTop()) + { + if (zOrder < 0 || zOrder > childComponentList_.size()) + zOrder = childComponentList_.size(); + + while (zOrder > 0) + { + if (! childComponentList_.getUnchecked (zOrder - 1)->isAlwaysOnTop()) + break; + + --zOrder; + } + } + + childComponentList_.insert (zOrder, child); + + child->internalHierarchyChanged(); + internalChildrenChanged(); + } +} + +void Component::addAndMakeVisible (Component* const child, int zOrder) +{ + if (child != 0) + { + child->setVisible (true); + addChildComponent (child, zOrder); + } +} + +void Component::removeChildComponent (Component* const child) +{ + removeChildComponent (childComponentList_.indexOf (child)); +} + +Component* Component::removeChildComponent (const int index) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + Component* const child = childComponentList_ [index]; + + if (child != 0) + { + sendFakeMouseMove(); + child->repaintParent(); + + childComponentList_.remove (index); + child->parentComponent_ = 0; + + JUCE_TRY + { + if ((currentlyFocusedComponent == child) + || child->isParentOf (currentlyFocusedComponent)) + { + // get rid first to force the grabKeyboardFocus to change to us. + giveAwayFocus(); + grabKeyboardFocus(); + } + } +#if JUCE_CATCH_UNHANDLED_EXCEPTIONS + catch (const std::exception& e) + { + currentlyFocusedComponent = 0; + Desktop::getInstance().triggerFocusCallback(); + JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); + } + catch (...) + { + currentlyFocusedComponent = 0; + Desktop::getInstance().triggerFocusCallback(); + JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); + } +#endif + + child->internalHierarchyChanged(); + internalChildrenChanged(); + } + + return child; +} + +//============================================================================== +void Component::removeAllChildren() +{ + for (int i = childComponentList_.size(); --i >= 0;) + removeChildComponent (i); +} + +void Component::deleteAllChildren() +{ + for (int i = childComponentList_.size(); --i >= 0;) + delete (removeChildComponent (i)); +} + +//============================================================================== +int Component::getNumChildComponents() const throw() +{ + return childComponentList_.size(); +} + +Component* Component::getChildComponent (const int index) const throw() +{ + return childComponentList_ [index]; +} + +int Component::getIndexOfChildComponent (const Component* const child) const throw() +{ + return childComponentList_.indexOf (const_cast (child)); +} + +Component* Component::getTopLevelComponent() const throw() +{ + const Component* comp = this; + + while (comp->parentComponent_ != 0) + comp = comp->parentComponent_; + + return (Component*) comp; +} + +bool Component::isParentOf (const Component* possibleChild) const throw() +{ + while (possibleChild->isValidComponent()) + { + possibleChild = possibleChild->parentComponent_; + + if (possibleChild == this) + return true; + } + + return false; +} + +//============================================================================== +void Component::parentHierarchyChanged() +{ +} + +void Component::childrenChanged() +{ +} + +void Component::internalChildrenChanged() +{ + const ComponentDeletionWatcher deletionChecker (this); + const bool hasListeners = componentListeners_ != 0; + + childrenChanged(); + + if (hasListeners) + { + if (deletionChecker.hasBeenDeleted()) + return; + + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentChildrenChanged (*this); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } +} + +void Component::internalHierarchyChanged() +{ + parentHierarchyChanged(); + + const ComponentDeletionWatcher deletionChecker (this); + + if (componentListeners_ != 0) + { + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentParentHierarchyChanged (*this); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } + + for (int i = childComponentList_.size(); --i >= 0;) + { + childComponentList_.getUnchecked (i)->internalHierarchyChanged(); + + // you really shouldn't delete the parent component during a callback telling you + // that it's changed.. + jassert (! deletionChecker.hasBeenDeleted()); + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, childComponentList_.size()); + } +} + +//============================================================================== +void* Component::runModalLoopCallback (void* userData) +{ + return (void*) (pointer_sized_int) ((Component*) userData)->runModalLoop(); +} + +int Component::runModalLoop() +{ + if (! MessageManager::getInstance()->isThisTheMessageThread()) + { + // use a callback so this can be called from non-gui threads + return (int) (pointer_sized_int) + MessageManager::getInstance() + ->callFunctionOnMessageThread (&runModalLoopCallback, (void*) this); + } + + Component* const prevFocused = getCurrentlyFocusedComponent(); + + ComponentDeletionWatcher* deletionChecker = 0; + if (prevFocused != 0) + deletionChecker = new ComponentDeletionWatcher (prevFocused); + + if (! isCurrentlyModal()) + enterModalState(); + + JUCE_TRY + { + while (flags.currentlyModalFlag && flags.visibleFlag) + { + if (! MessageManager::getInstance()->runDispatchLoopUntil (20)) + break; + + // check whether this component was deleted during the last message + if (! isValidMessageListener()) + break; + } + } +#if JUCE_CATCH_UNHANDLED_EXCEPTIONS + catch (const std::exception& e) + { + JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); + return 0; + } + catch (...) + { + JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); + return 0; + } +#endif + + const int modalIndex = modalComponentReturnValueKeys.indexOf (this); + int returnValue = 0; + + if (modalIndex >= 0) + { + modalComponentReturnValueKeys.remove (modalIndex); + returnValue = modalReturnValues.remove (modalIndex); + } + + modalComponentStack.removeValue (this); + + if (deletionChecker != 0) + { + if (! deletionChecker->hasBeenDeleted()) + prevFocused->grabKeyboardFocus(); + + delete deletionChecker; + } + + return returnValue; +} + +void Component::enterModalState (const bool takeKeyboardFocus) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + // Check for an attempt to make a component modal when it already is! + // This can cause nasty problems.. + jassert (! flags.currentlyModalFlag); + + if (! isCurrentlyModal()) + { + modalComponentStack.add (this); + modalComponentReturnValueKeys.add (this); + modalReturnValues.add (0); + + flags.currentlyModalFlag = true; + setVisible (true); + + if (takeKeyboardFocus) + grabKeyboardFocus(); + } +} + +void Component::exitModalState (const int returnValue) +{ + if (isCurrentlyModal()) + { + if (MessageManager::getInstance()->isThisTheMessageThread()) + { + const int modalIndex = modalComponentReturnValueKeys.indexOf (this); + + if (modalIndex >= 0) + { + modalReturnValues.set (modalIndex, returnValue); + } + else + { + modalComponentReturnValueKeys.add (this); + modalReturnValues.add (returnValue); + } + + modalComponentStack.removeValue (this); + + flags.currentlyModalFlag = false; + } + else + { + postMessage (new Message (exitModalStateMessage, returnValue, 0, 0)); + } + } +} + +bool Component::isCurrentlyModal() const throw() +{ + return flags.currentlyModalFlag + && getCurrentlyModalComponent() == this; +} + +bool Component::isCurrentlyBlockedByAnotherModalComponent() const throw() +{ + Component* const mc = getCurrentlyModalComponent(); + + return mc != 0 + && mc != this + && (! mc->isParentOf (this)) + && ! mc->canModalEventBeSentToComponent (this); +} + +Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent() throw() +{ + Component* const c = (Component*) modalComponentStack.getLast(); + + return c->isValidComponent() ? c : 0; +} + +//============================================================================== +void Component::setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) throw() +{ + flags.bringToFrontOnClickFlag = shouldBeBroughtToFront; +} + +bool Component::isBroughtToFrontOnMouseClick() const throw() +{ + return flags.bringToFrontOnClickFlag; +} + +//============================================================================== +void Component::setMouseCursor (const MouseCursor& cursor) throw() +{ + cursor_ = cursor; + + if (flags.visibleFlag) + { + int mx, my; + getMouseXYRelative (mx, my); + + if (flags.draggingFlag || reallyContains (mx, my, false)) + { + internalUpdateMouseCursor (false); + } + } +} + +const MouseCursor Component::getMouseCursor() +{ + return cursor_; +} + +void Component::updateMouseCursor() const throw() +{ + sendFakeMouseMove(); +} + +void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() +{ + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + MouseCursor mc (getMouseCursor()); + + if (isUnboundedMouseModeOn && (unboundedMouseOffsetX != 0 + || unboundedMouseOffsetY != 0 + || ! isCursorVisibleUntilOffscreen)) + { + mc = MouseCursor::NoCursor; + } + + static void* currentCursorHandle = 0; + + if (forcedUpdate || mc.getHandle() != currentCursorHandle) + { + currentCursorHandle = mc.getHandle(); + mc.showInWindow (peer); + } + } +} + +//============================================================================== +void Component::setRepaintsOnMouseActivity (const bool shouldRepaint) throw() +{ + flags.repaintOnMouseActivityFlag = shouldRepaint; +} + +//============================================================================== +void Component::repaintParent() throw() +{ + if (flags.visibleFlag) + internalRepaint (0, 0, getWidth(), getHeight()); +} + +void Component::repaint() throw() +{ + repaint (0, 0, getWidth(), getHeight()); +} + +void Component::repaint (const int x, const int y, + const int w, const int h) throw() +{ + deleteAndZero (bufferedImage_); + + if (flags.visibleFlag) + internalRepaint (x, y, w, h); +} + +void Component::internalRepaint (int x, int y, int w, int h) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (x < 0) + { + w += x; + x = 0; + } + + if (x + w > getWidth()) + w = getWidth() - x; + + if (w > 0) + { + if (y < 0) + { + h += y; + y = 0; + } + + if (y + h > getHeight()) + h = getHeight() - y; + + if (h > 0) + { + if (parentComponent_ != 0) + { + x += getX(); + y += getY(); + + if (parentComponent_->flags.visibleFlag) + parentComponent_->internalRepaint (x, y, w, h); + } + else if (flags.hasHeavyweightPeerFlag) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + peer->repaint (x, y, w, h); + } + } + } +} + +//============================================================================== +void Component::paintEntireComponent (Graphics& originalContext) +{ + jassert (! originalContext.isClipEmpty()); + +#ifdef JUCE_DEBUG + flags.isInsidePaintCall = true; +#endif + + Graphics* g = &originalContext; + Image* effectImage = 0; + + if (effect_ != 0) + { + effectImage = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, + getWidth(), getHeight(), + ! flags.opaqueFlag); + + g = new Graphics (*effectImage); + } + + g->saveState(); + clipObscuredRegions (*g, g->getClipBounds(), 0, 0); + + if (! g->isClipEmpty()) + { + if (bufferedImage_ != 0) + { + g->setColour (Colours::black); + g->drawImageAt (bufferedImage_, 0, 0); + } + else + { + if (flags.bufferToImageFlag) + { + if (bufferedImage_ == 0) + { + bufferedImage_ = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, + getWidth(), getHeight(), ! flags.opaqueFlag); + + Graphics imG (*bufferedImage_); + paint (imG); + } + + g->setColour (Colours::black); + g->drawImageAt (bufferedImage_, 0, 0); + } + else + { + paint (*g); + g->resetToDefaultState(); + } + } + } + + g->restoreState(); + + for (int i = 0; i < childComponentList_.size(); ++i) + { + Component* const child = childComponentList_.getUnchecked (i); + + if (child->isVisible()) + { + g->saveState(); + + if (g->reduceClipRegion (child->getX(), child->getY(), + child->getWidth(), child->getHeight())) + { + for (int j = i + 1; j < childComponentList_.size(); ++j) + { + const Component* const sibling = childComponentList_.getUnchecked (j); + + if (sibling->flags.opaqueFlag && sibling->isVisible()) + g->excludeClipRegion (sibling->getX(), sibling->getY(), + sibling->getWidth(), sibling->getHeight()); + } + + if (! g->isClipEmpty()) + { + g->setOrigin (child->getX(), child->getY()); + + child->paintEntireComponent (*g); + } + } + + g->restoreState(); + } + } + + JUCE_TRY + { + g->saveState(); + paintOverChildren (*g); + g->restoreState(); + } + JUCE_CATCH_EXCEPTION + + if (effect_ != 0) + { + delete g; + + effect_->applyEffect (*effectImage, originalContext); + delete effectImage; + } + +#ifdef JUCE_DEBUG + flags.isInsidePaintCall = false; +#endif +} + +//============================================================================== +Image* Component::createComponentSnapshot (const Rectangle& areaToGrab, + const bool clipImageToComponentBounds) +{ + Rectangle r (areaToGrab); + + if (clipImageToComponentBounds) + r = r.getIntersection (Rectangle (0, 0, getWidth(), getHeight())); + + Image* const componentImage = new Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, + jmax (1, r.getWidth()), + jmax (1, r.getHeight()), + true); + + Graphics imageContext (*componentImage); + imageContext.setOrigin (-r.getX(), + -r.getY()); + + paintEntireComponent (imageContext); + + return componentImage; +} + +void Component::setComponentEffect (ImageEffectFilter* const effect) +{ + if (effect_ != effect) + { + effect_ = effect; + repaint(); + } +} + +//============================================================================== +LookAndFeel& Component::getLookAndFeel() const throw() +{ + const Component* c = this; + + do + { + if (c->lookAndFeel_ != 0) + return *(c->lookAndFeel_); + + c = c->parentComponent_; + } + while (c != 0); + + return LookAndFeel::getDefaultLookAndFeel(); +} + +void Component::setLookAndFeel (LookAndFeel* const newLookAndFeel) +{ + if (lookAndFeel_ != newLookAndFeel) + { + lookAndFeel_ = newLookAndFeel; + + sendLookAndFeelChange(); + } +} + +void Component::lookAndFeelChanged() +{ +} + +void Component::sendLookAndFeelChange() +{ + repaint(); + + lookAndFeelChanged(); + + // (it's not a great idea to do anything that would delete this component + // during the lookAndFeelChanged() callback) + jassert (isValidComponent()); + + const ComponentDeletionWatcher deletionChecker (this); + + for (int i = childComponentList_.size(); --i >= 0;) + { + childComponentList_.getUnchecked (i)->sendLookAndFeelChange(); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, childComponentList_.size()); + } +} + +static const String getColourPropertyName (const int colourId) throw() +{ + String s; + s.preallocateStorage (18); + s << T("jcclr_") << colourId; + return s; +} + +const Colour Component::findColour (const int colourId, const bool inheritFromParent) const throw() +{ + const String customColour (getComponentProperty (getColourPropertyName (colourId), + inheritFromParent, + String::empty)); + + if (customColour.isNotEmpty()) + return Colour (customColour.getIntValue()); + + return getLookAndFeel().findColour (colourId); +} + +bool Component::isColourSpecified (const int colourId) const throw() +{ + return getComponentProperty (getColourPropertyName (colourId), + false, + String::empty).isNotEmpty(); +} + +void Component::removeColour (const int colourId) +{ + if (isColourSpecified (colourId)) + { + removeComponentProperty (getColourPropertyName (colourId)); + colourChanged(); + } +} + +void Component::setColour (const int colourId, const Colour& colour) +{ + const String colourName (getColourPropertyName (colourId)); + const String customColour (getComponentProperty (colourName, false, String::empty)); + + if (customColour.isEmpty() || Colour (customColour.getIntValue()) != colour) + { + setComponentProperty (colourName, colour); + colourChanged(); + } +} + +void Component::copyAllExplicitColoursTo (Component& target) const throw() +{ + if (propertySet_ != 0) + { + const StringPairArray& props = propertySet_->getAllProperties(); + const StringArray& keys = props.getAllKeys(); + + for (int i = 0; i < keys.size(); ++i) + { + if (keys[i].startsWith (T("jcclr_"))) + { + target.setComponentProperty (keys[i], + props.getAllValues() [i]); + } + } + + target.colourChanged(); + } +} + +void Component::colourChanged() +{ +} + +//============================================================================== +const Rectangle Component::getUnclippedArea() const +{ + int x = 0, y = 0, w = getWidth(), h = getHeight(); + + Component* p = parentComponent_; + int px = getX(); + int py = getY(); + + while (p != 0) + { + if (! Rectangle::intersectRectangles (x, y, w, h, -px, -py, p->getWidth(), p->getHeight())) + return Rectangle(); + + px += p->getX(); + py += p->getY(); + p = p->parentComponent_; + } + + return Rectangle (x, y, w, h); +} + +void Component::clipObscuredRegions (Graphics& g, const Rectangle& clipRect, + const int deltaX, const int deltaY) const throw() +{ + for (int i = childComponentList_.size(); --i >= 0;) + { + const Component* const c = childComponentList_.getUnchecked(i); + + if (c->isVisible()) + { + Rectangle newClip (clipRect.getIntersection (c->bounds_)); + + if (! newClip.isEmpty()) + { + if (c->isOpaque()) + { + g.excludeClipRegion (deltaX + newClip.getX(), + deltaY + newClip.getY(), + newClip.getWidth(), + newClip.getHeight()); + } + else + { + newClip.translate (-c->getX(), -c->getY()); + c->clipObscuredRegions (g, newClip, + c->getX() + deltaX, + c->getY() + deltaY); + } + } + } + } +} + +void Component::getVisibleArea (RectangleList& result, + const bool includeSiblings) const +{ + result.clear(); + const Rectangle unclipped (getUnclippedArea()); + + if (! unclipped.isEmpty()) + { + result.add (unclipped); + + if (includeSiblings) + { + const Component* const c = getTopLevelComponent(); + + int x = 0, y = 0; + c->relativePositionToOtherComponent (this, x, y); + + c->subtractObscuredRegions (result, x, y, + Rectangle (0, 0, c->getWidth(), c->getHeight()), + this); + } + + subtractObscuredRegions (result, 0, 0, unclipped, 0); + result.consolidate(); + } +} + +void Component::subtractObscuredRegions (RectangleList& result, + const int deltaX, + const int deltaY, + const Rectangle& clipRect, + const Component* const compToAvoid) const throw() +{ + for (int i = childComponentList_.size(); --i >= 0;) + { + const Component* const c = childComponentList_.getUnchecked(i); + + if (c != compToAvoid && c->isVisible()) + { + if (c->isOpaque()) + { + Rectangle childBounds (c->bounds_.getIntersection (clipRect)); + childBounds.translate (deltaX, deltaY); + + result.subtract (childBounds); + } + else + { + Rectangle newClip (clipRect.getIntersection (c->bounds_)); + newClip.translate (-c->getX(), -c->getY()); + + c->subtractObscuredRegions (result, + c->getX() + deltaX, + c->getY() + deltaY, + newClip, + compToAvoid); + } + } + } +} + +//============================================================================== +void Component::mouseEnter (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseExit (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseDown (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseUp (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseDrag (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseMove (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseDoubleClick (const MouseEvent&) +{ + // base class does nothing +} + +void Component::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) +{ + // the base class just passes this event up to its parent.. + + if (parentComponent_ != 0) + parentComponent_->mouseWheelMove (e.getEventRelativeTo (parentComponent_), + wheelIncrementX, wheelIncrementY); +} + + +//============================================================================== +void Component::resized() +{ + // base class does nothing +} + +void Component::moved() +{ + // base class does nothing +} + +void Component::childBoundsChanged (Component*) +{ + // base class does nothing +} + +void Component::parentSizeChanged() +{ + // base class does nothing +} + +void Component::addComponentListener (ComponentListener* const newListener) throw() +{ + if (componentListeners_ == 0) + componentListeners_ = new VoidArray (4); + + componentListeners_->addIfNotAlreadyThere (newListener); +} + +void Component::removeComponentListener (ComponentListener* const listenerToRemove) throw() +{ + jassert (isValidComponent()); + + if (componentListeners_ != 0) + componentListeners_->removeValue (listenerToRemove); +} + +//============================================================================== +void Component::inputAttemptWhenModal() +{ + getTopLevelComponent()->toFront (true); + + getLookAndFeel().playAlertSound(); +} + +bool Component::canModalEventBeSentToComponent (const Component*) +{ + return false; +} + +void Component::internalModalInputAttempt() +{ + Component* const current = getCurrentlyModalComponent(); + + if (current != 0) + current->inputAttemptWhenModal(); +} + + +//============================================================================== +void Component::paint (Graphics&) +{ + // all painting is done in the subclasses + + jassert (! isOpaque()); // if your component's opaque, you've gotta paint it! +} + +void Component::paintOverChildren (Graphics&) +{ + // all painting is done in the subclasses +} + +//============================================================================== +void Component::handleMessage (const Message& message) +{ + if (message.intParameter1 == exitModalStateMessage) + { + exitModalState (message.intParameter2); + } + else if (message.intParameter1 == customCommandMessage) + { + handleCommandMessage (message.intParameter2); + } +} + +//============================================================================== +void Component::postCommandMessage (const int commandId) throw() +{ + postMessage (new Message (customCommandMessage, commandId, 0, 0)); +} + +void Component::handleCommandMessage (int) +{ + // used by subclasses +} + +//============================================================================== +void Component::addMouseListener (MouseListener* const newListener, + const bool wantsEventsForAllNestedChildComponents) throw() +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (mouseListeners_ == 0) + mouseListeners_ = new VoidArray (4); + + if (! mouseListeners_->contains (newListener)) + { + if (wantsEventsForAllNestedChildComponents) + { + mouseListeners_->insert (0, newListener); + ++numDeepMouseListeners; + } + else + { + mouseListeners_->add (newListener); + } + } +} + +void Component::removeMouseListener (MouseListener* const listenerToRemove) throw() +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (mouseListeners_ != 0) + { + const int index = mouseListeners_->indexOf (listenerToRemove); + + if (index >= 0) + { + if (index < numDeepMouseListeners) + --numDeepMouseListeners; + + mouseListeners_->remove (index); + } + } +} + +//============================================================================== +void Component::internalMouseEnter (int x, int y, int64 time) +{ + if (isCurrentlyBlockedByAnotherModalComponent()) + { + // if something else is modal, always just show a normal mouse cursor + if (componentUnderMouse == this) + { + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + MouseCursor mc (MouseCursor::NormalCursor); + mc.showInWindow (peer); + } + } + + return; + } + + if (! flags.mouseInsideFlag) + { + flags.mouseInsideFlag = true; + flags.mouseOverFlag = true; + flags.draggingFlag = false; + + if (isValidComponent()) + { + const ComponentDeletionWatcher deletionChecker (this); + + if (flags.repaintOnMouseActivityFlag) + repaint(); + + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (time), + x, y, + Time (time), + 0, false); + + mouseEnter (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseEnter (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked(i))->mouseEnter (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked(i)))->mouseEnter (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } + } + + if (componentUnderMouse == this) + internalUpdateMouseCursor (true); +} + +void Component::internalMouseExit (int x, int y, int64 time) +{ + const ComponentDeletionWatcher deletionChecker (this); + + if (flags.draggingFlag) + { + internalMouseUp (ModifierKeys::getCurrentModifiers().getRawFlags(), x, y, time); + + if (deletionChecker.hasBeenDeleted()) + return; + } + + enableUnboundedMouseMovement (false); + + if (flags.mouseInsideFlag || flags.mouseOverFlag) + { + flags.mouseInsideFlag = false; + flags.mouseOverFlag = false; + flags.draggingFlag = false; + + if (flags.repaintOnMouseActivityFlag) + repaint(); + + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (time), + x, y, + Time (time), + 0, false); + mouseExit (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseExit (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseExit (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseExit (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } +} + +//============================================================================== +class InternalDragRepeater : public Timer +{ +public: + InternalDragRepeater() + {} + + ~InternalDragRepeater() + {} + + void timerCallback() + { + Component* const c = Component::getComponentUnderMouse(); + + if (c != 0 && c->isMouseButtonDown()) + { + int x, y; + c->getMouseXYRelative (x, y); + + // the offsets have been added on, so must be taken off before calling the + // drag.. otherwise they'll be added twice + x -= unboundedMouseOffsetX; + y -= unboundedMouseOffsetY; + + c->internalMouseDrag (x, y, Time::currentTimeMillis()); + } + } + + juce_UseDebuggingNewOperator +}; + +static InternalDragRepeater* dragRepeater = 0; + +void Component::beginDragAutoRepeat (const int interval) +{ + if (interval > 0) + { + if (dragRepeater == 0) + dragRepeater = new InternalDragRepeater(); + + if (dragRepeater->getTimerInterval() != interval) + dragRepeater->startTimer (interval); + } + else + { + deleteAndZero (dragRepeater); + } +} + +//============================================================================== +void Component::internalMouseDown (const int x, const int y) +{ + const ComponentDeletionWatcher deletionChecker (this); + + if (isCurrentlyBlockedByAnotherModalComponent()) + { + internalModalInputAttempt(); + + if (deletionChecker.hasBeenDeleted()) + return; + + // If processing the input attempt has exited the modal loop, we'll allow the event + // to be delivered.. + if (isCurrentlyBlockedByAnotherModalComponent()) + { + // allow blocked mouse-events to go to global listeners.. + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (juce_recentMouseDownTimes[0]), + x, y, + Time (juce_recentMouseDownTimes[0]), + countMouseClicks(), + false); + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + return; + } + } + + { + Component* c = this; + + while (c != 0) + { + if (c->isBroughtToFrontOnMouseClick()) + { + c->toFront (true); + + if (deletionChecker.hasBeenDeleted()) + return; + } + + c = c->parentComponent_; + } + } + + if (! flags.dontFocusOnMouseClickFlag) + grabFocusInternal (focusChangedByMouseClick); + + if (! deletionChecker.hasBeenDeleted()) + { + flags.draggingFlag = true; + flags.mouseOverFlag = true; + + if (flags.repaintOnMouseActivityFlag) + repaint(); + + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (juce_recentMouseDownTimes[0]), + x, y, + Time (juce_recentMouseDownTimes[0]), + countMouseClicks(), + false); + mouseDown (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDown (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDown (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } +} + +//============================================================================== +void Component::internalMouseUp (const int oldModifiers, int x, int y, const int64 time) +{ + if (isValidComponent() && flags.draggingFlag) + { + flags.draggingFlag = false; + deleteAndZero (dragRepeater); + + x += unboundedMouseOffsetX; + y += unboundedMouseOffsetY; + juce_LastMousePosX = x; + juce_LastMousePosY = y; + relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY); + + const ComponentDeletionWatcher deletionChecker (this); + + if (flags.repaintOnMouseActivityFlag) + repaint(); + + int mdx = juce_recentMouseDownX[0]; + int mdy = juce_recentMouseDownY[0]; + globalPositionToRelative (mdx, mdy); + + const MouseEvent me (x, y, + oldModifiers, + this, + Time (time), + mdx, mdy, + Time (juce_recentMouseDownTimes [0]), + countMouseClicks(), + juce_MouseHasMovedSignificantlySincePressed + || juce_recentMouseDownTimes[0] + 300 < time); + + mouseUp (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseUp (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseUp (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + { + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseUp (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } + + // check for double-click + if (me.getNumberOfClicks() >= 2) + { + const int numListeners = (mouseListeners_ != 0) ? mouseListeners_->size() : 0; + + mouseDoubleClick (me); + + int i; + for (i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDoubleClick (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + for (i = numListeners; --i >= 0;) + { + if (deletionChecker.hasBeenDeleted() || mouseListeners_ == 0) + return; + + MouseListener* const ml = (MouseListener*)((*mouseListeners_)[i]); + if (ml != 0) + ml->mouseDoubleClick (me); + } + + if (deletionChecker.hasBeenDeleted()) + return; + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDoubleClick (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } + } + + enableUnboundedMouseMovement (false); +} + +void Component::internalMouseDrag (int x, int y, const int64 time) +{ + if (isValidComponent() && flags.draggingFlag) + { + flags.mouseOverFlag = reallyContains (x, y, false); + + x += unboundedMouseOffsetX; + y += unboundedMouseOffsetY; + juce_LastMousePosX = x; + juce_LastMousePosY = y; + relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY); + + juce_MouseHasMovedSignificantlySincePressed + = juce_MouseHasMovedSignificantlySincePressed + || abs (juce_recentMouseDownX[0] - juce_LastMousePosX) >= 4 + || abs (juce_recentMouseDownY[0] - juce_LastMousePosY) >= 4; + + const ComponentDeletionWatcher deletionChecker (this); + + int mdx = juce_recentMouseDownX[0]; + int mdy = juce_recentMouseDownY[0]; + globalPositionToRelative (mdx, mdy); + + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (time), + mdx, mdy, + Time (juce_recentMouseDownTimes[0]), + countMouseClicks(), + juce_MouseHasMovedSignificantlySincePressed + || juce_recentMouseDownTimes[0] + 300 < time); + + mouseDrag (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDrag (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDrag (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDrag (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + + if (this == componentUnderMouse) + { + if (isUnboundedMouseModeOn) + { + Rectangle screenArea (getParentMonitorArea().expanded (-2, -2)); + + int mx, my; + Desktop::getMousePosition (mx, my); + + if (! screenArea.contains (mx, my)) + { + int deltaX = 0, deltaY = 0; + + if (mx <= screenArea.getX() || mx >= screenArea.getRight()) + deltaX = getScreenX() + getWidth() / 2 - mx; + + if (my <= screenArea.getY() || my >= screenArea.getBottom()) + deltaY = getScreenY() + getHeight() / 2 - my; + + unboundedMouseOffsetX -= deltaX; + unboundedMouseOffsetY -= deltaY; + + Desktop::setMousePosition (mx + deltaX, + my + deltaY); + } + else if (isCursorVisibleUntilOffscreen + && (unboundedMouseOffsetX != 0 || unboundedMouseOffsetY != 0) + && screenArea.contains (mx + unboundedMouseOffsetX, + my + unboundedMouseOffsetY)) + { + mx += unboundedMouseOffsetX; + my += unboundedMouseOffsetY; + unboundedMouseOffsetX = 0; + unboundedMouseOffsetY = 0; + + Desktop::setMousePosition (mx, my); + } + } + + internalUpdateMouseCursor (false); + } + } +} + +void Component::internalMouseMove (const int x, const int y, const int64 time) +{ + const ComponentDeletionWatcher deletionChecker (this); + + if (isValidComponent()) + { + const MouseEvent me (x, y, + ModifierKeys::getCurrentModifiers(), + this, + Time (time), + x, y, + Time (time), + 0, false); + + if (isCurrentlyBlockedByAnotherModalComponent()) + { + // allow blocked mouse-events to go to global listeners.. + Desktop::getInstance().sendMouseMove(); + } + else + { + if (this == componentUnderMouse) + internalUpdateMouseCursor (false); + + flags.mouseOverFlag = true; + + mouseMove (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + Desktop::getInstance().resetTimer(); + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseMove (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseMove (me); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseMove (me); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + } + } +} + +void Component::internalMouseWheel (const int intAmountX, const int intAmountY, const int64 time) +{ + const ComponentDeletionWatcher deletionChecker (this); + + const float wheelIncrementX = intAmountX * (1.0f / 256.0f); + const float wheelIncrementY = intAmountY * (1.0f / 256.0f); + + int mx, my; + getMouseXYRelative (mx, my); + + const MouseEvent me (mx, my, + ModifierKeys::getCurrentModifiers(), + this, + Time (time), + mx, my, + Time (time), + 0, false); + + if (isCurrentlyBlockedByAnotherModalComponent()) + { + // allow blocked mouse-events to go to global listeners.. + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + } + else + { + mouseWheelMove (me, wheelIncrementX, wheelIncrementY); + + if (deletionChecker.hasBeenDeleted()) + return; + + for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;) + { + ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, Desktop::getInstance().mouseListeners.size()); + } + + if (mouseListeners_ != 0) + { + for (int i = mouseListeners_->size(); --i >= 0;) + { + ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, mouseListeners_->size()); + } + } + + const Component* p = parentComponent_; + + while (p != 0) + { + const ComponentDeletionWatcher parentDeletionChecker (p); + + for (int i = p->numDeepMouseListeners; --i >= 0;) + { + ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY); + + if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, p->numDeepMouseListeners); + } + + p = p->parentComponent_; + } + + sendFakeMouseMove(); + } +} + +void Component::sendFakeMouseMove() const +{ + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + peer->sendFakeMouseMove(); +} + +void Component::broughtToFront() +{ +} + +void Component::internalBroughtToFront() +{ + if (isValidComponent()) + { + if (flags.hasHeavyweightPeerFlag) + Desktop::getInstance().componentBroughtToFront (this); + + const ComponentDeletionWatcher deletionChecker (this); + broughtToFront(); + + if (deletionChecker.hasBeenDeleted()) + return; + + if (componentListeners_ != 0) + { + for (int i = componentListeners_->size(); --i >= 0;) + { + ((ComponentListener*) componentListeners_->getUnchecked (i)) + ->componentBroughtToFront (*this); + + if (deletionChecker.hasBeenDeleted()) + return; + + i = jmin (i, componentListeners_->size()); + } + } + + // when brought to the front and there's a modal component blocking this one, + // we need to bring the modal one to the front instead.. + + Component* const cm = getCurrentlyModalComponent(); + + if (cm != 0 && cm->getTopLevelComponent() != getTopLevelComponent()) + { + cm->getTopLevelComponent()->toFront (true); + } + } +} + +void Component::focusGained (FocusChangeType) +{ + // base class does nothing +} + +void Component::internalFocusGain (const FocusChangeType cause) +{ + const ComponentDeletionWatcher deletionChecker (this); + + focusGained (cause); + + if (! deletionChecker.hasBeenDeleted()) + internalChildFocusChange (cause); +} + +void Component::focusLost (FocusChangeType) +{ + // base class does nothing +} + +void Component::internalFocusLoss (const FocusChangeType cause) +{ + const ComponentDeletionWatcher deletionChecker (this); + + focusLost (focusChangedDirectly); + + if (! deletionChecker.hasBeenDeleted()) + internalChildFocusChange (cause); +} + +void Component::focusOfChildComponentChanged (FocusChangeType /*cause*/) +{ + // base class does nothing +} + +void Component::internalChildFocusChange (FocusChangeType cause) +{ + const bool childIsNowFocused = hasKeyboardFocus (true); + + if (flags.childCompFocusedFlag != childIsNowFocused) + { + flags.childCompFocusedFlag = childIsNowFocused; + + const ComponentDeletionWatcher deletionChecker (this); + focusOfChildComponentChanged (cause); + + if (deletionChecker.hasBeenDeleted()) + return; + } + + if (parentComponent_ != 0) + parentComponent_->internalChildFocusChange (cause); +} + +//============================================================================== +bool Component::isEnabled() const throw() +{ + return (! flags.isDisabledFlag) + && (parentComponent_ == 0 || parentComponent_->isEnabled()); +} + +void Component::setEnabled (const bool shouldBeEnabled) +{ + if (flags.isDisabledFlag == shouldBeEnabled) + { + flags.isDisabledFlag = ! shouldBeEnabled; + + // if any parent components are disabled, setting our flag won't make a difference, + // so no need to send a change message + if (parentComponent_ == 0 || parentComponent_->isEnabled()) + sendEnablementChangeMessage(); + } +} + +void Component::sendEnablementChangeMessage() +{ + const ComponentDeletionWatcher deletionChecker (this); + + enablementChanged(); + + if (deletionChecker.hasBeenDeleted()) + return; + + for (int i = getNumChildComponents(); --i >= 0;) + { + Component* const c = getChildComponent (i); + + if (c != 0) + { + c->sendEnablementChangeMessage(); + + if (deletionChecker.hasBeenDeleted()) + return; + } + } +} + +void Component::enablementChanged() +{ +} + +//============================================================================== +void Component::setWantsKeyboardFocus (const bool wantsFocus) throw() +{ + flags.wantsFocusFlag = wantsFocus; +} + +void Component::setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus) +{ + flags.dontFocusOnMouseClickFlag = ! shouldGrabFocus; +} + +bool Component::getMouseClickGrabsKeyboardFocus() const throw() +{ + return ! flags.dontFocusOnMouseClickFlag; +} + +bool Component::getWantsKeyboardFocus() const throw() +{ + return flags.wantsFocusFlag && ! flags.isDisabledFlag; +} + +void Component::setFocusContainer (const bool isFocusContainer) throw() +{ + flags.isFocusContainerFlag = isFocusContainer; +} + +bool Component::isFocusContainer() const throw() +{ + return flags.isFocusContainerFlag; +} + +int Component::getExplicitFocusOrder() const throw() +{ + return getComponentPropertyInt (T("_jexfo"), false, 0); +} + +void Component::setExplicitFocusOrder (const int newFocusOrderIndex) throw() +{ + setComponentProperty (T("_jexfo"), newFocusOrderIndex); +} + +KeyboardFocusTraverser* Component::createFocusTraverser() +{ + if (flags.isFocusContainerFlag || parentComponent_ == 0) + return new KeyboardFocusTraverser(); + + return parentComponent_->createFocusTraverser(); +} + +void Component::takeKeyboardFocus (const FocusChangeType cause) +{ + // give the focus to this component + if (currentlyFocusedComponent != this) + { + JUCE_TRY + { + // get the focus onto our desktop window + ComponentPeer* const peer = getPeer(); + + if (peer != 0) + { + const ComponentDeletionWatcher deletionChecker (this); + + peer->grabFocus(); + + if (peer->isFocused() && currentlyFocusedComponent != this) + { + Component* const componentLosingFocus = currentlyFocusedComponent; + + currentlyFocusedComponent = this; + + Desktop::getInstance().triggerFocusCallback(); + + // call this after setting currentlyFocusedComponent so that the one that's + // losing it has a chance to see where focus is going + if (componentLosingFocus->isValidComponent()) + componentLosingFocus->internalFocusLoss (cause); + + if (currentlyFocusedComponent == this) + { + focusGained (cause); + + if (! deletionChecker.hasBeenDeleted()) + internalChildFocusChange (cause); + } + } + } + } +#if JUCE_CATCH_UNHANDLED_EXCEPTIONS + catch (const std::exception& e) + { + currentlyFocusedComponent = 0; + Desktop::getInstance().triggerFocusCallback(); + JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); + } + catch (...) + { + currentlyFocusedComponent = 0; + Desktop::getInstance().triggerFocusCallback(); + JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); + } +#endif + } +} + +void Component::grabFocusInternal (const FocusChangeType cause, const bool canTryParent) +{ + if (isShowing()) + { + if (flags.wantsFocusFlag && (isEnabled() || parentComponent_ == 0)) + { + takeKeyboardFocus (cause); + } + else + { + if (isParentOf (currentlyFocusedComponent) + && currentlyFocusedComponent->isShowing()) + { + // do nothing if the focused component is actually a child of ours.. + } + else + { + // find the default child component.. + KeyboardFocusTraverser* const traverser = createFocusTraverser(); + + if (traverser != 0) + { + Component* const defaultComp = traverser->getDefaultComponent (this); + delete traverser; + + if (defaultComp != 0) + { + defaultComp->grabFocusInternal (cause, false); + return; + } + } + + if (canTryParent && parentComponent_ != 0) + { + // if no children want it and we're allowed to try our parent comp, + // then pass up to parent, which will try our siblings. + parentComponent_->grabFocusInternal (cause, true); + } + } + } + } +} + +void Component::grabKeyboardFocus() +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + grabFocusInternal (focusChangedDirectly); +} + +void Component::moveKeyboardFocusToSibling (const bool moveToNext) +{ + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + checkMessageManagerIsLocked + + if (parentComponent_ != 0) + { + KeyboardFocusTraverser* const traverser = createFocusTraverser(); + + if (traverser != 0) + { + Component* const nextComp = moveToNext ? traverser->getNextComponent (this) + : traverser->getPreviousComponent (this); + delete traverser; + + if (nextComp != 0) + { + if (nextComp->isCurrentlyBlockedByAnotherModalComponent()) + { + const ComponentDeletionWatcher deletionChecker (nextComp); + internalModalInputAttempt(); + + if (deletionChecker.hasBeenDeleted() + || nextComp->isCurrentlyBlockedByAnotherModalComponent()) + return; + } + + nextComp->grabFocusInternal (focusChangedByTabKey); + return; + } + } + + parentComponent_->moveKeyboardFocusToSibling (moveToNext); + } +} + +bool Component::hasKeyboardFocus (const bool trueIfChildIsFocused) const throw() +{ + return (currentlyFocusedComponent == this) + || (trueIfChildIsFocused && isParentOf (currentlyFocusedComponent)); +} + +Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw() +{ + return currentlyFocusedComponent; +} + +void Component::giveAwayFocus() +{ + // use a copy so we can clear the value before the call + Component* const componentLosingFocus = currentlyFocusedComponent; + currentlyFocusedComponent = 0; + Desktop::getInstance().triggerFocusCallback(); + + if (componentLosingFocus->isValidComponent()) + componentLosingFocus->internalFocusLoss (focusChangedDirectly); +} + +//============================================================================== +bool Component::isMouseOver() const throw() +{ + return flags.mouseOverFlag; +} + +bool Component::isMouseButtonDown() const throw() +{ + return flags.draggingFlag; +} + +bool Component::isMouseOverOrDragging() const throw() +{ + return flags.mouseOverFlag || flags.draggingFlag; +} + +bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw() +{ + return ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(); +} + +void Component::getMouseXYRelative (int& mx, int& my) const throw() +{ + Desktop::getMousePosition (mx, my); + globalPositionToRelative (mx, my); + + mx += unboundedMouseOffsetX; + my += unboundedMouseOffsetY; +} + +void Component::enableUnboundedMouseMovement (bool enable, + bool keepCursorVisibleUntilOffscreen) throw() +{ + enable = enable && isMouseButtonDown(); + isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen; + + if (enable != isUnboundedMouseModeOn) + { + if ((! enable) && ((! isCursorVisibleUntilOffscreen) + || unboundedMouseOffsetX != 0 + || unboundedMouseOffsetY != 0)) + { + // when released, return the mouse to within the component's bounds + + int mx, my; + getMouseXYRelative (mx, my); + + mx = jlimit (0, getWidth(), mx); + my = jlimit (0, getHeight(), my); + + relativePositionToGlobal (mx, my); + + Desktop::setMousePosition (mx, my); + } + + isUnboundedMouseModeOn = enable; + unboundedMouseOffsetX = 0; + unboundedMouseOffsetY = 0; + + internalUpdateMouseCursor (true); + } +} + +Component* JUCE_CALLTYPE Component::getComponentUnderMouse() throw() +{ + return componentUnderMouse; +} + +//============================================================================== +const Rectangle Component::getParentMonitorArea() const throw() +{ + int centreX = getWidth() / 2; + int centreY = getHeight() / 2; + relativePositionToGlobal (centreX, centreY); + + return Desktop::getInstance().getMonitorAreaContaining (centreX, centreY); +} + +//============================================================================== +void Component::addKeyListener (KeyListener* const newListener) throw() +{ + if (keyListeners_ == 0) + keyListeners_ = new VoidArray (4); + + keyListeners_->addIfNotAlreadyThere (newListener); +} + +void Component::removeKeyListener (KeyListener* const listenerToRemove) throw() +{ + if (keyListeners_ != 0) + keyListeners_->removeValue (listenerToRemove); +} + +bool Component::keyPressed (const KeyPress&) +{ + return false; +} + +bool Component::keyStateChanged() +{ + return false; +} + +void Component::modifierKeysChanged (const ModifierKeys& modifiers) +{ + if (parentComponent_ != 0) + parentComponent_->modifierKeysChanged (modifiers); +} + +void Component::internalModifierKeysChanged() +{ + sendFakeMouseMove(); + + modifierKeysChanged (ModifierKeys::getCurrentModifiers()); +} + +//============================================================================== +ComponentPeer* Component::getPeer() const throw() +{ + if (flags.hasHeavyweightPeerFlag) + return ComponentPeer::getPeerFor (this); + else if (parentComponent_ != 0) + return parentComponent_->getPeer(); + else + return 0; +} + +//============================================================================== +const String Component::getComponentProperty (const String& keyName, + const bool useParentComponentIfNotFound, + const String& defaultReturnValue) const throw() +{ + if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) + return propertySet_->getValue (keyName, defaultReturnValue); + + if (useParentComponentIfNotFound && (parentComponent_ != 0)) + return parentComponent_->getComponentProperty (keyName, true, defaultReturnValue); + + return defaultReturnValue; +} + +int Component::getComponentPropertyInt (const String& keyName, + const bool useParentComponentIfNotFound, + const int defaultReturnValue) const throw() +{ + if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) + return propertySet_->getIntValue (keyName, defaultReturnValue); + + if (useParentComponentIfNotFound && (parentComponent_ != 0)) + return parentComponent_->getComponentPropertyInt (keyName, true, defaultReturnValue); + + return defaultReturnValue; +} + +double Component::getComponentPropertyDouble (const String& keyName, + const bool useParentComponentIfNotFound, + const double defaultReturnValue) const throw() +{ + if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) + return propertySet_->getDoubleValue (keyName, defaultReturnValue); + + if (useParentComponentIfNotFound && (parentComponent_ != 0)) + return parentComponent_->getComponentPropertyDouble (keyName, true, defaultReturnValue); + + return defaultReturnValue; +} + +bool Component::getComponentPropertyBool (const String& keyName, + const bool useParentComponentIfNotFound, + const bool defaultReturnValue) const throw() +{ + if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName))) + return propertySet_->getBoolValue (keyName, defaultReturnValue); + + if (useParentComponentIfNotFound && (parentComponent_ != 0)) + return parentComponent_->getComponentPropertyBool (keyName, true, defaultReturnValue); + + return defaultReturnValue; +} + +const Colour Component::getComponentPropertyColour (const String& keyName, + const bool useParentComponentIfNotFound, + const Colour& defaultReturnValue) const throw() +{ + return Colour ((uint32) getComponentPropertyInt (keyName, + useParentComponentIfNotFound, + defaultReturnValue.getARGB())); +} + +void Component::setComponentProperty (const String& keyName, const String& value) throw() +{ + if (propertySet_ == 0) + propertySet_ = new PropertySet(); + + propertySet_->setValue (keyName, value); +} + +void Component::setComponentProperty (const String& keyName, const int value) throw() +{ + if (propertySet_ == 0) + propertySet_ = new PropertySet(); + + propertySet_->setValue (keyName, value); +} + +void Component::setComponentProperty (const String& keyName, const double value) throw() +{ + if (propertySet_ == 0) + propertySet_ = new PropertySet(); + + propertySet_->setValue (keyName, value); +} + +void Component::setComponentProperty (const String& keyName, const bool value) throw() +{ + if (propertySet_ == 0) + propertySet_ = new PropertySet(); + + propertySet_->setValue (keyName, value); +} + +void Component::setComponentProperty (const String& keyName, const Colour& colour) throw() +{ + setComponentProperty (keyName, (int) colour.getARGB()); +} + +void Component::removeComponentProperty (const String& keyName) throw() +{ + if (propertySet_ != 0) + propertySet_->removeValue (keyName); +} + +//============================================================================== +ComponentDeletionWatcher::ComponentDeletionWatcher (const Component* const componentToWatch_) throw() + : componentToWatch (componentToWatch_), + componentUID (componentToWatch_->getComponentUID()) +{ + // not possible to check on an already-deleted object.. + jassert (componentToWatch_->isValidComponent()); +} + +ComponentDeletionWatcher::~ComponentDeletionWatcher() throw() {} + +bool ComponentDeletionWatcher::hasBeenDeleted() const throw() +{ + return ! (componentToWatch->isValidComponent() + && componentToWatch->getComponentUID() == componentUID); +} + +const Component* ComponentDeletionWatcher::getComponent() const throw() +{ + return hasBeenDeleted() ? 0 : componentToWatch; +} + + +END_JUCE_NAMESPACE