wxTaskBarIcon with Balloon tooltips!

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia »

I don't know how you do in wxDevCpp 6.10, but I guess you can search the file shellapi.h on your system and look whether it has definition for NIIF_INFO or not, if not, then download the latest platform SDK from microsoft and update your adv project by adding a preprocessor _WIN32_IE=0x600 and then recompile the adv project. You can use the free Microsoft Visual Studio 2005 Express for that.
Mr.shi
Earned a small fee
Earned a small fee
Posts: 13
Joined: Fri Jul 13, 2007 3:05 am

Post by Mr.shi »

Code: Select all

/////////////////////////////////////////////////////////////////////////
// File:        taskbar.cpp
// Purpose:     Implements wxTaskBarIconEx class for manipulating icons on
//              the Windows task bar.
// Author:      Julian Smart
// Modified by:
// Created:     24/3/98
// RCS-ID:      $Id: taskbarex.cpp 11913 2007-01-19 23:45:19Z rwalton $
// Copyright:   (c)
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "taskbarex.h"
#endif

#include "stdwx.h"
#include "BOINCGUIApp.h"
#include "msw/taskbarex.h"
#include "BOINCTaskBar.h"


LRESULT APIENTRY wxTaskBarIconExWindowProc( HWND hWnd, unsigned msg, UINT wParam, LONG lParam );

wxChar* wxTaskBarExWindowClass = (wxChar*) wxT("wxTaskBarExWindowClass");
wxChar* wxTaskBarExWindow = (wxChar*) wxT("wxTaskBarExWindow");

const UINT WM_TASKBARCREATED   = ::RegisterWindowMessage(wxT("TaskbarCreated"));
const UINT WM_TASKBARSHUTDOWN  = ::RegisterWindowMessage(wxT("TaskbarShutdown"));

bool   wxTaskBarIconEx::sm_registeredClass = FALSE;
UINT   wxTaskBarIconEx::sm_taskbarMsg = 0;

DEFINE_EVENT_TYPE( wxEVT_TASKBAR_CREATED )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_CONTEXT_MENU )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_SELECT )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_KEY_SELECT )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_SHOW )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_HIDE )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_TIMEOUT )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_USERCLICK )
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_SHUTDOWN )

IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIconEx, wxEvtHandler)

BEGIN_EVENT_TABLE (wxTaskBarIconEx, wxEvtHandler)
    EVT_CLOSE(wxTaskBarIconEx::OnClose)
    EVT_TASKBAR_CREATED(wxTaskBarIconEx::OnTaskBarCreated)
END_EVENT_TABLE ()


wxTaskBarIconEx::wxTaskBarIconEx(void)
{
    m_hWnd = 0;
    m_iconAdded = FALSE;

    if (RegisterWindowClass())
        m_hWnd = CreateTaskBarWindow( wxTaskBarExWindow );
}

wxTaskBarIconEx::wxTaskBarIconEx( wxChar* szWindowTitle )
{
    m_hWnd = 0;
    m_iconAdded = FALSE;

    if (RegisterWindowClass())
        m_hWnd = CreateTaskBarWindow( szWindowTitle );
}

wxTaskBarIconEx::~wxTaskBarIconEx(void)
{
    if (m_iconAdded)
    {
        RemoveIcon();
    }

    if (m_hWnd)
    {
        ::DestroyWindow((HWND) m_hWnd);
        m_hWnd = 0;
    }
}

// Events
void wxTaskBarIconEx::OnClose(wxCloseEvent& WXUNUSED(event))
{
    wxLogTrace(wxT("Function Start/End"), wxT("wxTaskBarIconEx::OnClose - Function Begin"));

    ::DestroyWindow((HWND) m_hWnd);
    m_hWnd = 0;

    wxLogTrace(wxT("Function Start/End"), wxT("wxTaskBarIconEx::OnClose - Function End"));
}

void wxTaskBarIconEx::OnTaskBarCreated(wxTaskBarIconExEvent& WXUNUSED(event))
{
    m_iconAdded = (Shell_NotifyIcon(NIM_ADD, &notifyData) != 0);
    Shell_NotifyIcon(NIM_SETVERSION, &notifyData);
}

// Operations
bool wxTaskBarIconEx::SetIcon(const wxIcon& icon, const wxString& tooltip)
{
    if (!IsOK())
        return FALSE;

    memset(&notifyData, 0, sizeof(notifyData));
    notifyData.cbSize           = sizeof(notifyData);
    notifyData.hWnd             = (HWND) m_hWnd;
    notifyData.uID              = 99;
    notifyData.uCallbackMessage = sm_taskbarMsg;
    notifyData.uFlags           = NIF_MESSAGE;
    notifyData.uVersion         = NOTIFYICON_VERSION;

    if (icon.Ok())
    {
        notifyData.uFlags |= NIF_ICON;
        notifyData.hIcon = (HICON) icon.GetHICON();
    }

    if (((const wxChar*) tooltip != NULL) && (tooltip != wxT("")))
    {
        notifyData.uFlags |= NIF_TIP ;
        lstrcpyn(notifyData.szTip, WXSTRINGCAST tooltip, sizeof(notifyData.szTip));
    }


    if (m_iconAdded)
        return (Shell_NotifyIcon(NIM_MODIFY, &notifyData) != 0);
    else
    {
        m_iconAdded = (Shell_NotifyIcon(NIM_ADD, &notifyData) != 0);
        if (IsBalloonsSupported())
            Shell_NotifyIcon(NIM_SETVERSION, &notifyData);
        return m_iconAdded;
    }
}

bool wxTaskBarIconEx::SetBalloon(const wxIcon& icon, const wxString title, const wxString message, unsigned int timeout, unsigned int iconballoon)
{
    if (!IsOK())
        return false;

    wxString strTip = wxEmptyString;

    if (!IsBalloonsSupported())
        strTip = title + wxT(" - ") + message;

    memset(&notifyData, 0, sizeof(notifyData));
    notifyData.cbSize           = sizeof(notifyData);
    notifyData.hWnd             = (HWND) m_hWnd;
    notifyData.uID              = 99;
    notifyData.uCallbackMessage = sm_taskbarMsg;
    notifyData.uFlags           = NIF_MESSAGE;
    notifyData.dwInfoFlags      = iconballoon | NIIF_NOSOUND;
    notifyData.uTimeout         = timeout;
    notifyData.uVersion         = NOTIFYICON_VERSION;

    if (icon.Ok())
    {
        notifyData.uFlags |= NIF_ICON;
        notifyData.hIcon = (HICON) icon.GetHICON();
    }

    if (IsBalloonsSupported())
    {
        notifyData.uFlags |= NIF_INFO | NIF_TIP;
        lstrcpyn(notifyData.szInfo, WXSTRINGCAST message, sizeof(notifyData.szInfo));
        lstrcpyn(notifyData.szInfoTitle, WXSTRINGCAST title, sizeof(notifyData.szInfoTitle));
        lstrcpyn(notifyData.szTip, WXSTRINGCAST wxEmptyString, sizeof(notifyData.szTip));
    }
    else
    {
        notifyData.uFlags |= NIF_TIP;
        lstrcpyn(notifyData.szTip, WXSTRINGCAST strTip, sizeof(notifyData.szTip));
    }

    if (m_iconAdded)
        return (Shell_NotifyIcon(NIM_MODIFY, & notifyData) != 0);
    else
    {
        m_iconAdded = (Shell_NotifyIcon(NIM_ADD, & notifyData) != 0);
        if (IsBalloonsSupported())
            Shell_NotifyIcon(NIM_SETVERSION, &notifyData);
        return m_iconAdded;
    }
}

