/////////////////////////////////////////////////////////////////////////////// // Name: src/msw/notifmsg.cpp // Purpose: implementation of wxNotificationMessage for Windows // Author: Vadim Zeitlin // Created: 2007-12-01 // RCS-ID: $Id: notifmsg.cpp 69379 2011-10-11 17:08:02Z VZ $ // Copyright: (c) 2007 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif // we can only use the native implementation if we have a working // wxTaskBarIcon::ShowBalloon() method #if wxUSE_NOTIFICATION_MESSAGE && \ wxUSE_TASKBARICON && wxUSE_TASKBARICON_BALLOONS #include "wx/notifmsg.h" #ifndef WX_PRECOMP #include "wx/toplevel.h" #include "wx/app.h" #include "wx/string.h" #endif // WX_PRECOMP #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: wxDECLARE_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; } }; // 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; wxDECLARE_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::OnClick), 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(wxT("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 WXUNUSED_UNLESS_DEBUG(timeout), int flags) { wxASSERT_MSG( timeout == wxNotificationMessage::Timeout_Never, wxT("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) { if ( m_ownsIcon ) { // This object will self-destruct and also delete the icon when the // notification is hidden. new wxNotificationIconEvtHandler(m_icon); } } bool wxAutoNotifMsgImpl::DoShow(const wxString& title, const wxString& message, int timeout, int flags) { wxASSERT_MSG( timeout != wxNotificationMessage::Timeout_Never, wxT("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 */ bool wxNotificationMessage::ms_alwaysUseGeneric = false; /* static */ wxTaskBarIcon *wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon *icon) { return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon); } bool wxNotificationMessage::Show(int timeout) { if ( !m_impl ) { if ( !ms_alwaysUseGeneric && 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