Page 1 of 3

wxTaskBarIcon with Balloon tooltips!

Posted: Mon Sep 13, 2004 6:22 pm
by ctz
This class extends wxTaskBarIcon to offer balloon tooltips! It works very well in my application qDong:

Image

Code: Select all

class QDongTaskIcon : public wxTaskBarIcon
{
public:
	QDongTaskIcon();

	bool ShowBalloon(wxString title, wxString message, unsigned int timeout = 10000, int icon = NIIF_INFO);
};

QDongTaskIcon::QDongTaskIcon() : wxTaskBarIcon()
{
}

bool QDongTaskIcon::ShowBalloon(wxString title, wxString message, unsigned int timeout, int icon)
{
	if (!IsOK())
		return FALSE;

	NOTIFYICONDATA notifyData;

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

	notifyData.uFlags |= NIF_INFO;
	lstrcpyn(notifyData.szInfo, WXSTRINGCAST message, sizeof(notifyData.szInfo));
	lstrcpyn(notifyData.szInfoTitle, WXSTRINGCAST title, sizeof(notifyData.szInfoTitle));
	notifyData.dwInfoFlags = icon | NIIF_NOSOUND;
	notifyData.uTimeout = timeout;

	notifyData.uID = 99;

	if (m_iconAdded)
		return (Shell_NotifyIcon(NIM_MODIFY, &notifyData) != 0);
	else
		return false;
}
Possible values for icon are:

NIIF_ERROR
An error icon.
NIIF_INFO
An information icon.
NIIF_NONE
No icon.
NIIF_WARNING
A warning icon.

:arrow: however using this class is not compatible with windows ME and less. Only 2000, XP and 2003 support balloon tooltips AFAIK.

Posted: Tue Sep 14, 2004 3:38 am
by eros
Great stuff!

Posted: Tue Sep 14, 2004 6:42 am
by tierra
Awesome! Now I'm going to be looking for reasons to use this code just like I've been searching for reasons to use Jorgen's work... not to say Jorgen's work isn't good for anything, it's just a little more rare cases, and when they pop up, it definately comes in handy.

Posted: Tue Sep 14, 2004 6:45 am
by Ryan Norton
NEAT!!

Definately stickied :).

Posted: Sun Sep 19, 2004 1:22 pm
by Avi
Very nice indeed! I would add an enum wxBalloonIcon which has nicer balloon icons codes ;) Anyway, please make this a patch (to extend the wxWidgets library) and post it at SF.net (so it will be in one of the next wxWidgets versions if excepted!).

Posted: Mon Oct 11, 2004 5:18 pm
by Scorcher24
Hi there !!
thx for your snippet. I tried it out, but I have some Problems.
It is about that Visual Stduio tells me, that some elements are no members of NOTIFYICONDATA. I have done the define like MSDN tells me (#define IE 0x0500 or so) but It doesn't help. I also included <shellapi.h>. Perhaps you can tell me whats wrong ??
rya.
Scorcher24

My own version oif this snippet for 2.5.3

Posted: Wed Oct 13, 2004 11:44 am
by gunnar
I posted this on wx-dev list,but in case not everyone reads this list.

Well the forum version does actually not work with 2.5.3
No m_hWnd member anymore, but a wxTaskBarIconWindow * m_win,
where wxTaskBarIconWindow is deifined inside taskbar.cpp meaning its not
accessible from a user.

I made a quite hackish workaround and wrote the following code.

Code: Select all

#ifdef wxHAS_TASK_BAR_ICON
#include "wx/taskbar.h"
#ifdef __WXMSW__
#include <ShellAPI.h>
//
// Here i define wxTaskBarIconWindow as it is only define privately in
taskbar,cpp of wxwidgets
// This is a hack, but which choice do i have else?
class wxTaskBarIconWindow : public wxFrame
{
public:
        wxTaskBarIconWindow(wxTaskBarIcon *icon)
                : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, 0),
                m_icon(icon)
        {
        }


private:
        wxTaskBarIcon *m_icon;
};

#endif