bool wxTaskBarIconEx::RemoveIcon(void)
{
    if (!m_iconAdded)
        return FALSE;

    memset(&notifyData, 0, sizeof(notifyData));
    notifyData.cbSize = sizeof(notifyData);
    notifyData.hWnd = (HWND) m_hWnd;
    notifyData.uCallbackMessage = sm_taskbarMsg;
    notifyData.uFlags = NIF_MESSAGE;
    notifyData.hIcon = 0 ; // hIcon;
    notifyData.uID = 99;
    m_iconAdded = FALSE;

    return (Shell_NotifyIcon(NIM_DELETE, & notifyData) != 0);
}

bool wxTaskBarIconEx::PopupMenu(wxMenu *menu) //, int x, int y);
{
    // OK, so I know this isn't thread-friendly, but
    // what to do? We need this check.

    static bool s_inPopup = FALSE;

    if (s_inPopup)
        return FALSE;

    s_inPopup = TRUE;

    bool        rval = FALSE;
    wxWindow*   win;
    int         x, y;
    wxGetMousePosition(&x, &y);

    // is wxFrame the best window type to use???
    win = new wxFrame(NULL, -1, wxEmptyString, wxPoint(x,y), wxSize(-1,-1), 0);
    win->PushEventHandler(this);

    // Remove from record of top-level windows, or will confuse wxWindows
    // if we try to exit right now.
    wxTopLevelWindows.DeleteObject(win);

    menu->UpdateUI();

    // Work around a WIN32 bug
    ::SetForegroundWindow ((HWND) win->GetHWND ());

    rval = win->PopupMenu(menu, 0, 0);

    // Work around a WIN32 bug
    ::PostMessage ((HWND) win->GetHWND(),WM_NULL,0,0L);

    win->PopEventHandler(FALSE);
    win->Destroy();
    delete win;

    s_inPopup = FALSE;

    return rval;
}


bool wxTaskBarIconEx::RegisterWindowClass()
{
    if (sm_registeredClass)
        return TRUE;

    // Also register the taskbar message here
    sm_taskbarMsg = ::RegisterWindowMessage(wxT("wxTaskBarIconExMessage"));

    WNDCLASS        wc;
    bool        rc;

    HINSTANCE hInstance = GetModuleHandle(NULL);

    /*
     * set up and register window class
     */
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC) wxTaskBarIconExWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = 0;
    wc.hCursor = 0;
    wc.hbrBackground = 0;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = wxTaskBarExWindowClass ;
    rc = (::RegisterClass( &wc ) != 0);

    sm_registeredClass = (rc != 0);

    return( (rc != 0) );
}

WXHWND wxTaskBarIconEx::CreateTaskBarWindow( wxChar* szWindowTitle )
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

    HWND hWnd = CreateWindowEx (0, wxTaskBarExWindowClass,
            szWindowTitle,
            WS_OVERLAPPED,
            0,
            0,
            10,
            10,
            NULL,
            (HMENU) 0,
            hInstance,
            NULL);

    return (WXHWND) hWnd;
}

bool wxTaskBarIconEx::IsBalloonsSupported()
{
#ifdef __WXMSW__
    wxInt32 iMajor = 0, iMinor = 0;
    if ( wxWINDOWS_NT == wxGetOsVersion( &iMajor, &iMinor ) )
    {
        if ( (5 >= iMajor) && (0 <= iMinor) )
            return true;
    }
#endif
    return false;
}

long wxTaskBarIconEx::WindowProc( WXHWND hWnd, unsigned int msg, unsigned int wParam, long lParam )
{
    wxLogTrace(wxT("Function Start/End"), wxT("wxTaskBarIconEx::WindowProc - Function Begin"));

    wxEventType eventType = 0;
    long        lReturnValue = 0;     

    if      ( WM_CLOSE == msg )
    {
        wxLogTrace(wxT("Function Status"), wxT("wxTaskBarIconEx::WindowProc - WM_CLOSE Detected"));
 
        wxCloseEvent eventClose(wxEVT_CLOSE_WINDOW);
        ProcessEvent(eventClose);

        if ( !eventClose.GetSkipped() )
            lReturnValue = DefWindowProc((HWND) hWnd, msg, wParam, lParam);
        else
            lReturnValue = 0;
    }
    else if ( WM_TASKBARCREATED == msg )
    {
        wxLogTrace(wxT("Function Status"), wxT("wxTaskBarIconEx::WindowProc - WM_TASKBARCREATED Detected"));
        eventType = wxEVT_TASKBAR_CREATED;
    }
    else if ( WM_TASKBARSHUTDOWN == msg )
    {
        wxLogTrace(wxT("Function Status"), wxT("wxTaskBarIconEx::WindowProc - WM_TASKBARSHUTDOWN Detected"));
        eventType = wxEVT_TASKBAR_SHUTDOWN;
    }
    if (msg != sm_taskbarMsg)
        lReturnValue = DefWindowProc((HWND) hWnd, msg, wParam, lParam);

    if ( 0 == eventType )
    {
        switch (lParam)
        {
            case WM_LBUTTONDOWN:
                eventType = wxEVT_TASKBAR_LEFT_DOWN;
                break;

            case WM_LBUTTONUP:
                eventType = wxEVT_TASKBAR_LEFT_UP;
                break;

            case WM_RBUTTONDOWN:
                eventType = wxEVT_TASKBAR_RIGHT_DOWN;
                break;

            case WM_RBUTTONUP:
                eventType = wxEVT_TASKBAR_RIGHT_UP;
                break;

            case WM_LBUTTONDBLCLK:
                eventType = wxEVT_TASKBAR_LEFT_DCLICK;
                break;

            case WM_RBUTTONDBLCLK:
                eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
                break;

            case WM_MOUSEMOVE:
                eventType = wxEVT_TASKBAR_MOVE;
                break;

            case WM_CONTEXTMENU:
                eventType = wxEVT_TASKBAR_CONTEXT_MENU;
                break;

            case NIN_SELECT:
                eventType = wxEVT_TASKBAR_SELECT;
                break;

            case NIN_KEYSELECT:
                eventType = wxEVT_TASKBAR_KEY_SELECT;
                break;

            case NIN_BALLOONSHOW:
                eventType = wxEVT_TASKBAR_BALLOON_SHOW;
                break;

            case NIN_BALLOONHIDE:
                eventType = wxEVT_TASKBAR_BALLOON_HIDE;
                break;

            case NIN_BALLOONTIMEOUT:
                eventType = wxEVT_TASKBAR_BALLOON_TIMEOUT;
                break;

            case NIN_BALLOONUSERCLICK:
                eventType = wxEVT_TASKBAR_BALLOON_USERCLICK;
                break;
        }
    }

    if (eventType)
    {
        wxTaskBarIconExEvent event(eventType, this);
        ProcessEvent(event);

        lReturnValue = 0;
    }

    wxLogTrace(wxT("Function Start/End"), wxT("wxTaskBarIconEx::WindowProc - Function End"));
    return lReturnValue;
}

LRESULT APIENTRY wxTaskBarIconExWindowProc( HWND hWnd, unsigned msg, UINT wParam, LONG lParam )
{
    return wxGetApp().GetTaskBarIcon()->WindowProc((WXHWND) hWnd, msg, wParam, lParam);
}


const char *BOINC_RCSID_46d006c50e = "$Id: taskbarex.cpp 11913 2007-01-19 23:45:19Z rwalton $";

