@@ -2573,6 +2573,13 @@ private: | |||
Array <Atom> srcMimeTypeAtomList; | |||
}; | |||
//============================================================================== | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
if (enableOrDisable) | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
//============================================================================== | |||
ComponentPeer* Component::createNewPeer (int styleFlags, void* /*nativeWindowToAttachTo*/) | |||
{ | |||
@@ -95,7 +95,7 @@ public: | |||
} | |||
void addSubMenu (NSMenu* parent, const PopupMenu& child, | |||
const String& name, int& menuId, int& tag) | |||
const String& name, const int menuId, int& tag) | |||
{ | |||
NSMenuItem* item = [parent addItemWithTitle: juceStringToNS (name) | |||
action: nil | |||
@@ -181,98 +181,102 @@ public: | |||
MenuBarModel* currentModel; | |||
private: | |||
JuceMenuCallback* callback; | |||
NSMenu* createMenu (const PopupMenu menu, | |||
const String& menuName, | |||
int& id, | |||
const int topLevelIndex) | |||
void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||
const int topLevelMenuId, const int topLevelIndex) | |||
{ | |||
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
[m setAutoenablesItems: false]; | |||
PopupMenu::MenuItemIterator iter (menu); | |||
while (iter.next()) | |||
if (iter.isSeparator) | |||
{ | |||
[menuToAddTo addItem: [NSMenuItem separatorItem]]; | |||
} | |||
else if (iter.isSectionHeader) | |||
{ | |||
NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
NSMenuItem* item = [menuToAddTo addItemWithTitle: text | |||
action: nil | |||
keyEquivalent: @""]; | |||
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 = [menuToAddTo 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]; | |||
[item setTag: iter.itemId]; | |||
[item setEnabled: iter.isEnabled]; | |||
NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, topLevelMenuId, topLevelIndex); | |||
[menuToAddTo setSubmenu: sub forItem: item]; | |||
[sub release]; | |||
} | |||
else | |||
{ | |||
NSMenuItem* item = [menuToAddTo addItemWithTitle: text | |||
action: @selector (menuItemInvoked:) | |||
keyEquivalent: @""]; | |||
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]; | |||
[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]; | |||
NSMutableArray* info = [NSMutableArray arrayWithObject: [NSNumber numberWithUnsignedLongLong: (pointer_sized_int) (void*) iter.commandManager]]; | |||
[info addObject: [NSNumber numberWithInt: topLevelIndex]]; | |||
[item setRepresentedObject: info]; | |||
if (iter.commandManager != 0) | |||
{ | |||
const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
->getKeyPressesAssignedToCommand (iter.itemId)); | |||
if (iter.commandManager != 0) | |||
if (keyPresses.size() > 0) | |||
{ | |||
const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
->getKeyPressesAssignedToCommand (iter.itemId)); | |||
if (keyPresses.size() > 0) | |||
{ | |||
const KeyPress& kp = keyPresses.getReference(0); | |||
juce_wchar key = kp.getTextCharacter(); | |||
if (kp.getKeyCode() == KeyPress::backspaceKey) | |||
key = NSBackspaceCharacter; | |||
else if (kp.getKeyCode() == KeyPress::deleteKey) | |||
key = NSDeleteCharacter; | |||
else if (key == 0) | |||
key = (juce_wchar) kp.getKeyCode(); | |||
unsigned int mods = 0; | |||
if (kp.getModifiers().isShiftDown()) | |||
mods |= NSShiftKeyMask; | |||
if (kp.getModifiers().isCtrlDown()) | |||
mods |= NSControlKeyMask; | |||
if (kp.getModifiers().isAltDown()) | |||
mods |= NSAlternateKeyMask; | |||
if (kp.getModifiers().isCommandDown()) | |||
mods |= NSCommandKeyMask; | |||
[item setKeyEquivalent: juceStringToNS (String::charToString (key))]; | |||
[item setKeyEquivalentModifierMask: mods]; | |||
} | |||
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]; | |||
} | |||
} | |||
} | |||
} | |||
private: | |||
JuceMenuCallback* callback; | |||
NSMenu* createMenu (const PopupMenu menu, | |||
const String& menuName, | |||
const int topLevelMenuId, | |||
const int topLevelIndex) | |||
{ | |||
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
[m setAutoenablesItems: false]; | |||
PopupMenu::MenuItemIterator iter (menu); | |||
while (iter.next()) | |||
addMenuItem (iter, m, topLevelMenuId, topLevelIndex); | |||
[m update]; | |||
return m; | |||
@@ -315,49 +319,22 @@ END_JUCE_NAMESPACE | |||
BEGIN_JUCE_NAMESPACE | |||
void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel) throw() | |||
//============================================================================== | |||
static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||
const PopupMenu* extraItems) | |||
{ | |||
if (getMacMainMenu() != newMenuBarModel) | |||
if (extraItems != 0 && JuceMainMenuHandler::instance != 0 && extraItems->getNumItems() > 0) | |||
{ | |||
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(); | |||
PopupMenu::MenuItemIterator iter (*extraItems); | |||
JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
} | |||
while (iter.next()) | |||
JuceMainMenuHandler::instance->addMenuItem (iter, menu, 0, -1); | |||
[menu addItem: [NSMenuItem separatorItem]]; | |||
} | |||
} | |||
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: @""]; | |||
@@ -403,9 +380,12 @@ static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName) | |||
} | |||
// Since our app has no NIB, this initialises a standard app menu... | |||
void initialiseMainMenu() | |||
static void rebuildMainMenu (const PopupMenu* extraItems) | |||
{ | |||
if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
// this can't be used in a plugin! | |||
jassert (JUCEApplication::getInstance() != 0); | |||
if (JUCEApplication::getInstance() != 0) | |||
{ | |||
const ScopedAutoReleasePool pool; | |||
@@ -418,12 +398,50 @@ void initialiseMainMenu() | |||
[mainMenu setSubmenu: appMenu forItem: item]; | |||
[NSApp setMainMenu: mainMenu]; | |||
createStandardAppMenu (appMenu, JUCEApplication::getInstance()->getApplicationName()); | |||
createStandardAppMenu (appMenu, JUCEApplication::getInstance()->getApplicationName(), extraItems); | |||
[appMenu release]; | |||
[mainMenu release]; | |||
} | |||
} | |||
void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel, | |||
const PopupMenu* extraAppleMenuItems) throw() | |||
{ | |||
if (getMacMainMenu() != newMenuBarModel) | |||
{ | |||
if (newMenuBarModel == 0) | |||
{ | |||
delete JuceMainMenuHandler::instance; | |||
jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | |||
jassert (extraAppleMenuItems == 0); // you can't specify some extra items without also supplying a model | |||
extraAppleMenuItems = 0; | |||
} | |||
else | |||
{ | |||
if (JuceMainMenuHandler::instance == 0) | |||
JuceMainMenuHandler::instance = new JuceMainMenuHandler(); | |||
JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
} | |||
} | |||
rebuildMainMenu (extraAppleMenuItems); | |||
} | |||
MenuBarModel* MenuBarModel::getMacMainMenu() throw() | |||
{ | |||
return JuceMainMenuHandler::instance != 0 | |||
? JuceMainMenuHandler::instance->currentModel : 0; | |||
} | |||
void initialiseMainMenu() | |||
{ | |||
if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
rebuildMainMenu (0); | |||
} | |||
#endif |
@@ -110,8 +110,6 @@ public: | |||
END_JUCE_NAMESPACE | |||
using namespace JUCE_NAMESPACE; | |||
typedef void (*juce_HandleProcessFocusChangeFunction)(); | |||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) | |||
@interface JuceAppDelegate : NSObject | |||
@@ -1062,9 +1062,16 @@ void juce_HandleProcessFocusChange() | |||
if (NSViewComponentPeer::isValidPeer (currentlyFocusedPeer)) | |||
{ | |||
if (Process::isForegroundProcess()) | |||
{ | |||
currentlyFocusedPeer->handleFocusGain(); | |||
} | |||
else | |||
{ | |||
currentlyFocusedPeer->handleFocusLoss(); | |||
// turn kiosk mode off if we lose focus.. | |||
Desktop::getInstance().setKioskModeComponent (0); | |||
} | |||
} | |||
} | |||
@@ -1337,6 +1344,23 @@ void NSViewComponentPeer::redirectMovedOrResized() | |||
handleMovedOrResized(); | |||
} | |||
//============================================================================== | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
// Very annoyingly, this function has to use the old SetSystemUIMode function, | |||
// which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||
// is apparently still available in 64-bit apps.. | |||
if (enableOrDisable) | |||
{ | |||
SetSystemUIMode (kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
else | |||
{ | |||
SetSystemUIMode (kUIModeNormal, 0); | |||
} | |||
} | |||
//============================================================================== | |||
void NSViewComponentPeer::repaint (int x, int y, int w, int h) | |||
{ | |||
@@ -1962,6 +1962,8 @@ private: | |||
// so this forces an update when the app is brought to the front | |||
if (wParam != FALSE) | |||
juce_repeatLastProcessPriority(); | |||
else | |||
Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus | |||
juce_CheckCurrentlyFocusedTopLevelWindow(); | |||
modifiersAtLastCallback = -1; | |||
@@ -2299,6 +2301,13 @@ bool Desktop::isScreenSaverEnabled() throw() | |||
return screenSaverAllowed; | |||
} | |||
//============================================================================== | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
if (enableOrDisable) | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
//============================================================================== | |||
static BOOL CALLBACK enumMonitorsProc (HMONITOR, HDC, LPRECT r, LPARAM userInfo) | |||
{ | |||
@@ -121,7 +121,8 @@ class ContentComp : public Component, | |||
setDefaultLookAndFeel = 0x200b, | |||
setOldSchoolLookAndFeel = 0x200c, | |||
useNativeTitleBar = 0x200d, | |||
useNativeMenus = 0x200e | |||
useNativeMenus = 0x200e, | |||
goToKioskMode = 0x200f | |||
}; | |||
public: | |||
@@ -223,6 +224,10 @@ public: | |||
#if JUCE_MAC | |||
menu.addCommandItem (commandManager, useNativeMenus); | |||
#endif | |||
#if ! JUCE_LINUX | |||
menu.addCommandItem (commandManager, goToKioskMode); | |||
#endif | |||
} | |||
return menu; | |||
@@ -268,6 +273,10 @@ public: | |||
#if JUCE_MAC | |||
, useNativeMenus | |||
#endif | |||
#if ! JUCE_LINUX | |||
, goToKioskMode | |||
#endif | |||
}; | |||
commands.addArray (ids, numElementsInArray (ids)); | |||
@@ -381,6 +390,13 @@ public: | |||
break; | |||
#endif | |||
#if ! JUCE_LINUX | |||
case goToKioskMode: | |||
result.setInfo (T("Show full-screen kiosk mode"), String::empty, generalCategory, 0); | |||
result.setTicked (Desktop::getInstance().getKioskModeComponent() != 0); | |||
break; | |||
#endif | |||
default: | |||
break; | |||
}; | |||
@@ -482,6 +498,20 @@ public: | |||
break; | |||
#endif | |||
#if ! JUCE_LINUX | |||
case goToKioskMode: | |||
if (Desktop::getInstance().getKioskModeComponent() == 0) | |||
{ | |||
Desktop::getInstance().setKioskModeComponent (getTopLevelComponent()); | |||
} | |||
else | |||
{ | |||
Desktop::getInstance().setKioskModeComponent (0); | |||
} | |||
break; | |||
#endif | |||
default: | |||
return false; | |||
}; | |||
@@ -40219,7 +40219,8 @@ Desktop::Desktop() throw() | |||
monitorCoordsClipped (2), | |||
monitorCoordsUnclipped (2), | |||
lastMouseX (0), | |||
lastMouseY (0) | |||
lastMouseY (0), | |||
kioskModeComponent (0) | |||
{ | |||
refreshMonitorSizes(); | |||
} | |||
@@ -40487,6 +40488,40 @@ void Desktop::resetTimer() throw() | |||
getMousePosition (lastMouseX, lastMouseY); | |||
} | |||
extern void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable); | |||
void Desktop::setKioskModeComponent (Component* componentToUse) | |||
{ | |||
if (kioskModeComponent != componentToUse) | |||
{ | |||
// agh! Don't delete a component without first stopping it being the kiosk comp | |||
jassert (kioskModeComponent == 0 || kioskModeComponent->isValidComponent()); | |||
// agh! Don't remove a component from the desktop if it's the kiosk comp! | |||
jassert (kioskModeComponent == 0 || kioskModeComponent->isOnDesktop()); | |||
if (kioskModeComponent->isValidComponent()) | |||
{ | |||
juce_setKioskComponent (kioskModeComponent, false); | |||
kioskModeComponent->setBounds (kioskComponentOriginalBounds); | |||
} | |||
kioskModeComponent = componentToUse; | |||
if (kioskModeComponent != 0) | |||
{ | |||
jassert (kioskModeComponent->isValidComponent()); | |||
// Only components that are already on the desktop can be put into kiosk mode! | |||
jassert (kioskModeComponent->isOnDesktop()); | |||
kioskComponentOriginalBounds = kioskModeComponent->getBounds(); | |||
juce_setKioskComponent (kioskModeComponent, true); | |||
} | |||
} | |||
} | |||
END_JUCE_NAMESPACE | |||
/********* End of inlined file: juce_Desktop.cpp *********/ | |||
@@ -42660,13 +42695,13 @@ void Label::setText (const String& newText, | |||
text = newText; | |||
repaint(); | |||
textWasChanged(); | |||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted()) | |||
{ | |||
componentMovedOrResized (*ownerComponent, true, true); | |||
if (broadcastChangeMessage) | |||
callChangeListeners(); | |||
} | |||
if (broadcastChangeMessage) | |||
callChangeListeners(); | |||
} | |||
} | |||
@@ -42770,6 +42805,10 @@ void Label::textWasEdited() | |||
{ | |||
} | |||
void Label::textWasChanged() | |||
{ | |||
} | |||
void Label::showEditor() | |||
{ | |||
if (editor == 0) | |||
@@ -42799,6 +42838,8 @@ bool Label::updateFromTextEditorContents() | |||
text = newText; | |||
repaint(); | |||
textWasChanged(); | |||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted()) | |||
componentMovedOrResized (*ownerComponent, true, true); | |||
@@ -242642,6 +242683,8 @@ private: | |||
// so this forces an update when the app is brought to the front | |||
if (wParam != FALSE) | |||
juce_repeatLastProcessPriority(); | |||
else | |||
Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus | |||
juce_CheckCurrentlyFocusedTopLevelWindow(); | |||
modifiersAtLastCallback = -1; | |||
@@ -242969,6 +243012,12 @@ bool Desktop::isScreenSaverEnabled() throw() | |||
return screenSaverAllowed; | |||
} | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
if (enableOrDisable) | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
static BOOL CALLBACK enumMonitorsProc (HMONITOR, HDC, LPRECT r, LPARAM userInfo) | |||
{ | |||
Array <Rectangle>* const monitorCoords = (Array <Rectangle>*) userInfo; | |||
@@ -261216,6 +261265,12 @@ private: | |||
Array <Atom> srcMimeTypeAtomList; | |||
}; | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
if (enableOrDisable) | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
ComponentPeer* Component::createNewPeer (int styleFlags, void* /*nativeWindowToAttachTo*/) | |||
{ | |||
return new LinuxComponentPeer (this, styleFlags); | |||
@@ -265133,9 +265188,16 @@ void juce_HandleProcessFocusChange() | |||
if (NSViewComponentPeer::isValidPeer (currentlyFocusedPeer)) | |||
{ | |||
if (Process::isForegroundProcess()) | |||
{ | |||
currentlyFocusedPeer->handleFocusGain(); | |||
} | |||
else | |||
{ | |||
currentlyFocusedPeer->handleFocusLoss(); | |||
// turn kiosk mode off if we lose focus.. | |||
Desktop::getInstance().setKioskModeComponent (0); | |||
} | |||
} | |||
} | |||
@@ -265406,6 +265468,22 @@ void NSViewComponentPeer::redirectMovedOrResized() | |||
handleMovedOrResized(); | |||
} | |||
void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
{ | |||
// Very annoyingly, this function has to use the old SetSystemUIMode function, | |||
// which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||
// is apparently still available in 64-bit apps.. | |||
if (enableOrDisable) | |||
{ | |||
SetSystemUIMode (kUIModeAllSuppressed, kUIOptionAutoShowMenuBar); | |||
kioskModeComponent->setBounds (Desktop::getInstance().getMainMonitorArea (false)); | |||
} | |||
else | |||
{ | |||
SetSystemUIMode (kUIModeNormal, 0); | |||
} | |||
} | |||
void NSViewComponentPeer::repaint (int x, int y, int w, int h) | |||
{ | |||
[view setNeedsDisplayInRect: | |||
@@ -266306,7 +266384,7 @@ public: | |||
} | |||
void addSubMenu (NSMenu* parent, const PopupMenu& child, | |||
const String& name, int& menuId, int& tag) | |||
const String& name, const int menuId, int& tag) | |||
{ | |||
NSMenuItem* item = [parent addItemWithTitle: juceStringToNS (name) | |||
action: nil | |||
@@ -266392,98 +266470,102 @@ public: | |||
MenuBarModel* currentModel; | |||
private: | |||
JuceMenuCallback* callback; | |||
NSMenu* createMenu (const PopupMenu menu, | |||
const String& menuName, | |||
int& id, | |||
const int topLevelIndex) | |||
void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||
const int topLevelMenuId, const int topLevelIndex) | |||
{ | |||
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
[m setAutoenablesItems: false]; | |||
NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
PopupMenu::MenuItemIterator iter (menu); | |||
while (iter.next()) | |||
if (iter.isSeparator) | |||
{ | |||
[menuToAddTo addItem: [NSMenuItem separatorItem]]; | |||
} | |||
else if (iter.isSectionHeader) | |||
{ | |||
NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
NSMenuItem* item = [menuToAddTo addItemWithTitle: text | |||
action: nil | |||
keyEquivalent: @""]; | |||
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 = [menuToAddTo 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]; | |||
[item setTag: iter.itemId]; | |||
[item setEnabled: iter.isEnabled]; | |||
NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, topLevelMenuId, topLevelIndex); | |||
[menuToAddTo setSubmenu: sub forItem: item]; | |||
[sub release]; | |||
} | |||
else | |||
{ | |||
NSMenuItem* item = [menuToAddTo addItemWithTitle: text | |||
action: @selector (menuItemInvoked:) | |||
keyEquivalent: @""]; | |||
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]; | |||
[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]; | |||
NSMutableArray* info = [NSMutableArray arrayWithObject: [NSNumber numberWithUnsignedLongLong: (pointer_sized_int) (void*) iter.commandManager]]; | |||
[info addObject: [NSNumber numberWithInt: topLevelIndex]]; | |||
[item setRepresentedObject: info]; | |||
if (iter.commandManager != 0) | |||
{ | |||
const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
->getKeyPressesAssignedToCommand (iter.itemId)); | |||
if (iter.commandManager != 0) | |||
if (keyPresses.size() > 0) | |||
{ | |||
const Array <KeyPress> keyPresses (iter.commandManager->getKeyMappings() | |||
->getKeyPressesAssignedToCommand (iter.itemId)); | |||
if (keyPresses.size() > 0) | |||
{ | |||
const KeyPress& kp = keyPresses.getReference(0); | |||
juce_wchar key = kp.getTextCharacter(); | |||
if (kp.getKeyCode() == KeyPress::backspaceKey) | |||
key = NSBackspaceCharacter; | |||
else if (kp.getKeyCode() == KeyPress::deleteKey) | |||
key = NSDeleteCharacter; | |||
else if (key == 0) | |||
key = (juce_wchar) kp.getKeyCode(); | |||
unsigned int mods = 0; | |||
if (kp.getModifiers().isShiftDown()) | |||
mods |= NSShiftKeyMask; | |||
if (kp.getModifiers().isCtrlDown()) | |||
mods |= NSControlKeyMask; | |||
if (kp.getModifiers().isAltDown()) | |||
mods |= NSAlternateKeyMask; | |||
if (kp.getModifiers().isCommandDown()) | |||
mods |= NSCommandKeyMask; | |||
[item setKeyEquivalent: juceStringToNS (String::charToString (key))]; | |||
[item setKeyEquivalentModifierMask: mods]; | |||
} | |||
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]; | |||
} | |||
} | |||
} | |||
} | |||
private: | |||
JuceMenuCallback* callback; | |||
NSMenu* createMenu (const PopupMenu menu, | |||
const String& menuName, | |||
const int topLevelMenuId, | |||
const int topLevelIndex) | |||
{ | |||
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)]; | |||
[m setAutoenablesItems: false]; | |||
PopupMenu::MenuItemIterator iter (menu); | |||
while (iter.next()) | |||
addMenuItem (iter, m, topLevelMenuId, topLevelIndex); | |||
[m update]; | |||
return m; | |||
@@ -266526,47 +266608,21 @@ END_JUCE_NAMESPACE | |||
BEGIN_JUCE_NAMESPACE | |||
void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel) throw() | |||
static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||
const PopupMenu* extraItems) | |||
{ | |||
if (getMacMainMenu() != newMenuBarModel) | |||
if (extraItems != 0 && JuceMainMenuHandler::instance != 0 && extraItems->getNumItems() > 0) | |||
{ | |||
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(); | |||
PopupMenu::MenuItemIterator iter (*extraItems); | |||
JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
} | |||
} | |||
} | |||
while (iter.next()) | |||
JuceMainMenuHandler::instance->addMenuItem (iter, menu, 0, -1); | |||
MenuBarModel* MenuBarModel::getMacMainMenu() throw() | |||
{ | |||
return JuceMainMenuHandler::instance != 0 | |||
? JuceMainMenuHandler::instance->currentModel : 0; | |||
} | |||
[menu addItem: [NSMenuItem separatorItem]]; | |||
} | |||
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: @""]; | |||
@@ -266612,9 +266668,12 @@ static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName) | |||
} | |||
// Since our app has no NIB, this initialises a standard app menu... | |||
void initialiseMainMenu() | |||
static void rebuildMainMenu (const PopupMenu* extraItems) | |||
{ | |||
if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
// this can't be used in a plugin! | |||
jassert (JUCEApplication::getInstance() != 0); | |||
if (JUCEApplication::getInstance() != 0) | |||
{ | |||
const ScopedAutoReleasePool pool; | |||
@@ -266627,13 +266686,50 @@ void initialiseMainMenu() | |||
[mainMenu setSubmenu: appMenu forItem: item]; | |||
[NSApp setMainMenu: mainMenu]; | |||
createStandardAppMenu (appMenu, JUCEApplication::getInstance()->getApplicationName()); | |||
createStandardAppMenu (appMenu, JUCEApplication::getInstance()->getApplicationName(), extraItems); | |||
[appMenu release]; | |||
[mainMenu release]; | |||
} | |||
} | |||
void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel, | |||
const PopupMenu* extraAppleMenuItems) throw() | |||
{ | |||
if (getMacMainMenu() != newMenuBarModel) | |||
{ | |||
if (newMenuBarModel == 0) | |||
{ | |||
delete JuceMainMenuHandler::instance; | |||
jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | |||
jassert (extraAppleMenuItems == 0); // you can't specify some extra items without also supplying a model | |||
extraAppleMenuItems = 0; | |||
} | |||
else | |||
{ | |||
if (JuceMainMenuHandler::instance == 0) | |||
JuceMainMenuHandler::instance = new JuceMainMenuHandler(); | |||
JuceMainMenuHandler::instance->setMenu (newMenuBarModel); | |||
} | |||
} | |||
rebuildMainMenu (extraAppleMenuItems); | |||
} | |||
MenuBarModel* MenuBarModel::getMacMainMenu() throw() | |||
{ | |||
return JuceMainMenuHandler::instance != 0 | |||
? JuceMainMenuHandler::instance->currentModel : 0; | |||
} | |||
void initialiseMainMenu() | |||
{ | |||
if (JUCEApplication::getInstance() != 0) // only needed in an app | |||
rebuildMainMenu (0); | |||
} | |||
#endif | |||
/********* End of inlined file: juce_mac_MainMenu.mm *********/ | |||
@@ -268007,8 +268103,6 @@ public: | |||
END_JUCE_NAMESPACE | |||
using namespace JUCE_NAMESPACE; | |||
typedef void (*juce_HandleProcessFocusChangeFunction)(); | |||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) | |||
@interface JuceAppDelegate : NSObject | |||
@@ -23677,6 +23677,25 @@ public: | |||
/** Unregisters a listener that was added with addFocusChangeListener(). */ | |||
void removeFocusChangeListener (FocusChangeListener* const listener) throw(); | |||
/** Takes a component and makes it full-screen, removing the taskbar, dock, etc. | |||
The component must already be on the desktop for this method to work. It will | |||
be resized to completely fill the screen and any extraneous taskbars, menu bars, | |||
etc will be hidden. | |||
To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||
the component that's currently being used will be resized back to the size | |||
and position it was in before being put into this mode. | |||
*/ | |||
void setKioskModeComponent (Component* componentToUse); | |||
/** Returns the component that is currently being used in kiosk-mode. | |||
This is the component that was last set by setKioskModeComponent(). If none | |||
has been set, this returns 0. | |||
*/ | |||
Component* getKioskModeComponent() const { return kioskModeComponent; } | |||
/** Returns the number of components that are currently active as top-level | |||
desktop windows. | |||
@@ -23729,6 +23748,9 @@ private: | |||
Array <Rectangle> monitorCoordsClipped, monitorCoordsUnclipped; | |||
int lastMouseX, lastMouseY; | |||
Component* kioskModeComponent; | |||
Rectangle kioskComponentOriginalBounds; | |||
void timerCallback(); | |||
void sendMouseMove(); | |||
void resetTimer() throw(); | |||
@@ -33290,6 +33312,10 @@ protected: | |||
*/ | |||
virtual void textWasEdited(); | |||
/** Called when the text has been altered. | |||
*/ | |||
virtual void textWasChanged(); | |||
private: | |||
String text; | |||
Font font; | |||
@@ -43159,13 +43185,23 @@ public: | |||
You can pass 0 to stop the current model being displayed. Be careful | |||
not to delete a model while it is being used. | |||
An optional extra menu can be specified, containing items to add to the top of | |||
the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||
an apple, it's the one next to it, with your application's name at the top | |||
and the services menu etc on it). When one of these items is selected, the | |||
menu bar model will be used to invoke it, and in the menuItemSelected() callback | |||
the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems | |||
object then newMenuBarModel must be non-null. | |||
*/ | |||
static void setMacMainMenu (MenuBarModel* newMenuBarModel) throw(); | |||
static void setMacMainMenu (MenuBarModel* newMenuBarModel, | |||
const PopupMenu* extraAppleMenuItems = 0) throw(); | |||
/** MAC ONLY - Returns the menu model that is currently being shown as | |||
the main menu bar. | |||
*/ | |||
static MenuBarModel* getMacMainMenu() throw(); | |||
#endif | |||
/** @internal */ | |||
@@ -82,13 +82,13 @@ void Label::setText (const String& newText, | |||
text = newText; | |||
repaint(); | |||
textWasChanged(); | |||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted()) | |||
{ | |||
componentMovedOrResized (*ownerComponent, true, true); | |||
if (broadcastChangeMessage) | |||
callChangeListeners(); | |||
} | |||
if (broadcastChangeMessage) | |||
callChangeListeners(); | |||
} | |||
} | |||
@@ -194,6 +194,10 @@ void Label::textWasEdited() | |||
{ | |||
} | |||
void Label::textWasChanged() | |||
{ | |||
} | |||
void Label::showEditor() | |||
{ | |||
if (editor == 0) | |||
@@ -223,6 +227,8 @@ bool Label::updateFromTextEditorContents() | |||
text = newText; | |||
repaint(); | |||
textWasChanged(); | |||
if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted()) | |||
componentMovedOrResized (*ownerComponent, true, true); | |||
@@ -305,6 +305,10 @@ protected: | |||
*/ | |||
virtual void textWasEdited(); | |||
/** Called when the text has been altered. | |||
*/ | |||
virtual void textWasChanged(); | |||
private: | |||
String text; | |||
Font font; | |||
@@ -51,7 +51,8 @@ Desktop::Desktop() throw() | |||
monitorCoordsClipped (2), | |||
monitorCoordsUnclipped (2), | |||
lastMouseX (0), | |||
lastMouseY (0) | |||
lastMouseY (0), | |||
kioskModeComponent (0) | |||
{ | |||
refreshMonitorSizes(); | |||
} | |||
@@ -326,4 +327,40 @@ void Desktop::resetTimer() throw() | |||
getMousePosition (lastMouseX, lastMouseY); | |||
} | |||
//============================================================================== | |||
extern void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable); | |||
void Desktop::setKioskModeComponent (Component* componentToUse) | |||
{ | |||
if (kioskModeComponent != componentToUse) | |||
{ | |||
// agh! Don't delete a component without first stopping it being the kiosk comp | |||
jassert (kioskModeComponent == 0 || kioskModeComponent->isValidComponent()); | |||
// agh! Don't remove a component from the desktop if it's the kiosk comp! | |||
jassert (kioskModeComponent == 0 || kioskModeComponent->isOnDesktop()); | |||
if (kioskModeComponent->isValidComponent()) | |||
{ | |||
juce_setKioskComponent (kioskModeComponent, false); | |||
kioskModeComponent->setBounds (kioskComponentOriginalBounds); | |||
} | |||
kioskModeComponent = componentToUse; | |||
if (kioskModeComponent != 0) | |||
{ | |||
jassert (kioskModeComponent->isValidComponent()); | |||
// Only components that are already on the desktop can be put into kiosk mode! | |||
jassert (kioskModeComponent->isOnDesktop()); | |||
kioskComponentOriginalBounds = kioskModeComponent->getBounds(); | |||
juce_setKioskComponent (kioskModeComponent, true); | |||
} | |||
} | |||
} | |||
END_JUCE_NAMESPACE |
@@ -175,6 +175,26 @@ public: | |||
/** Unregisters a listener that was added with addFocusChangeListener(). */ | |||
void removeFocusChangeListener (FocusChangeListener* const listener) throw(); | |||
//============================================================================== | |||
/** Takes a component and makes it full-screen, removing the taskbar, dock, etc. | |||
The component must already be on the desktop for this method to work. It will | |||
be resized to completely fill the screen and any extraneous taskbars, menu bars, | |||
etc will be hidden. | |||
To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||
the component that's currently being used will be resized back to the size | |||
and position it was in before being put into this mode. | |||
*/ | |||
void setKioskModeComponent (Component* componentToUse); | |||
/** Returns the component that is currently being used in kiosk-mode. | |||
This is the component that was last set by setKioskModeComponent(). If none | |||
has been set, this returns 0. | |||
*/ | |||
Component* getKioskModeComponent() const { return kioskModeComponent; } | |||
//============================================================================== | |||
/** Returns the number of components that are currently active as top-level | |||
desktop windows. | |||
@@ -231,6 +251,9 @@ private: | |||
Array <Rectangle> monitorCoordsClipped, monitorCoordsUnclipped; | |||
int lastMouseX, lastMouseY; | |||
Component* kioskModeComponent; | |||
Rectangle kioskComponentOriginalBounds; | |||
void timerCallback(); | |||
void sendMouseMove(); | |||
void resetTimer() throw(); | |||
@@ -147,13 +147,23 @@ public: | |||
You can pass 0 to stop the current model being displayed. Be careful | |||
not to delete a model while it is being used. | |||
An optional extra menu can be specified, containing items to add to the top of | |||
the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||
an apple, it's the one next to it, with your application's name at the top | |||
and the services menu etc on it). When one of these items is selected, the | |||
menu bar model will be used to invoke it, and in the menuItemSelected() callback | |||
the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems | |||
object then newMenuBarModel must be non-null. | |||
*/ | |||
static void setMacMainMenu (MenuBarModel* newMenuBarModel) throw(); | |||
static void setMacMainMenu (MenuBarModel* newMenuBarModel, | |||
const PopupMenu* extraAppleMenuItems = 0) throw(); | |||
/** MAC ONLY - Returns the menu model that is currently being shown as | |||
the main menu bar. | |||
*/ | |||
static MenuBarModel* getMacMainMenu() throw(); | |||
#endif | |||
//============================================================================== | |||