//quite hackish attempt to be able to compile with release 2.5.2 and cvs
HEAD before 2.5.3 release
#if wxVERSION_NUMBER < 2503
#ifndef wxSUBRELEASE_NUMBER
#define wxTaskBarIconEvent wxEvent
#endif
#endif
class MusikTaskBarIcon: public wxTaskBarIcon
{
public:
        MusikTaskBarIcon(wxFrame * frame)
        {
#ifdef __WXMSW__
                m_dwShellDllVersion = GetDllVersion(wxT("shell32.dll"));
#endif
                m_pFrame = frame;
        };
        virtual bool SetIcon(const wxIcon& icon,
                const wxString& tooltip = wxEmptyString)
        {
                bool bRes = false;
#ifndef __WXMSW__
                bRes =  wxTaskBarIcon::SetIcon(icon,tooltip);
#else
                if(m_dwShellDllVersion < PACKVERSION(5,00))
                         bRes =  wxTaskBarIcon::SetIcon(icon,tooltip);
                else
                {
                        // we can use NOTIFYICONDATA V2,where the szTip has 128 chars instead of 64
                        bRes =  wxTaskBarIcon::SetIcon(icon,wxEmptyString); //just set the icon.
                        if(!tooltip.empty())
                        {// now set the tooltip text with the help of NOTIFYICONDATA V2 struct.
                                NOTIFYICONDATA nid;
                                memset(&nid,0,sizeof(nid));
                                nid.cbSize = NOTIFYICONDATAW_V2_SIZE;
                                nid.hWnd = (HWND)m_win->GetHWND();
                                nid.uID = 99;
                                nid.uFlags = NIF_TIP;
                                wxStrncpy(nid.szTip, tooltip.c_str(), WXSIZEOF(nid.szTip));
                                Shell_NotifyIcon(NIM_MODIFY, &nid);
                        }
                }
#endif
                return bRes;
        }
#ifdef __WXMSW__
        virtual bool ShowBalloonInfo(const wxString &sTitle,const wxString  &sText)
        {
                bool bRes = true;
                if(m_dwShellDllVersion >= PACKVERSION(5,00))
                {
                        NOTIFYICONDATA nid;
                        memset(&nid,0,sizeof(nid));
                        nid.cbSize = NOTIFYICONDATAW_V2_SIZE;
                        nid.hWnd = (HWND)m_win->GetHWND();
                        nid.uID = 99;
                        nid.uFlags = NIF_INFO;
                        wxStrncpy(nid.szInfo, sText.c_str(), WXSIZEOF(nid.szInfo));
                        wxStrncpy(nid.szInfoTitle, sTitle.c_str(), WXSIZEOF(nid.szInfoTitle));
                        nid.dwInfoFlags = NIIF_NOSOUND|NIIF_INFO;
                        nid.uTimeout = 5000;


                        Shell_NotifyIcon(NIM_MODIFY, &nid);
                }
                else
                        return false;

                return bRes;
        }
#endif
        void RestoreFrame();
    void OnRButtonUp(wxTaskBarIconEvent&);
    void OnLButtonDown(wxTaskBarIconEvent&);
    void OnMenuRestore(wxCommandEvent&);
    void OnMenuHide(wxCommandEvent&);
    void OnMenuPlayPause(wxCommandEvent&);
    void OnMenuPrev(wxCommandEvent&);
    void OnMenuNext(wxCommandEvent&);
    void OnMenuStop(wxCommandEvent&);
    void OnMenuExit(wxCommandEvent&);
    void OnMenuSetNewIcon(wxCommandEvent&);
        void OnUpdateUIRateSel ( wxUpdateUIEvent &event);
        void OnMenuRateSel( wxCommandEvent& event );

DECLARE_EVENT_TABLE()

private:
        wxFrame *m_pFrame;
#ifdef __WXMSW__
        DWORD m_dwShellDllVersion;
#endif
};
set _WIN32_IE=0x0600
in your projects preprocessor definitions.

the code of GetDllVersion(LPCTSTR dll)
can be found in the MSDN.

Maybe someone likes to incorporate this code into wxwidgets.
Instead of GetDllVersion(LPCTSTR dll) a more general version of
wxApp:GetComCtlVeersion() could be made.

EDIT: I added syntax highlighting, please use the [ syntax ] tag for code, or at least [ code ]


regards,
gunnar