Code: Select all

/////////////////////////////////////////////////////////////////////////
// File:        wx/msw/taskbar.h
// Purpose:     Defines wxTaskBarIcon class for manipulating icons on the
//              Windows task bar.
// Author:      Julian Smart
// Modified by:
// Created:     24/3/98
// RCS-ID:      $Id: taskbarex.h 12240 2007-03-17 19:37:56Z rwalton $
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////

#ifndef _TASKBAREX_H_
#define _TASKBAREX_H_

#if defined(__GNUG__) && !defined(__APPLE__)
#pragma interface "taskbarex.cpp"
#endif


// ----------------------------------------------------------------------------
// wxTaskBarIconEx 
// ----------------------------------------------------------------------------

class wxTaskBarIconExEvent;

class wxTaskBarIconEx: public wxEvtHandler {
    DECLARE_DYNAMIC_CLASS(wxTaskBarIconEx)
public:

    wxTaskBarIconEx(void);
    wxTaskBarIconEx( wxChar* szWindowTitle );

    virtual ~wxTaskBarIconEx(void);

// Events
    virtual void OnClose( wxCloseEvent& event );
    virtual void OnTaskBarCreated( wxTaskBarIconExEvent& event );

// Accessors
    inline WXHWND GetHWND() const { return m_hWnd; }
    inline bool IsOK() const { return (m_hWnd != 0) ; }
    inline bool IsIconInstalled() const { return m_iconAdded; }

// Operations

    bool SetIcon(
        const wxIcon& icon,
        const wxString& tooltip = wxEmptyString
    );

    bool SetBalloon(
        const wxIcon& icon, 
        const wxString title = wxEmptyString,
        const wxString message = wxEmptyString,
        unsigned int timeout = 5000,
        unsigned int iconballoon = NIIF_INFO
    );

    bool RemoveIcon();

    bool PopupMenu(wxMenu *menu); //, int x, int y);

// Implementation
    static bool RegisterWindowClass();
    static WXHWND CreateTaskBarWindow( wxChar* szWindowTitle );
    static bool IsBalloonsSupported();
    long WindowProc( WXHWND hWnd, unsigned int msg, unsigned int wParam, long lParam );

// Data members
protected:
    WXHWND          m_hWnd;
    bool            m_iconAdded;
    NOTIFYICONDATA  notifyData;
    static bool     sm_registeredClass;
    static unsigned int sm_taskbarMsg;

private:
    DECLARE_EVENT_TABLE()

};


// ----------------------------------------------------------------------------
// wxTaskBarIconEx events
// ----------------------------------------------------------------------------

class wxTaskBarIconExEvent : public wxEvent
{
public:
    wxTaskBarIconExEvent(wxEventType evtType, wxTaskBarIconEx *tbIcon)
        : wxEvent(wxID_ANY, evtType)
        {
            SetEventObject(tbIcon);
        }

    virtual wxEvent *Clone() const { return new wxTaskBarIconExEvent(*this); }
};

BEGIN_DECLARE_EVENT_TYPES()
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_CREATED, 1557 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_CONTEXT_MENU, 1558 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_SELECT, 1559 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_KEY_SELECT, 1560 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_SHOW, 1561 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_HIDE, 1562 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_TIMEOUT, 1563 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_USERCLICK, 1564 )
    DECLARE_EVENT_TYPE( wxEVT_TASKBAR_SHUTDOWN, 1565 )
END_DECLARE_EVENT_TYPES()

typedef void (wxEvtHandler::*wxTaskBarIconExEventFunction)(wxTaskBarIconExEvent&);

#define wxTaskBarIconExEventHandler(func) \
    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxTaskBarIconExEventFunction, &func)

#define wx__DECLARE_TASKBAREXEVT(evt, fn) \
    wx__DECLARE_EVT0(wxEVT_TASKBAR_ ## evt, wxTaskBarIconExEventHandler(fn))

#define EVT_TASKBAR_CREATED(fn)              wx__DECLARE_TASKBAREXEVT(CREATED, fn)
#define EVT_TASKBAR_CONTEXT_MENU(fn)         wx__DECLARE_TASKBAREXEVT(CONTEXT_MENU, fn)
#define EVT_TASKBAR_SELECT(fn)               wx__DECLARE_TASKBAREXEVT(SELECT, fn)
#define EVT_TASKBAR_KEY_SELECT(fn)           wx__DECLARE_TASKBAREXEVT(KEY_SELECT, fn)
#define EVT_TASKBAR_BALLOON_SHOW(fn)         wx__DECLARE_TASKBAREXEVT(BALLOON_SHOW, fn)
#define EVT_TASKBAR_BALLOON_HIDE(fn)         wx__DECLARE_TASKBAREXEVT(BALLOON_HIDE, fn)
#define EVT_TASKBAR_BALLOON_TIMEOUT(fn)      wx__DECLARE_TASKBAREXEVT(BALLOON_TIMEOUT, fn)
#define EVT_TASKBAR_CONTEXT_USERCLICK(fn)    wx__DECLARE_TASKBAREXEVT(BALLOON_USERCLICK, fn)
#define EVT_TASKBAR_SHUTDOWN(fn)             wx__DECLARE_TASKBAREXEVT(SHUTDOWN, fn)


#endif
    // _TASKBAR_H_
zhouhao
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2005 7:02 am

Post by zhouhao »

lowjoel wrote:OK guys this is the latest patch. This version allows for event handling to be done (took me half a day to solve the mystery of the undefined symbol :P)

Code: Select all

Index: include/wx/taskbar.h
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/include/wx/taskbar.h,v
retrieving revision 1.26
diff -u -r1.26 taskbar.h
--- include/wx/taskbar.h	2005/05/04 18:52:03	1.26
+++ include/wx/taskbar.h	2005/08/03 03:42:59
@@ -18,6 +18,13 @@
 
 #include "wx/event.h"
 
+//Balloon Tooltips messages sent by the shell for MSW
+#ifndef NIN_BALLOONSHOW
+	#define NIN_BALLOONSHOW 1026
+	#define NIN_BALLOONHIDE 1028
+	#define NIN_BALLOONUSERCLICK 1029
+#endif
+
 class WXDLLIMPEXP_ADV wxTaskBarIconEvent;
 
 // ----------------------------------------------------------------------------
@@ -93,6 +100,9 @@
     DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_RIGHT_UP,1554)
     DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_LEFT_DCLICK,1555)
     DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_RIGHT_DCLICK,1556)
+    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_BALLOON_SHOW,1557)
+    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_BALLOON_HIDE,1558)
+    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_ADV,wxEVT_TASKBAR_BALLOON_CLICK,1559)
 END_DECLARE_EVENT_TYPES()
 
 #define wxTaskBarIconEventHandler(func) \
@@ -108,6 +118,11 @@
 #define EVT_TASKBAR_RIGHT_UP(fn)     wx__DECLARE_TASKBAREVT(RIGHT_UP, fn)
 #define EVT_TASKBAR_LEFT_DCLICK(fn)  wx__DECLARE_TASKBAREVT(LEFT_DCLICK, fn)
 #define EVT_TASKBAR_RIGHT_DCLICK(fn) wx__DECLARE_TASKBAREVT(RIGHT_DCLICK, fn)
+
+//MSW only events
+#define EVT_TASKBAR_BALLOON_SHOW(fn)  wx__DECLARE_TASKBAREVT(BALLOON_SHOW, fn)
+#define EVT_TASKBAR_BALLOON_HIDE(fn)  wx__DECLARE_TASKBAREVT(BALLOON_HIDE, fn)
+#define EVT_TASKBAR_BALLOON_CLICK(fn) wx__DECLARE_TASKBAREVT(BALLOON_CLICK, fn)
 
 #endif
     // wxHAS_TASK_BAR_ICON

Index: include/wx/msw/taskbar.h
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/include/wx/msw/taskbar.h,v
retrieving revision 1.24
diff -u -r1.24 taskbar.h
--- include/wx/msw/taskbar.h	2004/09/07 06:00:52	1.24
+++ include/wx/msw/taskbar.h	2005/08/03 04:56:17
@@ -17,6 +17,7 @@
 #pragma interface "taskbar.h"
 #endif
 
+#include <shellapi.h>
 #include "wx/icon.h"
 
 // private helper class:
@@ -37,6 +38,7 @@
     bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxEmptyString);
     bool RemoveIcon(void);
     bool PopupMenu(wxMenu *menu); //, int x, int y);
+    bool ShowBalloon(wxString title, wxString message, unsigned int timeout = 10000, int icon = NIIF_INFO);
 
 #if WXWIN_COMPATIBILITY_2_4
     wxDEPRECATED( bool IsOK() const );

Index: src/common/taskbarcmn.cpp
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/src/common/taskbarcmn.cpp,v
retrieving revision 1.10
diff -u -r1.10 taskbarcmn.cpp
--- src/common/taskbarcmn.cpp	2004/09/23 18:20:54	1.10
+++ src/common/taskbarcmn.cpp	2005/08/03 03:57:13
@@ -35,6 +35,9 @@
 DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_UP )
 DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_DCLICK )
 DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_DCLICK )
+DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_CLICK )
+DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_HIDE )
+DEFINE_EVENT_TYPE( wxEVT_TASKBAR_BALLOON_SHOW )
 
 
 BEGIN_EVENT_TABLE(wxTaskBarIconBase, wxEvtHandler)

Index: src/msw/taskbar.cpp
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/src/msw/taskbar.cpp,v
retrieving revision 1.46
diff -u -r1.46 taskbar.cpp
--- src/msw/taskbar.cpp	2005/05/31 09:20:33	1.46
+++ src/msw/taskbar.cpp	2005/08/03 04:56:05
@@ -165,7 +165,6 @@
     if ( !tooltip.empty() )
     {
         notifyData.uFlags |= NIF_TIP;
-//        lstrcpyn(notifyData.szTip, tooltip.c_str(), WXSIZEOF(notifyData.szTip));
         wxStrncpy(notifyData.szTip, tooltip.c_str(), WXSIZEOF(notifyData.szTip));
     }
 
@@ -315,9 +314,26 @@
         case WM_MOUSEMOVE:
             eventType = wxEVT_TASKBAR_MOVE;
             break;
-
+        
+        case NIN_BALLOONSHOW:
+			//NIN_BALLOONSHOW - Sent when the balloon is shown (balloons are queued).
+			eventType = wxEVT_TASKBAR_BALLOON_SHOW;
+			break;
+		
+		case NIN_BALLOONHIDE:
+			//NIN_BALLOONHIDE - Sent when the balloon disappears - for example, when the
+			//icon is deleted. This message is not sent if the balloon is dismissed
+			//because of a timeout or a mouse click.
+			eventType = wxEVT_TASKBAR_BALLOON_HIDE;
+			break;
+		
+		case NIN_BALLOONUSERCLICK:
+			//NIN_BALLOONUSERCLICK - Sent when the balloon is dismissed because of a mouse click.
+			eventType = wxEVT_TASKBAR_BALLOON_CLICK;
+			break;
+		
         default:
-            break;
+			break;
     }
 
     if (eventType)
@@ -328,6 +344,25 @@
     }
 
     return 0;
+}
+
+bool wxTaskBarIcon::ShowBalloon(wxString title, wxString message, unsigned int timeout, int icon)
+{
+	if (!IsOk())
+	    return false;
+
+	NotifyIconData notifyData((HWND)m_win->GetHWND());
+    notifyData.uFlags = NIF_INFO;
+
+    wxStrncpy(notifyData.szInfo, message.c_str(), WXSIZEOF(notifyData.szInfo));
+    wxStrncpy(notifyData.szInfoTitle, title.c_str(), WXSIZEOF(notifyData.szInfoTitle));
+    notifyData.dwInfoFlags = icon;
+    notifyData.uTimeout = timeout;
+	
+    if (m_iconAdded)
+	    return Shell_NotifyIcon(NIM_MODIFY, &notifyData);
+    else
+        return false;
 }
 
 #endif // __WIN95__
EVT_TASKBAR_BALLOON_SHOW will be triggered when the ballon is shown (ballons take turns to be shown)
EVT_TASKBAR_BALLOON_HIDE will be triggered when the balloon is deleted by the program. It isnt sent when the user dismisses the balloon
EVT_TASKBAR_BALLOON_CLICK will be triggered when the user clicks on the balloon
How does ShowBallon works? I use the following code in my OnInit. But no balloon is shown.

Code: Select all

	taskbar.SetIcon(wxICON(amain),_T("This is a testing"));	
	taskbar.ShowBalloon(_T("This is a test"),_T("This is a testing message"),10000,NIIF_INFO);

Any idea?
Plazzmex
In need of some credit
In need of some credit
Posts: 8
Joined: Tue May 08, 2007 1:11 pm

Post by Plazzmex »

hi..
I have some errors with NOTIFYICONDATA struct.
I've tried anything but the problem is still there.
I'm using wxDev-c++ 6.10.2 with minGW 3.4.5
when i'm trying to create a balloontip in the compilation it says me:

Code: Select all

In function `WindowProcedure': 
structure has no member named `uTimeout' 
structure has no member named `szInfoTitle'
structure has no member named `szInfo'
the i've tried to write this to the resource file

Code: Select all

define _WIN32_IE 0x0501
but its still don'w work.. and now i have some conflict in definition of _WIN32_IE cause i need to write in the source file this

Code: Select all

#ifndef _WIN32_IE
#define _WIN32_IE 0x0300
#endif
cause if i don't it says me [Warning] implicit declaration of function `InitCommonControlsEx'

when i write just define _WIN32_IE 0x0501 and delete the _WIN32_IE 0x0300 the program compiles good without errors but the balloontip doesn't work anyway..

how to fix this ?
thanks..
Rayman
Earned a small fee
Earned a small fee
Posts: 10
Joined: Wed Jul 16, 2008 9:48 pm
Contact:

Post by Rayman »

I used the information here to adopt my code to generate ballon tooltips by my application. This worked perfect until wxwidgets version 2.8.6!

Unfortunately, my code stoped working when going to wxwidgets 2.8.8. The behavior when entering the ballon routine is as follows: The system tray adds an 'empty' icon field and the ballon tooltip is NOT shown (formerly it was). After the timeout the empty field is removed.

Here is the code which stopped working after 2.8.6:

Code: Select all

bool TaskBarIcon::ShowBalloonTip(wxString title, wxString message, unsigned int timeout, int icon)
{
	NOTIFYICONDATA 	notifyData;
	wxIcon			tool_icon(tool_xpm);

	memset(&notifyData, 0, sizeof(NOTIFYICONDATA));
	notifyData.cbSize = sizeof(NOTIFYICONDATA);
  	notifyData.uFlags = NIF_INFO | NIF_MESSAGE;
	notifyData.hWnd = (HWND) parent->GetHWND();
	notifyData.uID = 99;
  	notifyData.uTimeout = timeout;
  	notifyData.hIcon = (HICON) tool_icon.GetHICON();
	notifyData.dwInfoFlags = icon | NIIF_NOSOUND | NIIF_INFO;

	wxStrncpy(notifyData.szInfo, message.c_str(), WXSIZEOF(notifyData.szInfo));
	wxStrncpy(notifyData.szInfoTitle, title.c_str(), WXSIZEOF(notifyData.szInfoTitle));

	Shell_NotifyIcon(NIM_ADD, &notifyData);

	wxSleep((int) (timeout / 100.0));

	return (Shell_NotifyIcon(NIM_DELETE, &notifyData) != 0);
}
Could anyone please guide me why this is not working anymore? Were there changes regarding this in wxwidgets releases after 2.8.6?

My platform is Windows XP (SP3) and MinGW/gcc.

Edit (2008-07-29): I've modified the taskbar sample which comes with wxwidgets (./samples/taskbar) and included the above function. The code compiled with the corresponding makefile and wxwidgets 2.8.4 works, the balloon tooltip is shown. The same code compiled with 2.8.8 doesnt work.

Thanks,
Stefan.
Last edited by Rayman on Sat Aug 30, 2008 2:04 pm, edited 1 time in total.
TrV
Ultimate wxWidgets Guru
Ultimate wxWidgets Guru
Posts: 630
Joined: Wed Jul 04, 2007 1:12 pm

Post by TrV »

Rayman wrote:Could anybody please test and verify this behaviour?
I've tested your binaries :
- the 2.8.4 version works (i mean balloon tips work)
- the 2.8.8 does not work
Rayman
Earned a small fee
Earned a small fee
Posts: 10
Joined: Wed Jul 16, 2008 9:48 pm
Contact:

Post by Rayman »

Meanwhile I found out what's wrong. The misbehaviour only appears with MinGW 3.4.5 and thus is independent of the wxWidgets version.

The balloon tooltip behaviour depends on the definitions of the NOTIFYICONDATA struct in shellapi.h.

More information can be found here:

http://groups.google.de/group/comp.soft ... 555?hl=de#

Stefan.
blockn102
Experienced Solver
Experienced Solver
Posts: 70
Joined: Sat Oct 25, 2008 2:38 am

Post by blockn102 »

I think wxPopup is better than it.
??? year olds :)
blockn102
Experienced Solver
Experienced Solver
Posts: 70
Joined: Sat Oct 25, 2008 2:38 am

Post by blockn102 »

The best balloon tip implement.

https://balloontip.dev.java.net/

Image
??? year olds :)
NuSkooler
In need of some credit
In need of some credit
Posts: 8
Joined: Sat Sep 29, 2007 6:42 pm
Location: UT, USA

Post by NuSkooler »

I have created a replacement wxTaskBarIcon class (wxTaskBarIconEx) that has support for balloon tips and enhanced functionality found in newer versions of Windows (large icons for e.g.). Due to time, I have yet to attempt to merge any of wxWidgets as a complete replacement. The class works on 2k+.

Hopefully this can be useful to someone and/or can be built upon.

Code: Select all

#ifndef __WX_MSW_TASKBAR_ICON_EX__
#define __WX_MSW_TASKBAR_ICON_EX__

#if defined(__GNUG__) && !defined(__APPLE__)
	#pragma interface "wxMswTaskbarIconEx.cpp"
#endif	//	defined(__GNUG__) && !defined(__APPLE__)

#if defined(_MSC_VER)
	#pragma warning(push)
	#pragma warning(disable:4251)
#endif	//	defined(_MSC_VER)

#include <wx/wx.h>
#include <wx/taskbar.h>

#if defined(_MSC_VER)
	#pragma warning(pop)
#endif	//	defined(_MSC_VER)

//	forwards
class wxMswTaskBarIconExWindow;

///////////////////////////////////////////////////////////////////////////////
//	wxMswTaskBarIconEx
///////////////////////////////////////////////////////////////////////////////

enum EWxMswTaskBarIconExFeatures {
	//
	//	Feature sets supported. Keep these in order!
	//	Also note that this class doesn't attempt to work with < Win2k
	//
	wxMSW_TASKBAREX_FEATURES_2K_PLUS		= 1,
	wxMSW_TASKBAREX_FEATURES_XP_PLUS		= 2,
	wxMSW_TASKBAREX_FEATURES_XP_SP2_PLUS	= 3,
	wxMSW_TASKBAREX_FEATURES_VISTA_PLUS		= 4,
	wxMSW_TASKBAREX_FEATURES_WIN7_PLUS		= 5,
};

//
//	Our own flags to cover NIIF_* flags
//
enum EWxMswTaskBarIconExShowBalloonFlags {
	wxMSW_TASKBAREX_SB_NONE					= 0x00000000,	//	NIIF_NONE

	//	icon flags - mutually exclusive
	wxMSW_TASKBAREX_SB_INFO					= 0x00000001,	//	NIIF_INFO
	wxMSW_TASKBAREX_SB_WARNING				= 0x00000002,	//	NIIF_WARNING
	wxMSW_TASKBAREX_SB_ERROR				= 0x00000003,	//	NIIF_ERROR

	wxMSW_TASKBAREX_SB_NOSOUND				= 0x00000010,	//	NIIF_NOSOUND (XPSP2+)
	wxMSW_TASKBAREX_SB_LARGE_ICON			= 0x00000020,	//	NIIF_LARGE_ICON (Vista+); wxIcon must be a large icon
	wxMSW_TASKBAREX_SB_RESPECT_QUIET_TIME	= 0x00000080,	//	NIIF_RESPECT_QUIET_TIME (Win7+)

	wxMSW_TASKBAREX_SB_DEFAULT			=
		(wxMSW_TASKBAREX_SB_NOSOUND | wxMSW_TASKBAREX_SB_RESPECT_QUIET_TIME)
};

//
//	Our own flags to replace NIF_* flags
//
enum EWxmswTaskBarIconExShowBalloonExFlags {
	wxMSW_TASKBAREX_SB_EX_NONE			= 0x00000000,
	wxMSW_TASKBAREX_SB_EX_REALTIME		= 0x00000001,
};

class wxMswTaskBarIconEx
	: public wxTaskBarIconBase
{
	DECLARE_DYNAMIC_CLASS(wxMswTaskBarIconEx)
public:
	static const unsigned int TIMEOUT_MIN	= 10000;	//	10s
	static const unsigned int TIMEOUT_MAX	= 30000;	//	30s

	wxMswTaskBarIconEx();
	~wxMswTaskBarIconEx();

	//	wxTaskBarIconBase virtuals
	virtual bool SetIcon(const wxIcon& icon,
		const wxString& tooltip = wxEmptyString);
	virtual bool RemoveIcon();
	virtual bool PopupMenu(wxMenu* pMenu);

	//	things found in the standard MSW impl. of wxTaskBarIcon
	WXHWND GetHWND() const;
	inline bool IsOk() const { return (NULL != m_win); }
	inline bool IsIconInstalled() const { return m_bIconAdded; }

	//	wxMswTaskBarIconEx only methods
	inline EWxMswTaskBarIconExFeatures GetFeatureSet() const { return m_featureSet; }

	///
	///	@brief	Shows a balloon notification from the tray icon
	///
	///	@param [in] title	Notification title (max length = 127 characters)
	///	@param [in]	msg		Notification message (max length = 256, but 200
	///	recommended max)
	///	@param [in] userIcon	User defined wxIcon to display. Pass wxIcon()
	///	if using stock icons (see EShowBalloonFlags)
	///	@param [in] flags	Bitmask of EWxMswTaskBarIconExShowBalloonFlags values
	///	@param [in] extraFlags	Bitmask of EWxmswTaskBarExShowBalloonExFlags
	///	values
	///	@param [in] timeout	Timeout value for notification. Note that in Vista+
	///	this value is ignored (timeouts are handled by the system)
	///
	bool ShowBalloonNotification(const wxString& title, const wxString& msg,
		const wxIcon& userIcon, const wxUint32 flags = wxMSW_TASKBAREX_SB_DEFAULT,
		const wxUint32 extraFlags = wxMSW_TASKBAREX_SB_EX_NONE,
		const unsigned int timeout = TIMEOUT_MAX);
protected:
	friend class wxMswTaskBarIconExWindow;

	long WindowProc(unsigned int msg, unsigned int wParam, long lParam);
	void InitFeatureSet();
    void RegisterWindowMessages();

	EWxMswTaskBarIconExFeatures		m_featureSet;
	wxMswTaskBarIconExWindow*		m_win;
	bool							m_bIconAdded;
	wxIcon							m_icon;
	wxString						m_tooltip;
};

