|  | /*
  ==============================================================================
   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 IconConverters
{
    extern HICON createHICONFromImage (const Image& image, const BOOL isIcon, int hotspotX, int hotspotY);
}
//==============================================================================
class SystemTrayIconComponent::Pimpl
{
public:
    Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
        : owner (owner_),
          originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
          taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
    {
        SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
        zerostruct (iconData);
        iconData.cbSize = sizeof (iconData);
        iconData.hWnd = hwnd;
        iconData.uID = (UINT) (pointer_sized_int) hwnd;
        iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
        iconData.uCallbackMessage = WM_TRAYNOTIFY;
        iconData.hIcon = hicon;
        Shell_NotifyIcon (NIM_ADD, &iconData);
    }
    ~Pimpl()
    {
        SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
        iconData.uFlags = 0;
        Shell_NotifyIcon (NIM_DELETE, &iconData);
        DestroyIcon (iconData.hIcon);
    }
    void updateIcon (HICON hicon)
    {
        HICON oldIcon = iconData.hIcon;
        iconData.hIcon = hicon;
        iconData.uFlags = NIF_ICON;
        Shell_NotifyIcon (NIM_MODIFY, &iconData);
        DestroyIcon (oldIcon);
    }
    void setToolTip (const String& toolTip)
    {
        iconData.uFlags = NIF_TIP;
        toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
        Shell_NotifyIcon (NIM_MODIFY, &iconData);
    }
    void handleTaskBarEvent (const LPARAM lParam)
    {
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
        {
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
                 || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
            {
                Component* const current = Component::getCurrentlyModalComponent();
                if (current != nullptr)
                    current->inputAttemptWhenModal();
            }
        }
        else
        {
            ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
            if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
                eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
            else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
                eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
                eventMods = eventMods.withoutMouseButtons();
            const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
                                Point<int>(), eventMods, &owner, &owner, Time (getMouseEventTime()),
                                Point<int>(), Time (getMouseEventTime()), 1, false);
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
            {
                SetFocus (iconData.hWnd);
                SetForegroundWindow (iconData.hWnd);
                owner.mouseDown (e);
            }
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
            {
                owner.mouseUp (e);
            }
            else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
            {
                owner.mouseDoubleClick (e);
            }
            else if (lParam == WM_MOUSEMOVE)
            {
                owner.mouseMove (e);
            }
        }
    }
    static Pimpl* getPimpl (HWND 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)
                    return iconComp->pimpl;
            }
        }
        return nullptr;
    }
    static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        Pimpl* const p = getPimpl (hwnd);
        if (p != nullptr)
            return p->windowProc  (hwnd, message, wParam, lParam);
        else
            return DefWindowProcW (hwnd, message, wParam, lParam);
   }
    LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if (message == WM_TRAYNOTIFY)
        {
            handleTaskBarEvent (lParam);
        }
        else if (message == taskbarCreatedMessage)
        {
            iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
            Shell_NotifyIcon (NIM_ADD, &iconData);
        }
        return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
    }
private:
    SystemTrayIconComponent& owner;
    NOTIFYICONDATA iconData;
    WNDPROC originalWndProc;
    const DWORD taskbarCreatedMessage;
    enum { WM_TRAYNOTIFY = WM_USER + 100 };
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl);
};
//==============================================================================
void SystemTrayIconComponent::setIconImage (const Image& newImage)
{
    if (newImage.isValid())
    {
        HICON hicon = IconConverters::createHICONFromImage (newImage, TRUE, 0, 0);
        if (pimpl == nullptr)
            pimpl = new Pimpl (*this, hicon, (HWND) getWindowHandle());
        else
            pimpl->updateIcon (hicon);
    }
    else
    {
        pimpl = nullptr;
    }
}
void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
{
    if (pimpl != nullptr)
        pimpl->setToolTip (tooltip);
}
 |