EDIT: Updated the "tag" again to wxWidgtes syntax highlighting :)
Greetz,
upCASE

Posted: Sat Jul 02, 2005 12:23 pm
by lowjoel
hmm will downloading the latest platform SDK do the trick? any help would be much appreciated.

thanks,
joel

Posted: Sun Jul 03, 2005 12:00 pm
by wxDiilbert
Only works on MSW right ? :)

Posted: Sun Jul 03, 2005 12:01 pm
by wxDiilbert
lowjoel wrote:hmm will downloading the latest platform SDK do the trick? any help would be much appreciated.

thanks,
joel
Yes... I have used tooltip stuff in MFC apps before and you need the common core component of the latest SDK installed.

Posted: Mon Jul 11, 2005 11:52 pm
I don't understand Gunnar's example. And the original one isn't quite working for me either. I ran into Gunnar's problem with m_hWnd not being available to set the NOTIFYICONDATA.hWnd equal to.

I assume this is the handle of the window that the tooltip will show up in. Only problem is, I don't see how Gunnar's example of including the wxTaskBarIconWindow class definition helps me accomplish this goal.

In his code for setting hWnd, he shows:

Code: Select all

nid.hWnd = (HWND)m_win->GetHWND()
I can't figure out where the m_win is supposed to be coming from there. I'm assuming that it's a reference to the wxTaskBarIconWindow, but how do we get that? If we instantiate it separately (after the wxTaskBarIcon is created), and then pass it into the ShowBalloon method, things don't work (I've tried this). That's probably not surprising, in that I think what he's saying is a wxTaskBarIconWindow is created under the covers when a wxTaskBarIcon is created. So how the deuce do I get the address (or the hWnd) of that window after it's created in a hidden manner during the wxTaskBarIcon creation?

Basically, I don't understand what I'm supposed to do with the wxTaskBarIconWindow class, and how that helps me get this bleeding window handle that I need.

Have been struggling with this one for some time. I would certainly appreciate help.

Thanks.

Posted: Mon Aug 01, 2005 5:04 am
by lowjoel
I'm working on a patch to integrate this function into wxTaskBarIcon... and hopefully i will build a dll and static version (along with 2.6.2 CVS) and upload it to my server for download (along with a few other patches) just that building wx takes time.... :roll:

Posted: Mon Aug 01, 2005 12:46 pm
by lowjoel
I've done the patch:

Code: Select all

Index: build/msw/config.gcc
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/build/msw/config.gcc,v
retrieving revision 1.18
diff -u -r1.18 config.gcc
--- build/msw/config.gcc	2005/07/28 12:42:09	1.18
+++ build/msw/config.gcc	2005/08/01 06:01:02

@@ -17,10 +17,10 @@
 CXX = g++
 
 # Standard flags for CC 
-CFLAGS = 
+CFLAGS = -D_WIN32_IE=0x0600
 
 # Standard flags for C++ 
-CXXFLAGS = 
+CXXFLAGS = -D_WIN32_IE=0x0600
 
 # Standard preprocessor flags (common for CC and CXX) 
 CPPFLAGS = 


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/01 08:22:00
@@ -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/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/01 12:43:45
@@ -135,7 +135,7 @@
 {
     if (m_iconAdded)
         RemoveIcon();
-
+	
     if (m_win)
         m_win->Destroy();
 }
@@ -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));
     }
 
@@ -183,6 +182,9 @@
     if (!m_iconAdded)
         return false;
 
+    /*if (m_balloon)
+        Shell_NotifyIcon(NIM_DELETE, &m_notifyData) != 0;*/
+
     m_iconAdded = false;
 
     NotifyIconData notifyData((HWND)m_win->GetHWND());
@@ -328,6 +330,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__
The devpak will be available soon

Posted: Mon Aug 01, 2005 9:31 pm
lowjoel wrote:I've done the patch:
That's pretty cool. What's this 'devpack' about? What would I need to do to update my DLLs to include your patch?

Also, does this mean that we can expect that code in future versions of wxWidgets?

Posted: Mon Aug 01, 2005 11:53 pm
by lowjoel
devpaks are prebuilt libraries... for mingw

but if u want to include the patch in ur distro, feel free,

but it doesnt mean it will be included in later wx versions