////////////////////////////////////////////////////////////////////////////////
//	wxMswTaskBarIconExEvent
////////////////////////////////////////////////////////////////////////////////
class wxMswTaskBarIconExEvent
	: public wxEvent
{
public:
	wxMswTaskBarIconExEvent(wxEventType evtType,
		wxMswTaskBarIconEx* pTaskBarIcon)
		: wxEvent(wxID_ANY, evtType)
	{
		SetEventObject(pTaskBarIcon);
	}

	virtual wxEvent* Clone() const { return new wxMswTaskBarIconExEvent(*this); }
private:
	DECLARE_NO_ASSIGN_CLASS(wxMswTaskBarIconExEvent)
};

BEGIN_DECLARE_EVENT_TYPES()
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_CREATED, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_CONTEXT_MENU, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_SELECT, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_KEY_SELECT, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_SHOW, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_HIDE, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_TIMEOUT, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_USERCLICK, wxID_ANY)
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_SHUTDOWN, wxID_ANY)
END_DECLARE_EVENT_TYPES()

typedef void (wxEvtHandler::*wxMswTaskBarIconExEventFunction)(wxMswTaskBarIconExEvent&);

#define wxMswTaskBarIconExEventHandler(func) \
    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxMswTaskBarIconExEventFunction, &func)

#define wx__DECLARE_MSW_TASKBAR_EX_EVT(evt, fn) \
    wx__DECLARE_EVT0(wxEVT_TASKBAR_ ## evt, wxMswTaskBarIconExEventHandler(fn))

#define EVT_TASKBAR_CREATED(fn)              wx__DECLARE_MSW_TASKBAR_EX_EVT(CREATED, fn)
#define EVT_TASKBAR_CONTEXT_MENU(fn)         wx__DECLARE_MSW_TASKBAR_EX_EVT(CONTEXT_MENU, fn)
#define EVT_TASKBAR_SELECT(fn)               wx__DECLARE_MSW_TASKBAR_EX_EVT(SELECT, fn)
#define EVT_TASKBAR_KEY_SELECT(fn)           wx__DECLARE_MSW_TASKBAR_EX_EVT(KEY_SELECT, fn)
#define EVT_TASKBAR_BALLOON_SHOW(fn)         wx__DECLARE_MSW_TASKBAR_EX_EVT(BALLOON_SHOW, fn)
#define EVT_TASKBAR_BALLOON_HIDE(fn)         wx__DECLARE_MSW_TASKBAR_EX_EVT(BALLOON_HIDE, fn)
#define EVT_TASKBAR_BALLOON_TIMEOUT(fn)      wx__DECLARE_MSW_TASKBAR_EX_EVT(BALLOON_TIMEOUT, fn)
#define EVT_TASKBAR_CONTEXT_USERCLICK(fn)    wx__DECLARE_MSW_TASKBAR_EX_EVT(BALLOON_USERCLICK, fn)
#define EVT_TASKBAR_SHUTDOWN(fn)             wx__DECLARE_MSW_TASKBAR_EX_EVT(SHUTDOWN, fn)

#endif	//	!__WX_MSW_TASKBAR_ICON_EX__

Code: Select all

#if defined(_MSC_VER)
	//	disable stupid STL warnings
	#pragma warning(push)
	#pragma warning(disable:4251)
#endif	//	defined(__WXMSW__)

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#if defined(__BORLANDC__)
    #pragma hdrstop
#endif	//	defined(__BORLANDC__)

#if !defined(WX_PRECOMP)
    #include "wx/window.h"
    #include "wx/frame.h"
    #include "wx/utils.h"
    #include "wx/menu.h"
#endif	//	!defined(WX_PRECOMP)

#include "wx/msw/private.h"
#include "wx/msw/winundef.h"
#include "wx/msw/ole/uuid.h"

#include "wx/dynlib.h"
#include "wxMswTaskBarIconEx.h"

#if !defined(__WXWINCE__)
    #include <winreg.h>
    #include <shellapi.h>
	#include <shlwapi.h>
#endif	//	!defined(__WXWINCE__)

DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_CREATED)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_CONTEXT_MENU)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_SELECT)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_KEY_SELECT)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_SHOW)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_HIDE)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_TIMEOUT)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_BALLOON_USERCLICK)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_TASKBAR_SHUTDOWN)

//	:TODO: add support for dwState (2k+) and hidden, e.g. HideIcon(const bool bHide)

//	globals
UINT	gs_msgWxMswTaskBar			= 0;
UINT	gs_msgRestartWxMswTaskBar	= 0;

static const GUID gs_wxMswTaskBarIconExGuid = {
	0x575a3b13, 0xe5f3, 0x475d, {0xbd, 0xf0, 0x7c, 0xad, 0xcc, 0xd0, 0x9a, 0xe9}
};

////////////////////////////////////////////////////////////////////////////////
//	wxMswTaskBarIconExWindow
//
//	Notes taken from wxTaskBarIconWindow:
//
//	"NB: this class serves two purposes:
//     1. win32 needs a HWND associated with taskbar icon, this provides it
//     2. we need wxTopLevelWindow so that the app doesn't exit when
//        last frame is closed but there still is a taskbar icon"
//
////////////////////////////////////////////////////////////////////////////////

class wxMswTaskBarIconExWindow
	: public wxFrame
{
public:
	wxMswTaskBarIconExWindow(wxMswTaskBarIconEx* pTaskBarIcon)
		: wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition,
			wxDefaultSize, 0)
		, m_pTaskBarIcon(pTaskBarIcon)
	{
	}

    WXLRESULT MSWWindowProc(WXUINT msg, WXWPARAM wParam, WXLPARAM lParam)
    {
        if(msg == gs_msgRestartWxMswTaskBar || msg == gs_msgWxMswTaskBar) {
            return m_pTaskBarIcon->WindowProc(msg, wParam, lParam);
        } else {
            return wxFrame::MSWWindowProc(msg, wParam, lParam);
        }
    }
private:
    wxMswTaskBarIconEx*	m_pTaskBarIcon;
};

