mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-21 01:24:21 +00:00
Added some new methods to SystemTrayIconComponent for highlighting and message bubbles.
This commit is contained in:
parent
64391b7552
commit
09d20dcae8
7 changed files with 146 additions and 47 deletions
|
|
@ -69,7 +69,7 @@ void* attachSubWindow (void* hostWindowRef, Component* comp)
|
|||
f.size.height = comp->getHeight();
|
||||
[content setFrame: f];
|
||||
|
||||
const int mainScreenHeight = [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
|
||||
const int mainScreenHeight = getMainScreenHeight();
|
||||
|
||||
#if WINDOWPOSITION_BODGE
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,23 @@ extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
|
|||
namespace juce {
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
static CGFloat getMainScreenHeight() noexcept
|
||||
{
|
||||
return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
|
||||
}
|
||||
|
||||
static void flipScreenRect (NSRect& r) noexcept
|
||||
{
|
||||
r.origin.y = getMainScreenHeight() - (r.origin.y + r.size.height);
|
||||
}
|
||||
|
||||
static NSRect flippedScreenRect (NSRect r) noexcept
|
||||
{
|
||||
flipScreenRect (r);
|
||||
return r;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class NSViewComponentPeer : public ComponentPeer
|
||||
{
|
||||
|
|
@ -107,7 +124,7 @@ public:
|
|||
{
|
||||
r.origin.x = (CGFloat) component.getX();
|
||||
r.origin.y = (CGFloat) component.getY();
|
||||
r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - (r.origin.y + r.size.height);
|
||||
flipScreenRect (r);
|
||||
|
||||
window = [createWindowInstance() initWithContentRect: r
|
||||
styleMask: getNSWindowStyleMask (windowStyleFlags)
|
||||
|
|
@ -241,9 +258,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - (r.origin.y + r.size.height);
|
||||
|
||||
[window setFrame: [window frameRectForContentRect: r]
|
||||
[window setFrame: [window frameRectForContentRect: flippedScreenRect (r)]
|
||||
display: true];
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +278,7 @@ public:
|
|||
r.origin = [viewWindow convertBaseToScreen: r.origin];
|
||||
#endif
|
||||
|
||||
r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - r.origin.y - r.size.height;
|
||||
flipScreenRect (r);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -875,13 +890,9 @@ public:
|
|||
#endif
|
||||
)
|
||||
{
|
||||
NSRect current = [window frame];
|
||||
current.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - current.origin.y - current.size.height;
|
||||
Rectangle<int> pos (convertToRectInt (flippedScreenRect (r)));
|
||||
Rectangle<int> original (convertToRectInt (flippedScreenRect ([window frame])));
|
||||
|
||||
r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - r.origin.y - r.size.height;
|
||||
|
||||
Rectangle<int> pos (convertToRectInt (r));
|
||||
Rectangle<int> original (convertToRectInt (current));
|
||||
const Rectangle<int> screenBounds (Desktop::getInstance().getDisplays().getTotalBounds (true));
|
||||
|
||||
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||
|
|
@ -898,15 +909,12 @@ public:
|
|||
{
|
||||
constrainer->checkBounds (pos, original, screenBounds,
|
||||
pos.getY() != original.getY() && pos.getBottom() == original.getBottom(),
|
||||
pos.getX() != original.getX() && pos.getRight() == original.getRight(),
|
||||
pos.getX() != original.getX() && pos.getRight() == original.getRight(),
|
||||
pos.getY() == original.getY() && pos.getBottom() != original.getBottom(),
|
||||
pos.getX() == original.getX() && pos.getRight() != original.getRight());
|
||||
pos.getX() == original.getX() && pos.getRight() != original.getRight());
|
||||
}
|
||||
|
||||
r.origin.x = pos.getX();
|
||||
r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - r.size.height - pos.getY();
|
||||
r.size.width = pos.getWidth();
|
||||
r.size.height = pos.getHeight();
|
||||
r = flippedScreenRect (makeNSRect (pos));
|
||||
}
|
||||
|
||||
return r;
|
||||
|
|
@ -1578,17 +1586,8 @@ private:
|
|||
static NSRect firstRectForCharacterRange (id self, SEL, NSRange)
|
||||
{
|
||||
if (NSViewComponentPeer* const owner = getOwner (self))
|
||||
{
|
||||
if (Component* const comp = dynamic_cast <Component*> (owner->findCurrentTextInputTarget()))
|
||||
{
|
||||
const Rectangle<int> bounds (comp->getScreenBounds());
|
||||
|
||||
return NSMakeRect (bounds.getX(),
|
||||
[[[NSScreen screens] objectAtIndex: 0] frame].size.height - bounds.getY(),
|
||||
bounds.getWidth(),
|
||||
bounds.getHeight());
|
||||
}
|
||||
}
|
||||
return flippedScreenRect (makeNSRect (comp->getScreenBounds()));
|
||||
|
||||
return NSZeroRect;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ Point<int> MouseInputSource::getCurrentRawMousePosition()
|
|||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
const NSPoint p ([NSEvent mouseLocation]);
|
||||
return Point<int> (roundToInt (p.x), roundToInt ([[[NSScreen screens] objectAtIndex: 0] frame].size.height - p.y));
|
||||
return Point<int> (roundToInt (p.x), roundToInt (getMainScreenHeight() - p.y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,13 +55,27 @@ public:
|
|||
~SystemTrayIconComponent();
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the image shown in the taskbar.
|
||||
*/
|
||||
/** Changes the image shown in the taskbar. */
|
||||
void setIconImage (const Image& newImage);
|
||||
|
||||
/** Changes the tooltip that Windows shows above the icon. */
|
||||
/** Changes the icon's tooltip (if the current OS supports this). */
|
||||
void setIconTooltip (const String& tooltip);
|
||||
|
||||
/** Highlights the icon (if the current OS supports this). */
|
||||
void setHighlighted (bool);
|
||||
|
||||
/** Shows a floating text bubble pointing to the icon (if the current OS supports this). */
|
||||
void showInfoBubble (const String& title, const String& content);
|
||||
|
||||
/** Hides the icon's floating text bubble (if the current OS supports this). */
|
||||
void hideInfoBubble();
|
||||
|
||||
/** Returns the raw handle to whatever kind of internal OS structure is
|
||||
involved in showing this icon.
|
||||
@see ComponentPeer::getNativeHandle()
|
||||
*/
|
||||
void* getNativeHandle() const;
|
||||
|
||||
#if JUCE_LINUX
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ extern Display* display;
|
|||
class SystemTrayIconComponent::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const Image& image_, Window windowH)
|
||||
: image (image_)
|
||||
Pimpl (const Image& im, Window windowH) : image (im)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
|
||||
|
|
@ -117,7 +116,27 @@ void SystemTrayIconComponent::paint (Graphics& g)
|
|||
RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize, false);
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::setIconTooltip (const String& /* tooltip */)
|
||||
void SystemTrayIconComponent::setIconTooltip (const String& /*tooltip*/)
|
||||
{
|
||||
// xxx not yet implemented!
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::setHighlighted (bool)
|
||||
{
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
|
||||
{
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::hideInfoBubble()
|
||||
{
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void* SystemTrayIconComponent::getNativeHandle() const
|
||||
{
|
||||
return getWindowHandle();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ public:
|
|||
|
||||
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain];
|
||||
[statusItem setView: view];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: view
|
||||
selector: @selector (frameChanged:)
|
||||
name: NSWindowDidMoveNotification
|
||||
object: nil];
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
|
|
@ -88,10 +93,6 @@ public:
|
|||
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());
|
||||
|
||||
MouseInputSource mouseSource = Desktop::getInstance().getMainMouseSource();
|
||||
|
|
@ -117,9 +118,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SystemTrayIconComponent& owner;
|
||||
NSStatusItem* statusItem;
|
||||
|
||||
private:
|
||||
NSImage* statusIcon;
|
||||
NSControl* view;
|
||||
bool isHighlighted;
|
||||
|
|
@ -139,6 +141,7 @@ private:
|
|||
addMethod (@selector (mouseDown:), handleEventDown, "v@:@");
|
||||
addMethod (@selector (rightMouseDown:), handleEventDown, "v@:@");
|
||||
addMethod (@selector (drawRect:), drawRect, "v@:@");
|
||||
addMethod (@selector (frameChanged:), frameChanged, "v@:@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
|
@ -178,6 +181,17 @@ private:
|
|||
fraction: 1.0f];
|
||||
}
|
||||
}
|
||||
|
||||
static void frameChanged (id self, SEL, NSNotification*)
|
||||
{
|
||||
if (Pimpl* const owner = getOwner (self))
|
||||
{
|
||||
NSRect r = [[[owner->statusItem view] window] frame];
|
||||
NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame];
|
||||
r.origin.y = sr.size.height - r.origin.y - r.size.height;
|
||||
owner->owner.setBounds (convertToRectInt (r));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
|
|
@ -204,3 +218,24 @@ void SystemTrayIconComponent::setIconTooltip (const String&)
|
|||
{
|
||||
// xxx not yet implemented!
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::setHighlighted (bool highlight)
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
pimpl->setHighlighted (highlight);
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
|
||||
{
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::hideInfoBubble()
|
||||
{
|
||||
// xxx Not implemented!
|
||||
}
|
||||
|
||||
void* SystemTrayIconComponent::getNativeHandle() const
|
||||
{
|
||||
return pimpl != nullptr ? pimpl->statusItem : nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public:
|
|||
iconData.uCallbackMessage = WM_TRAYNOTIFY;
|
||||
iconData.hIcon = hicon;
|
||||
|
||||
Shell_NotifyIcon (NIM_ADD, &iconData);
|
||||
notify (NIM_ADD);
|
||||
|
||||
// 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)
|
||||
|
|
@ -64,7 +64,7 @@ public:
|
|||
SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
|
||||
|
||||
iconData.uFlags = 0;
|
||||
Shell_NotifyIcon (NIM_DELETE, &iconData);
|
||||
notify (NIM_DELETE);
|
||||
DestroyIcon (iconData.hIcon);
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public:
|
|||
|
||||
iconData.hIcon = hicon;
|
||||
iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||
Shell_NotifyIcon (NIM_MODIFY, &iconData);
|
||||
notify (NIM_MODIFY);
|
||||
|
||||
DestroyIcon (oldIcon);
|
||||
}
|
||||
|
|
@ -83,7 +83,7 @@ public:
|
|||
{
|
||||
iconData.uFlags = NIF_TIP;
|
||||
toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
|
||||
Shell_NotifyIcon (NIM_MODIFY, &iconData);
|
||||
notify (NIM_MODIFY);
|
||||
}
|
||||
|
||||
void handleTaskBarEvent (const LPARAM lParam)
|
||||
|
|
@ -162,19 +162,30 @@ public:
|
|||
else if (message == taskbarCreatedMessage)
|
||||
{
|
||||
iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||
Shell_NotifyIcon (NIM_ADD, &iconData);
|
||||
notify (NIM_ADD);
|
||||
}
|
||||
|
||||
return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
private:
|
||||
void showBubble (const String& title, const String& content)
|
||||
{
|
||||
iconData.uFlags = 0x10 /*NIF_INFO*/;
|
||||
title.copyToUTF16 (iconData.szInfoTitle, sizeof (iconData.szInfoTitle) - 1);
|
||||
content.copyToUTF16 (iconData.szInfo, sizeof (iconData.szInfo) - 1);
|
||||
notify (NIM_MODIFY);
|
||||
}
|
||||
|
||||
SystemTrayIconComponent& owner;
|
||||
NOTIFYICONDATA iconData;
|
||||
|
||||
private:
|
||||
WNDPROC originalWndProc;
|
||||
const DWORD taskbarCreatedMessage;
|
||||
enum { WM_TRAYNOTIFY = WM_USER + 100 };
|
||||
|
||||
void notify (DWORD message) noexcept { Shell_NotifyIcon (message, &iconData); }
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
|
|
@ -201,3 +212,24 @@ void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
|
|||
if (pimpl != nullptr)
|
||||
pimpl->setToolTip (tooltip);
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::setHighlighted (bool)
|
||||
{
|
||||
// N/A on Windows.
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::showInfoBubble (const String& title, const String& content)
|
||||
{
|
||||
if (pimpl != nullptr)
|
||||
pimpl->showBubble (title, content);
|
||||
}
|
||||
|
||||
void SystemTrayIconComponent::hideInfoBubble()
|
||||
{
|
||||
showInfoBubble (String::empty, String::empty);
|
||||
}
|
||||
|
||||
void* SystemTrayIconComponent::getNativeHandle() const
|
||||
{
|
||||
return pimpl != nullptr ? &(pimpl->iconData) : nullptr;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue