| @@ -565,7 +565,7 @@ private: | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_WINDOWS || JUCE_LINUX | |||||
| #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC | |||||
| // Just add a simple icon to the Window system tray area.. | // Just add a simple icon to the Window system tray area.. | ||||
| class DemoTaskbarComponent : public SystemTrayIconComponent | class DemoTaskbarComponent : public SystemTrayIconComponent | ||||
| @@ -633,7 +633,7 @@ MainDemoWindow::MainDemoWindow() | |||||
| setVisible (true); | setVisible (true); | ||||
| #if JUCE_WINDOWS || JUCE_LINUX | |||||
| #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC | |||||
| taskbarIcon = new DemoTaskbarComponent(); | taskbarIcon = new DemoTaskbarComponent(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -28,7 +28,7 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| namespace MouseCursorHelpers | namespace MouseCursorHelpers | ||||
| { | { | ||||
| static NSImage* createNSImage (const Image& image) | |||||
| NSImage* createNSImage (const Image& image) | |||||
| { | { | ||||
| JUCE_AUTORELEASEPOOL | JUCE_AUTORELEASEPOOL | ||||
| { | { | ||||
| @@ -111,6 +111,7 @@ namespace juce | |||||
| #if JUCE_MAC | #if JUCE_MAC | ||||
| #include "native/juce_mac_NSViewComponent.mm" | #include "native/juce_mac_NSViewComponent.mm" | ||||
| #include "native/juce_mac_AppleRemote.mm" | #include "native/juce_mac_AppleRemote.mm" | ||||
| #include "native/juce_mac_SystemTrayIcon.cpp" | |||||
| #endif | #endif | ||||
| #if JUCE_IOS | #if JUCE_IOS | ||||
| @@ -23,7 +23,7 @@ | |||||
| ============================================================================== | ============================================================================== | ||||
| */ | */ | ||||
| #if JUCE_WINDOWS || JUCE_LINUX | |||||
| #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC | |||||
| SystemTrayIconComponent::SystemTrayIconComponent() | SystemTrayIconComponent::SystemTrayIconComponent() | ||||
| { | { | ||||
| @@ -26,7 +26,7 @@ | |||||
| #ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | #ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | ||||
| #define __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | #define __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | ||||
| #if JUCE_WINDOWS || JUCE_LINUX || DOXYGEN | |||||
| #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC || DOXYGEN | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -0,0 +1,173 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-11 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| 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. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| namespace MouseCursorHelpers | |||||
| { | |||||
| extern NSImage* createNSImage (const Image&); | |||||
| } | |||||
| class SystemTrayIconComponent::Pimpl | |||||
| { | |||||
| public: | |||||
| Pimpl (SystemTrayIconComponent& iconComp, const Image& im) | |||||
| : owner (iconComp), statusItem (nil), | |||||
| statusIcon (MouseCursorHelpers::createNSImage (im)) | |||||
| { | |||||
| static SystemTrayCallbackClass cls; | |||||
| callback = [cls.createInstance() init]; | |||||
| SystemTrayCallbackClass::setOwner (callback, this); | |||||
| statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]; | |||||
| [statusItem setHighlightMode: YES]; | |||||
| setIconSize(); | |||||
| [statusItem setImage: statusIcon]; | |||||
| [statusItem setTarget: callback]; | |||||
| [statusItem setAction: @selector (statusItemAction:)]; | |||||
| } | |||||
| ~Pimpl() | |||||
| { | |||||
| [statusItem release]; | |||||
| [statusIcon release]; | |||||
| [callback release]; | |||||
| } | |||||
| void updateIcon (const Image& newImage) | |||||
| { | |||||
| [statusIcon release]; | |||||
| statusIcon = MouseCursorHelpers::createNSImage (newImage); | |||||
| setIconSize(); | |||||
| } | |||||
| void handleStatusItemAction (NSEvent* e) | |||||
| { | |||||
| NSEventType type = [e type]; | |||||
| const bool isLeft = (type == NSLeftMouseDown || type == NSLeftMouseUp); | |||||
| const bool isRight = (type == NSRightMouseDown || type == NSRightMouseUp); | |||||
| if (owner.isCurrentlyBlockedByAnotherModalComponent()) | |||||
| { | |||||
| if (isLeft || isRight) | |||||
| if (Component* const current = Component::getCurrentlyModalComponent()) | |||||
| current->inputAttemptWhenModal(); | |||||
| } | |||||
| else | |||||
| { | |||||
| ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime()); | |||||
| if (([e modifierFlags] & NSCommandKeyMask) != 0) | |||||
| eventMods = eventMods.withFlags (ModifierKeys::commandModifier); | |||||
| NSRect r = [[e window] frame]; | |||||
| r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - r.origin.y - r.size.height; | |||||
| owner.setBounds (convertToRectInt (r)); | |||||
| const Time now (Time::getCurrentTime()); | |||||
| if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up | |||||
| { | |||||
| owner.mouseDown (MouseEvent (Desktop::getInstance().getMainMouseSource(), | |||||
| Point<int>(), | |||||
| eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier | |||||
| : ModifierKeys::rightButtonModifier), | |||||
| &owner, &owner, now, | |||||
| Point<int>(), now, 1, false)); | |||||
| owner.mouseUp (MouseEvent (Desktop::getInstance().getMainMouseSource(), | |||||
| Point<int>(), eventMods.withoutMouseButtons(), | |||||
| &owner, &owner, now, | |||||
| Point<int>(), now, 1, false)); | |||||
| } | |||||
| else if (type == NSMouseMoved) | |||||
| { | |||||
| owner.mouseMove (MouseEvent (Desktop::getInstance().getMainMouseSource(), | |||||
| Point<int>(), eventMods, | |||||
| &owner, &owner, now, | |||||
| Point<int>(), now, 1, false)); | |||||
| } | |||||
| } | |||||
| } | |||||
| private: | |||||
| SystemTrayIconComponent& owner; | |||||
| NSStatusItem* statusItem; | |||||
| NSImage* statusIcon; | |||||
| NSObject* callback; | |||||
| void setIconSize() | |||||
| { | |||||
| [statusIcon setSize: NSMakeSize (20.0f, 20.0f)]; | |||||
| } | |||||
| struct SystemTrayCallbackClass : public ObjCClass <NSObject> | |||||
| { | |||||
| SystemTrayCallbackClass() : ObjCClass <NSObject> ("JUCESystemTray_") | |||||
| { | |||||
| addIvar<SystemTrayIconComponent::Pimpl*> ("owner"); | |||||
| addMethod (@selector (statusItemAction:), statusItemAction, "v@:@"); | |||||
| registerClass(); | |||||
| } | |||||
| static void setOwner (id self, SystemTrayIconComponent::Pimpl* owner) | |||||
| { | |||||
| object_setInstanceVariable (self, "owner", owner); | |||||
| } | |||||
| private: | |||||
| static void statusItemAction (id self, SEL, id /*sender*/) | |||||
| { | |||||
| if (SystemTrayIconComponent::Pimpl* const owner = getIvar<SystemTrayIconComponent::Pimpl*> (self, "owner")) | |||||
| owner->handleStatusItemAction ([NSApp currentEvent]); | |||||
| } | |||||
| }; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) | |||||
| }; | |||||
| //============================================================================== | |||||
| void SystemTrayIconComponent::setIconImage (const Image& newImage) | |||||
| { | |||||
| if (newImage.isValid()) | |||||
| { | |||||
| if (pimpl == nullptr) | |||||
| pimpl = new Pimpl (*this, newImage); | |||||
| else | |||||
| pimpl->updateIcon (newImage); | |||||
| } | |||||
| else | |||||
| { | |||||
| pimpl = nullptr; | |||||
| } | |||||
| } | |||||
| void SystemTrayIconComponent::setIconTooltip (const String& /* tooltip */) | |||||
| { | |||||
| // xxx not yet implemented! | |||||
| } | |||||
| @@ -55,10 +55,9 @@ public: | |||||
| // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out. | // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out. | ||||
| // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later) | // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later) | ||||
| typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD); | typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD); | ||||
| ChangeWindowMessageFilterType changeWindowMessageFilter | |||||
| = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter"); | |||||
| if (changeWindowMessageFilter != nullptr) | |||||
| if (ChangeWindowMessageFilterType changeWindowMessageFilter | |||||
| = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter")) | |||||
| changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */); | changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */); | ||||
| } | } | ||||
| @@ -96,9 +95,7 @@ public: | |||||
| if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN | if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN | ||||
| || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) | || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) | ||||
| { | { | ||||
| Component* const current = Component::getCurrentlyModalComponent(); | |||||
| if (current != nullptr) | |||||
| if (Component* const current = Component::getCurrentlyModalComponent()) | |||||
| current->inputAttemptWhenModal(); | current->inputAttemptWhenModal(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -113,9 +110,11 @@ public: | |||||
| else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) | else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) | ||||
| eventMods = eventMods.withoutMouseButtons(); | eventMods = eventMods.withoutMouseButtons(); | ||||
| const Time eventTime (getMouseEventTime()); | |||||
| const MouseEvent e (Desktop::getInstance().getMainMouseSource(), | const MouseEvent e (Desktop::getInstance().getMainMouseSource(), | ||||
| Point<int>(), eventMods, &owner, &owner, Time (getMouseEventTime()), | |||||
| Point<int>(), Time (getMouseEventTime()), 1, false); | |||||
| Point<int>(), eventMods, &owner, &owner, eventTime, | |||||
| Point<int>(), eventTime, 1, false); | |||||
| if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) | if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) | ||||
| { | { | ||||
| @@ -141,17 +140,9 @@ public: | |||||
| static Pimpl* getPimpl (HWND hwnd) | static Pimpl* getPimpl (HWND hwnd) | ||||
| { | { | ||||
| if (JuceWindowIdentifier::isJUCEWindow (hwnd)) | if (JuceWindowIdentifier::isJUCEWindow (hwnd)) | ||||
| { | |||||
| ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8); | |||||
| if (peer != nullptr) | |||||
| { | |||||
| SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent())); | |||||
| if (iconComp != nullptr) | |||||
| if (ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8)) | |||||
| if (SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent()))) | |||||
| return iconComp->pimpl; | return iconComp->pimpl; | ||||
| } | |||||
| } | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||