////////////////////////////////////////////////////////////////////////////////
//	MswNotifyIconData - wrapper around NOTIFYICONDATA
////////////////////////////////////////////////////////////////////////////////
struct MswNotifyIconData
	: public NOTIFYICONDATA
{
	MswNotifyIconData(WXHWND hwnd, EWxMswTaskBarIconExFeatures featureSet)
	{
		memset(this, 0, sizeof(NOTIFYICONDATA));

		//
		//	See MSDN remarks about NOTIFYICONDATA & cbSize here:
		//	http://msdn.microsoft.com/en-us/library/bb773352%28VS.85%29.aspx
		//
		if(featureSet >= wxMSW_TASKBAREX_FEATURES_VISTA_PLUS) {
			this->cbSize		= sizeof(NOTIFYICONDATA);
		} else if(featureSet >= wxMSW_TASKBAREX_FEATURES_XP_PLUS) {
			this->cbSize		= NOTIFYICONDATA_V3_SIZE;
		} else {
			this->cbSize		= NOTIFYICONDATA_V2_SIZE;
		}

		this->hWnd				= (HWND)hwnd;
		this->uCallbackMessage	= gs_msgWxMswTaskBar;
		this->uFlags			= NIF_MESSAGE;

		//
		//	special setup depending on platform
		//
		//	Use guidItem for Win7+ otherwise uID
		//
		//	:TODO: look into this further - the icon must be "registered", which means this may not work as our icon can be in a resource
		/*if(featureSet >= wxMSW_TASKBAREX_FEATURES_WIN7_PLUS) {
			this->uFlags	|= NIF_GUID;
			this->guidItem	= gs_wxMswTaskBarIconExGuid;
		} else {*/
		this->uID		= 99;
		//}

		//
		//	set the version for platforms that support it (2k+)
		//
		if(featureSet >= wxMSW_TASKBAREX_FEATURES_VISTA_PLUS) {
			this->uVersion	= NOTIFYICON_VERSION_4;
		} else {
			this->uVersion	= NOTIFYICON_VERSION;
		}
	}
};

////////////////////////////////////////////////////////////////////////////////
//	wxMswTaskBarIconEx
////////////////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC_CLASS(wxMswTaskBarIconEx,	wxEvtHandler);

wxMswTaskBarIconEx::wxMswTaskBarIconEx()
	: m_win(NULL)
	, m_bIconAdded(false)
	, m_featureSet(wxMSW_TASKBAREX_FEATURES_2K_PLUS)
{
	InitFeatureSet();
	RegisterWindowMessages();
}

wxMswTaskBarIconEx::~wxMswTaskBarIconEx()
{
	if(m_bIconAdded) {
		RemoveIcon();
	}

	if(m_win) {
		m_win->Destroy();
	}
}

/*virtual*/
bool wxMswTaskBarIconEx::SetIcon(const wxIcon& icon,
								 const wxString& tooltip /*= wxEmptyString*/)
{
	if(!m_win) {
		m_win = new wxMswTaskBarIconExWindow(this);
	}

	m_icon = icon;
	m_tooltip = tooltip;

	MswNotifyIconData iconData(GetHwndOf(m_win), m_featureSet);

	if(icon.Ok()) {
		iconData.uFlags |= NIF_ICON;
		iconData.hIcon	= GetHiconOf(icon);
	}

	//
	//	set the tip even if empty so it can be removed
	//
	iconData.uFlags |= NIF_TIP;
	if(!tooltip.IsEmpty()) {
		wxStrncpy(iconData.szTip, tooltip.c_str(), WXSIZEOF(iconData.szTip));
	}

	bool success = (TRUE == Shell_NotifyIcon(
		m_bIconAdded ? NIM_MODIFY : NIM_ADD,
		&iconData));

	if(!success) {
		wxLogMessage(wxSysErrorMsg());
	}

	if(!m_bIconAdded && success) {
		m_bIconAdded = true;

		//
		//	Instruct Windows to respect the uVersion member
		//
		if(TRUE != Shell_NotifyIcon(NIM_SETVERSION, &iconData)) {
			wxLogMessage(wxSysErrorMsg());
		}
	}

	return success;
}

/*virtual*/
bool wxMswTaskBarIconEx::RemoveIcon()
{
	if(!m_bIconAdded) {
		return false;
	}

	m_bIconAdded = false;

	MswNotifyIconData iconData(GetHwndOf(m_win), m_featureSet);
	return (TRUE == Shell_NotifyIcon(NIM_DELETE, &iconData));
}

/*virtual*/
bool wxMswTaskBarIconEx::PopupMenu(wxMenu* pMenu)
{
	wxASSERT_MSG(NULL != m_win, wxT("taskbar icon not initialized"));

	static bool s_bInPopup = false;

	if(s_bInPopup) {
		return false;
	}

	s_bInPopup = true;

	int x;
	int y;
	::wxGetMousePosition(&x, &y);

	m_win->Move(x, y);
	m_win->PushEventHandler(this);

	pMenu->UpdateUI();

	//
	//	From origial wxTaskBarIcon::PopupMenu():
	//	"the SetForegroundWindow() and PostMessage() calls are needed to work
    //	around Win32 bug with the popup menus shown for the notifications as
    //	documented at http://support.microsoft.com/kb/q135788/"
	//
	::SetForegroundWindow(GetHwndOf(m_win));

	bool retVal = m_win->PopupMenu(pMenu, 0, 0);

	::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);

	m_win->PopEventHandler(false);

	s_bInPopup = false;
	return retVal;
}

WXHWND wxMswTaskBarIconEx::GetHWND() const
{
	return (NULL == m_win ? (WXHWND)NULL : GetHwndOf(m_win));
}

