@@ -102,16 +102,30 @@ static RLimitInitialiser rLimitInitialiser; | |||
#endif | |||
//============================================================================== | |||
#if ! JUCE_IOS | |||
static String getOSXVersion() | |||
{ | |||
JUCE_AUTORELEASEPOOL | |||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile: | |||
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")]; | |||
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]); | |||
} | |||
#endif | |||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() | |||
{ | |||
#if JUCE_IOS | |||
return iOS; | |||
#else | |||
SInt32 versionMinor = 0; | |||
OSErr err = Gestalt (gestaltSystemVersionMinor, &versionMinor); | |||
(void) err; | |||
jassert (err == noErr); | |||
return (OperatingSystemType) (versionMinor + MacOSX_10_4 - 4); | |||
StringArray parts; | |||
parts.addTokens (getOSXVersion(), ".", String::empty); | |||
jassert (parts[0].getIntValue() == 10); | |||
const int major = parts[1].getIntValue(); | |||
jassert (major > 2); | |||
return (OperatingSystemType) (major + MacOSX_10_4 - 4); | |||
#endif | |||
} | |||
@@ -120,13 +134,7 @@ String SystemStats::getOperatingSystemName() | |||
#if JUCE_IOS | |||
return "iOS " + nsStringToJuce ([[UIDevice currentDevice] systemVersion]); | |||
#else | |||
SInt32 major, minor; | |||
Gestalt (gestaltSystemVersionMajor, &major); | |||
Gestalt (gestaltSystemVersionMinor, &minor); | |||
String s ("Mac OSX "); | |||
s << (int) major << '.' << (int) minor; | |||
return s; | |||
return "Mac OSX " + getOSXVersion(); | |||
#endif | |||
} | |||
@@ -46,11 +46,15 @@ | |||
//============================================================================== | |||
#if JUCE_MAC | |||
#import <WebKit/WebKit.h> | |||
#define Point CarbonDummyPointName | |||
#define Component CarbonDummyCompName | |||
#import <Carbon/Carbon.h> // still needed for SetSystemUIMode() | |||
#undef Point | |||
#undef Component | |||
#import <IOKit/pwr_mgt/IOPMLib.h> | |||
#if JUCE_SUPPORT_CARBON | |||
#define Point CarbonDummyPointName | |||
#define Component CarbonDummyCompName | |||
#import <Carbon/Carbon.h> // still needed for SetSystemUIMode() | |||
#undef Point | |||
#undef Component | |||
#endif | |||
//============================================================================== | |||
#elif JUCE_WINDOWS | |||
@@ -84,70 +84,6 @@ private: | |||
} | |||
}; | |||
//============================================================================== | |||
class TemporaryMainMenuWithStandardCommands | |||
{ | |||
public: | |||
TemporaryMainMenuWithStandardCommands() | |||
: oldMenu (MenuBarModel::getMacMainMenu()), oldAppleMenu (nullptr) | |||
{ | |||
if (const PopupMenu* appleMenu = MenuBarModel::getMacExtraAppleItemsMenu()) | |||
oldAppleMenu = new PopupMenu (*appleMenu); | |||
MenuBarModel::setMacMainMenu (nullptr); | |||
NSMenu* menu = [[NSMenu alloc] initWithTitle: nsStringLiteral ("Edit")]; | |||
NSMenuItem* item; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Cut"), nil) | |||
action: @selector (cut:) keyEquivalent: nsStringLiteral ("x")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Copy"), nil) | |||
action: @selector (copy:) keyEquivalent: nsStringLiteral ("c")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Paste"), nil) | |||
action: @selector (paste:) keyEquivalent: nsStringLiteral ("v")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSApp mainMenu] addItemWithTitle: NSLocalizedString (nsStringLiteral ("Edit"), nil) | |||
action: nil keyEquivalent: nsEmptyString()]; | |||
[[NSApp mainMenu] setSubmenu: menu forItem: item]; | |||
[menu release]; | |||
// use a dummy modal component so that apps can tell that something is currently modal. | |||
dummyModalComponent.enterModalState(); | |||
} | |||
~TemporaryMainMenuWithStandardCommands() | |||
{ | |||
MenuBarModel::setMacMainMenu (oldMenu, oldAppleMenu); | |||
} | |||
private: | |||
MenuBarModel* oldMenu; | |||
ScopedPointer<PopupMenu> oldAppleMenu; | |||
// The OS view already plays an alert when clicking outside | |||
// the modal comp, so this override avoids adding extra | |||
// inappropriate noises when the cancel button is pressed. | |||
// This override is also important because it stops the base class | |||
// calling ModalComponentManager::bringToFront, which can get | |||
// recursive when file dialogs are involved | |||
class SilentDummyModalComp : public Component | |||
{ | |||
public: | |||
SilentDummyModalComp() {} | |||
void inputAttemptWhenModal() {} | |||
}; | |||
SilentDummyModalComp dummyModalComponent; | |||
}; | |||
static NSMutableArray* createAllowedTypesArray (const StringArray& filters) | |||
{ | |||
if (filters.size() == 0) | |||
@@ -295,7 +295,12 @@ private: | |||
if (NSNib* menuNib = [[[NSNib alloc] initWithNibNamed: @"RecentFilesMenuTemplate" bundle: nil] autorelease]) | |||
{ | |||
NSArray* array = nil; | |||
#if (! defined (MAC_OS_X_VERSION_10_8)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 | |||
[menuNib instantiateNibWithOwner: NSApp topLevelObjects: &array]; | |||
#else | |||
[menuNib instantiateWithOwner: NSApp topLevelObjects: &array]; | |||
#endif | |||
for (id object in array) | |||
{ | |||
@@ -303,9 +308,11 @@ private: | |||
{ | |||
if (NSArray* items = [object itemArray]) | |||
{ | |||
NSMenuItem* item = findRecentFilesItem (items); | |||
recentItem = [item retain]; | |||
break; | |||
if (NSMenuItem* item = findRecentFilesItem (items)) | |||
{ | |||
recentItem = [item retain]; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
@@ -529,6 +536,70 @@ private: | |||
JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr; | |||
//============================================================================== | |||
class TemporaryMainMenuWithStandardCommands | |||
{ | |||
public: | |||
TemporaryMainMenuWithStandardCommands() | |||
: oldMenu (MenuBarModel::getMacMainMenu()), oldAppleMenu (nullptr) | |||
{ | |||
if (const PopupMenu* appleMenu = MenuBarModel::getMacExtraAppleItemsMenu()) | |||
oldAppleMenu = new PopupMenu (*appleMenu); | |||
MenuBarModel::setMacMainMenu (nullptr); | |||
NSMenu* menu = [[NSMenu alloc] initWithTitle: nsStringLiteral ("Edit")]; | |||
NSMenuItem* item; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Cut"), nil) | |||
action: @selector (cut:) keyEquivalent: nsStringLiteral ("x")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Copy"), nil) | |||
action: @selector (copy:) keyEquivalent: nsStringLiteral ("c")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString (nsStringLiteral ("Paste"), nil) | |||
action: @selector (paste:) keyEquivalent: nsStringLiteral ("v")]; | |||
[menu addItem: item]; | |||
[item release]; | |||
item = [[NSApp mainMenu] addItemWithTitle: NSLocalizedString (nsStringLiteral ("Edit"), nil) | |||
action: nil keyEquivalent: nsEmptyString()]; | |||
[[NSApp mainMenu] setSubmenu: menu forItem: item]; | |||
[menu release]; | |||
// use a dummy modal component so that apps can tell that something is currently modal. | |||
dummyModalComponent.enterModalState(); | |||
} | |||
~TemporaryMainMenuWithStandardCommands() | |||
{ | |||
MenuBarModel::setMacMainMenu (oldMenu, oldAppleMenu); | |||
} | |||
private: | |||
MenuBarModel* oldMenu; | |||
ScopedPointer<PopupMenu> oldAppleMenu; | |||
// The OS view already plays an alert when clicking outside | |||
// the modal comp, so this override avoids adding extra | |||
// inappropriate noises when the cancel button is pressed. | |||
// This override is also important because it stops the base class | |||
// calling ModalComponentManager::bringToFront, which can get | |||
// recursive when file dialogs are involved | |||
class SilentDummyModalComp : public Component | |||
{ | |||
public: | |||
SilentDummyModalComp() {} | |||
void inputAttemptWhenModal() {} | |||
}; | |||
SilentDummyModalComp dummyModalComponent; | |||
}; | |||
//============================================================================== | |||
namespace MainMenuHelpers | |||
{ | |||
@@ -666,4 +737,8 @@ void juce_initialiseMacMainMenu() | |||
if (JuceMainMenuHandler::instance == nullptr) | |||
MainMenuHelpers::rebuildMainMenu (nullptr); | |||
// Forcing a rebuild of the menus like this seems necessary to kick the native | |||
// recent-files list into action.. (not sure precisely why though) | |||
TemporaryMainMenuWithStandardCommands dummy; (void) dummy; | |||
} |
@@ -230,24 +230,49 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const | |||
} | |||
//============================================================================== | |||
#ifndef __POWER__ // Some versions of the SDK omit this function.. | |||
extern "C" { extern OSErr UpdateSystemActivity (UInt8); } | |||
#endif | |||
class ScreenSaverDefeater : public Timer | |||
{ | |||
public: | |||
ScreenSaverDefeater() | |||
{ | |||
startTimer (10000); | |||
startTimer (5000); | |||
timerCallback(); | |||
} | |||
void timerCallback() | |||
{ | |||
if (Process::isForegroundProcess()) | |||
UpdateSystemActivity (1 /*UsrActivity*/); | |||
{ | |||
if (assertion == nullptr) | |||
assertion = new PMAssertion(); | |||
} | |||
else | |||
{ | |||
assertion = nullptr; | |||
} | |||
} | |||
struct PMAssertion | |||
{ | |||
PMAssertion() : assertionID (kIOPMNullAssertionID) | |||
{ | |||
IOReturn res = IOPMAssertionCreateWithName (kIOPMAssertionTypePreventUserIdleDisplaySleep, | |||
kIOPMAssertionLevelOn, | |||
CFSTR ("JUCE Playback"), | |||
&assertionID); | |||
jassert (res == kIOReturnSuccess); (void) res; | |||
} | |||
~PMAssertion() | |||
{ | |||
if (assertionID != kIOPMNullAssertionID) | |||
IOPMAssertionRelease (assertionID); | |||
} | |||
IOPMAssertionID assertionID; | |||
}; | |||
ScopedPointer<PMAssertion> assertion; | |||
}; | |||
static ScopedPointer<ScreenSaverDefeater> screenSaverDefeater; | |||