dolphin/Externals/wxWidgets3/src/msw/notifmsg.cpp

430 lines
12 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// 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 <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
// 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