bool
wxMswTaskBarIconEx::ShowBalloonNotification(const wxString& title,
											const wxString& msg,
											const wxIcon& userIcon,
											const wxUint32 flags /*= SHOW_BALLOON_DEFAULT*/,
											const wxUint32 extraFlags /*= SHOW_BALLOON_EX_NONE*/,
											const unsigned int timeout /*= TIMEOUT_MAX*/)
{
	if(!IsOk() && !SetIcon(m_icon, m_tooltip)) {
		return false;
	}

	MswNotifyIconData iconData(GetHwndOf(m_win), m_featureSet);

	//
	//	Standard flags for balloon hints
	//
	iconData.uFlags |= NIF_INFO;

	//
	//	XP SP2+ allows for the use of NIIF_USER (our userIcon)
	//
	if(userIcon.Ok() && m_featureSet >= wxMSW_TASKBAREX_FEATURES_XP_PLUS) {
		//
		//	if in Vista+ use the hBalloonIcon else hIcon
		//
		if(m_featureSet >= wxMSW_TASKBAREX_FEATURES_VISTA_PLUS) {
			iconData.hBalloonIcon	= GetHiconOf(userIcon);
		} else {
			iconData.uFlags			|= NIF_ICON;
			iconData.hIcon			= GetHiconOf(userIcon);
		}
		iconData.dwInfoFlags		|= NIIF_USER;
	} else {
		if(flags & wxMSW_TASKBAREX_SB_INFO) {
			iconData.dwInfoFlags |= NIIF_INFO;
		} else if(flags & wxMSW_TASKBAREX_SB_WARNING) {
			iconData.dwInfoFlags |= NIIF_WARNING;
		} else if(flags & wxMSW_TASKBAREX_SB_ERROR) {
			iconData.dwInfoFlags |= NIIF_ERROR;
		} else {
			//	provide a default
			iconData.dwInfoFlags |= NIIF_INFO;
		}
	}

	//
	//	Vista+ also allows for large icons in balloon tips
	//
	if(m_featureSet >= wxMSW_TASKBAREX_FEATURES_VISTA_PLUS &&
		(flags & wxMSW_TASKBAREX_SB_LARGE_ICON))
	{
		//
		//	From MSDN:
		//	"0x00000010. Windows Vista and later. The large version
		//	of the icon should be used as the notification icon.
		//	This corresponds to the icon with dimensions
		//	SM_CXICON x SM_CYICON. If this flag is not set, the icon
		//	with dimensions XM_CXSMICON x SM_CYSMICON is used.
		//
		//	* This flag can be used with all stock icons.
		//
		//	* Applications that use older customized icons
		//	(NIIF_USER with hIcon) must provide a new
		//	SM_CXICON x SM_CYICON version in the tray icon (hIcon).
		//	These icons are scaled down when they are displayed in
		//	the System Tray or System Control Area (SCA).
		//
		//	* New customized icons (NIIF_USER with hBalloonIcon)
		//	must supply an SM_CXICON x SM_CYICON version in the
		//	supplied icon (hBalloonIcon)."
		//
		//	If we're using userIcon instead of stock icons, validate it's OK
		//	otherwise fall back to default stock
		//
		if(userIcon.Ok()) {
			int largeIconX = ::wxSystemSettings::GetMetric(wxSYS_ICON_X);
			int largeIconY = ::wxSystemSettings::GetMetric(wxSYS_ICON_Y);
			if(userIcon.GetWidth() >= largeIconX ||
				userIcon.GetHeight() >= largeIconY)
			{
				iconData.dwInfoFlags	|= NIIF_LARGE_ICON;
			} else {
				iconData.hIcon			= 0;
				iconData.hBalloonIcon	= 0;
				iconData.dwInfoFlags	=~ NIIF_USER;
				iconData.dwInfoFlags	|= NIIF_INFO;
			}
		} else {
			iconData.dwInfoFlags		|= NIIF_LARGE_ICON;
		}
	}

	if(m_featureSet <= wxMSW_TASKBAREX_FEATURES_XP_PLUS) {
		iconData.uTimeout	= timeout;
	}

	//
	//	Mix in the rest of the flags
	//
	//	:TODO: clean this up, this is a dumb way of doing it me thinks
	if(flags & wxMSW_TASKBAREX_SB_NOSOUND) {
		iconData.dwInfoFlags	|= wxMSW_TASKBAREX_SB_NOSOUND;
	}
	if(flags & wxMSW_TASKBAREX_SB_RESPECT_QUIET_TIME) {
		iconData.dwInfoFlags	|= wxMSW_TASKBAREX_SB_RESPECT_QUIET_TIME;
	}
	if(extraFlags & wxMSW_TASKBAREX_SB_EX_REALTIME) {
		iconData.uFlags			|= wxMSW_TASKBAREX_SB_EX_REALTIME;
	}

	//
	//	Populate the actual tooltip message data
	//
	wxStrncpy(iconData.szInfo, msg.c_str(), WXSIZEOF(iconData.szInfo));
	wxStrncpy(iconData.szInfoTitle, title.c_str(),
		WXSIZEOF(iconData.szInfoTitle));

	return Shell_NotifyIcon(NIM_MODIFY, &iconData) ? true : false;
}

void wxMswTaskBarIconEx::InitFeatureSet()
{
	int major;
	int minor;
	::wxGetOsVersion(&major, &minor);

	if(major >= 6 && minor >= 1) {
		m_featureSet = wxMSW_TASKBAREX_FEATURES_WIN7_PLUS;
	} else if(major >= 6 && 0 == minor) {
		m_featureSet = wxMSW_TASKBAREX_FEATURES_VISTA_PLUS;
	} else if(major >= 5 && 1 == minor) {
		m_featureSet = wxMSW_TASKBAREX_FEATURES_XP_PLUS;

		//
		//	It's XP - see if it's SP2+
		//
		OSVERSIONINFOEX verInfo;
		memset(&verInfo, 0, sizeof(OSVERSIONINFOEX));
		verInfo.dwOSVersionInfoSize	= sizeof(OSVERSIONINFOEX);
		if(::GetVersionEx((LPOSVERSIONINFO)&verInfo) && verInfo.wServicePackMajor >= 3) {
			m_featureSet = wxMSW_TASKBAREX_FEATURES_XP_SP2_PLUS;
		}
	} else if(major >= 5 && 0 == minor) {
		m_featureSet = wxMSW_TASKBAREX_FEATURES_2K_PLUS;
	}
}

void wxMswTaskBarIconEx::RegisterWindowMessages()
{
	static bool s_bReg = false;
	if(!s_bReg) {
		gs_msgRestartWxMswTaskBar =
			::RegisterWindowMessage(wxT("TaskbarCreated"));
		gs_msgWxMswTaskBar =
			::RegisterWindowMessage(wxT("wxMswTaskBarIconExMessage"));
		s_bReg = true;
	}
}

long wxMswTaskBarIconEx::WindowProc(unsigned int msg, unsigned int wParam,
									long lParam)
{
	wxEventType eventType = 0;

	//
	//	Handle re-draw
	//
	if(gs_msgRestartWxMswTaskBar == msg) {
		m_bIconAdded = false;
		SetIcon(m_icon, m_tooltip);
		return 0;
	}

	wxASSERT(gs_msgWxMswTaskBar == msg);	//	the only other reason we should be called

	//
	//	Using NOTIFYICON_VERSION_4, we must interpret lParam & wParam
	//	differently
	//
	long winMsg;
	if(m_featureSet >= wxMSW_TASKBAREX_FEATURES_VISTA_PLUS) {
		winMsg = LOWORD(lParam);
	} else {
		winMsg = lParam;
	}

	switch(winMsg) {
		case WM_LBUTTONDOWN :
			eventType = wxEVT_TASKBAR_LEFT_DOWN;
			break;

		case WM_LBUTTONUP :
			eventType = wxEVT_TASKBAR_LEFT_UP;
			break;

		case WM_RBUTTONDOWN :
			eventType = wxEVT_TASKBAR_RIGHT_DOWN;
			break ;

		case WM_RBUTTONUP:
			eventType = wxEVT_TASKBAR_RIGHT_UP;
			break ;

		case WM_LBUTTONDBLCLK:
			eventType = wxEVT_TASKBAR_LEFT_DCLICK;
			break ;

		case WM_RBUTTONDBLCLK :
			eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
			break;

		case WM_MOUSEMOVE :
			eventType = wxEVT_TASKBAR_MOVE;
			break;

		case WM_CONTEXTMENU :
			eventType = wxEVT_TASKBAR_CONTEXT_MENU;
			break;

		case NIN_SELECT :
			eventType = wxEVT_TASKBAR_SELECT;
			break;

		case NIN_KEYSELECT :
			eventType = wxEVT_TASKBAR_KEY_SELECT;
			break;

		case NIN_BALLOONSHOW :
			eventType = wxEVT_TASKBAR_BALLOON_SHOW;
			break;

		case NIN_BALLOONHIDE :
			eventType = wxEVT_TASKBAR_BALLOON_HIDE;
			break;

		case NIN_BALLOONTIMEOUT :
			eventType = wxEVT_TASKBAR_BALLOON_TIMEOUT;
			break;

		case NIN_BALLOONUSERCLICK :
			eventType = wxEVT_TASKBAR_BALLOON_USERCLICK;
			break;
	}

	if(eventType) {
		wxMswTaskBarIconExEvent evt(eventType, this);
		ProcessEvent(evt);
	}

	return 0;
}

#if defined(_MSC_VER)
	#pragma warning(pop)
#endif	//	defined(__WXMSW__)

Post Reply