]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/notifmsg.cpp
implemented wxNotificationMessage for wxMSW using wxTaskBarIcon and fallback to gener...
[wxWidgets.git] / src / msw / notifmsg.cpp
diff --git a/src/msw/notifmsg.cpp b/src/msw/notifmsg.cpp
new file mode 100644 (file)
index 0000000..136a1bc
--- /dev/null
@@ -0,0 +1,420 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        src/msw/notifmsg.cpp
+// Purpose:     implementation of wxNotificationMessage for Windows
+// Author:      Vadim Zeitlin
+// Created:     2007-12-01
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON
+
+#ifndef WX_PRECOMP
+    #include "wx/string.h"
+#endif // WX_PRECOMP
+
+#include "wx/notifmsg.h"
+#include "wx/generic/notifmsg.h"
+
+#include "wx/taskbar.h"
+
+// ----------------------------------------------------------------------------
+// different implementations used by wxNotificationMessage
+// ----------------------------------------------------------------------------
+
+// base class for all available implementations
+class wxNotifMsgImpl
+{
+public:
+    wxNotifMsgImpl() { }
+    virtual ~wxNotifMsgImpl() { }
+
+    virtual bool DoShow(const wxString& title,
+                        const wxString& message,
+                        int timeout,
+                        int flags) = 0;
+    virtual bool DoClose() = 0;
+
+private:
+    DECLARE_NO_COPY_CLASS(wxNotifMsgImpl)
+};
+
+// implementation which is simply a bridge to wxGenericNotificationMessage
+class wxGenericNotifMsgImpl : public wxNotifMsgImpl
+{
+public:
+    wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage) { }
+    virtual ~wxGenericNotifMsgImpl() { delete m_notif; }
+
+    virtual bool DoShow(const wxString& title,
+                        const wxString& message,
+                        int timeout,
+                        int flags)
+    {
+        m_notif->SetTitle(title);
+        m_notif->SetMessage(message);
+        m_notif->SetFlags(flags);
+        return m_notif->Show(timeout);
+    }
+
+    virtual bool DoClose()
+    {
+        return m_notif->Close();
+    }
+
+private:
+    wxGenericNotificationMessage * const m_notif;
+};
+
+// common base class for implementations using a taskbar icon and balloons
+class wxBalloonNotifMsgImpl : public wxNotifMsgImpl
+{
+public:
+    // ctor sets up m_icon (using the icon of the top level parent of the given
+    // window) which can be used to show an attached balloon later by the
+    // derived classes
+    wxBalloonNotifMsgImpl(wxWindow *win) { SetUpIcon(win); }
+
+    // implementation of wxNotificationMessage method with the same name
+    static wxTaskBarIcon *UseTaskBarIcon(wxTaskBarIcon *icon);
+
+    virtual bool DoShow(const wxString& title,
+                        const wxString& message,
+                        int timeout,
+                        int flags);
+
+protected:
+    // sets up m_icon (doesn't do anything with the old value, caller beware)
+    void SetUpIcon(wxWindow *win);
+
+
+    static wxTaskBarIcon *ms_iconToUse;
+
+    // the icon we attach our notification to, either ms_iconToUse or a
+    // temporary one which we will destroy when done
+    wxTaskBarIcon *m_icon;
+
+    // should be only used if m_icon != NULL and indicates whether we should
+    // delete it
+    bool m_ownsIcon;
+};
+
+// implementation for automatically hidden notifications
+class wxAutoNotifMsgImpl : public wxBalloonNotifMsgImpl
+{
+public:
+    wxAutoNotifMsgImpl(wxWindow *win);
+
+    virtual bool DoShow(const wxString& title,
+                        const wxString& message,
+                        int timeout,
+                        int flags);
+
+    // can't close automatic notification [currently]
+    virtual bool DoClose() { return false; }
+
+private:
+    // custom event handler connected to m_icon which will receive the icon
+    // close event and delete it and itself when it happens
+    wxEvtHandler * const m_iconEvtHandler;
+};
+
+// implementation for manually closed notifications
+class wxManualNotifMsgImpl : public wxBalloonNotifMsgImpl
+{
+public:
+    wxManualNotifMsgImpl(wxWindow *win);
+    virtual ~wxManualNotifMsgImpl();
+
+    virtual bool DoShow(const wxString& title,
+                        const wxString& message,
+                        int timeout,
+                        int flags);
+    virtual bool DoClose();
+
+private:
+    // store ctor parameter as we need it to recreate the icon later if we're
+    // closed and shown again
+    wxWindow * const m_win;
+};
+
+// ----------------------------------------------------------------------------
+// custom event handler for task bar icons
+// ----------------------------------------------------------------------------
+
+// normally we'd just use a custom taskbar icon class but this is impossible
+// because we can be asked to attach the notifications to an existing icon
+// which we didn't create, hence we install a special event handler allowing us
+// to get the events we need (and, crucially, to delete the icon when it's not
+// needed any more) in any case
+
+class wxNotificationIconEvtHandler : public wxEvtHandler
+{
+public:
+    wxNotificationIconEvtHandler(wxTaskBarIcon *icon);
+
+private:
+    void OnTimeout(wxTaskBarIconEvent& event);
+    void OnClick(wxTaskBarIconEvent& event);
+
+    void OnIconHidden();
+
+
+    wxTaskBarIcon * const m_icon;
+
+    DECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler)
+};
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxNotificationIconEvtHandler
+// ----------------------------------------------------------------------------
+
+wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon *icon)
+                            : m_icon(icon)
+{
+    m_icon->Connect
+            (
+              wxEVT_TASKBAR_BALLOON_TIMEOUT,
+              wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout),
+              NULL,
+              this
+            );
+
+    m_icon->Connect
+            (
+              wxEVT_TASKBAR_BALLOON_CLICK,
+              wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout),
+              NULL,
+              this
+            );
+}
+
+void wxNotificationIconEvtHandler::OnIconHidden()
+{
+    delete m_icon;
+
+    delete this;
+}
+
+void
+wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent& WXUNUSED(event))
+{
+    OnIconHidden();
+}
+
+void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent& WXUNUSED(event))
+{
+    // TODO: generate an event notifying the user code?
+
+    OnIconHidden();
+}
+
+// ----------------------------------------------------------------------------
+// wxBalloonNotifMsgImpl
+// ----------------------------------------------------------------------------
+
+wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_iconToUse = NULL;
+
+/* static */
+wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon)
+{
+    wxTaskBarIcon * const iconOld = ms_iconToUse;
+    ms_iconToUse = icon;
+    return iconOld;
+}
+
+void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
+{
+    if ( ms_iconToUse )
+    {
+        // use an existing icon
+        m_ownsIcon = false;
+        m_icon = ms_iconToUse;
+    }
+    else // no user-specified icon to attach to
+    {
+        // create our own one
+        m_ownsIcon = true;
+        m_icon = new wxTaskBarIcon;
+
+        // use the icon of the associated (or main, if none) frame
+        wxIcon icon;
+        if ( win )
+            win = wxGetTopLevelParent(win);
+        if ( !win )
+            win = wxTheApp->GetTopWindow();
+        if ( win )
+        {
+            const wxTopLevelWindow * const
+                tlw = wxDynamicCast(win, wxTopLevelWindow);
+            if ( tlw )
+                icon = tlw->GetIcon();
+        }
+
+        if ( !icon.IsOk() )
+        {
+            // we really must have some icon
+            icon = wxIcon(_T("wxICON_AAA"));
+        }
+
+        m_icon->SetIcon(icon);
+    }
+}
+
+bool
+wxBalloonNotifMsgImpl::DoShow(const wxString& title,
+                              const wxString& message,
+                              int timeout,
+                              int flags)
+{
+    timeout *= 1000; // Windows expresses timeout in milliseconds
+
+    return m_icon->ShowBalloon(title, message, timeout, flags);
+}
+
+// ----------------------------------------------------------------------------
+// wxManualNotifMsgImpl
+// ----------------------------------------------------------------------------
+
+wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow *win)
+                    : wxBalloonNotifMsgImpl(win),
+                      m_win(win)
+{
+}
+
+wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
+{
+    if ( m_icon )
+        DoClose();
+}
+
+bool
+wxManualNotifMsgImpl::DoShow(const wxString& title,
+                             const wxString& message,
+                             int timeout,
+                             int flags)
+{
+    wxASSERT_MSG( timeout == wxNotificationMessage::Timeout_Never,
+                    _T("shouldn't be used") );
+
+    // base class creates the icon for us initially but we could have destroyed
+    // it in DoClose(), recreate it if this was the case
+    if ( !m_icon )
+        SetUpIcon(m_win);
+
+    // use maximal (in current Windows versions) timeout (but it will still
+    // disappear on its own)
+    return wxBalloonNotifMsgImpl::DoShow(title, message, 30, flags);
+}
+
+bool wxManualNotifMsgImpl::DoClose()
+{
+    if ( m_ownsIcon )
+    {
+        // we don't need the icon any more
+        delete m_icon;
+    }
+    else // using an existing icon
+    {
+        // just hide the balloon
+        m_icon->ShowBalloon("", "");
+    }
+
+    m_icon = NULL;
+
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// wxAutoNotifMsgImpl
+// ----------------------------------------------------------------------------
+
+wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win)
+                  : wxBalloonNotifMsgImpl(win),
+                    m_iconEvtHandler(new wxNotificationIconEvtHandler(m_icon))
+{
+}
+
+bool
+wxAutoNotifMsgImpl::DoShow(const wxString& title,
+                           const wxString& message,
+                           int timeout,
+                           int flags)
+{
+    wxASSERT_MSG( timeout != wxNotificationMessage::Timeout_Never,
+                    _T("shouldn't be used") );
+
+    if ( timeout == wxNotificationMessage::Timeout_Auto )
+    {
+        // choose a value more or less in the middle of the allowed range
+        timeout = 1;
+    }
+
+    return wxBalloonNotifMsgImpl::DoShow(title, message, timeout, flags);
+}
+
+// ----------------------------------------------------------------------------
+// wxNotificationMessage
+// ----------------------------------------------------------------------------
+
+/* static */
+wxTaskBarIcon *wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon *icon)
+{
+    return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon);
+}
+
+bool wxNotificationMessage::Show(int timeout)
+{
+    if ( !m_impl )
+    {
+        if ( wxTheApp->GetShell32Version() >= 500 )
+        {
+            if ( timeout == Timeout_Never )
+                m_impl = new wxManualNotifMsgImpl(GetParent());
+            else
+                m_impl = new wxAutoNotifMsgImpl(GetParent());
+        }
+        else // no support for balloon tooltips
+        {
+            m_impl = new wxGenericNotifMsgImpl;
+        }
+    }
+    //else: reuse the same implementation for the subsequent calls, it would
+    //      be too confusing if it changed
+
+    return m_impl->DoShow(GetTitle(), GetMessage(), timeout, GetFlags());
+}
+
+bool wxNotificationMessage::Close()
+{
+    wxCHECK_MSG( m_impl, false, "must show the notification first" );
+
+    return m_impl->DoClose();
+}
+
+wxNotificationMessage::~wxNotificationMessage()
+{
+    delete m_impl;
+}
+
+#endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON