mirror of https://github.com/BOINC/boinc.git
424 lines
12 KiB
C++
424 lines
12 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// File: taskbar.cpp
|
|
// Purpose: Implements wxTaskBarIconEx class for manipulating icons on
|
|
// the Windows task bar.
|
|
// Author: Julian Smart
|
|
// Modified by: Rom Walton
|
|
// Created: 24/3/98
|
|
// RCS-ID: $Id$
|
|
// 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"
|
|
|
|
|
|
// Add items new to Windows Vista and Windows 7
|
|
//
|
|
#ifndef NIF_GUID
|
|
#define NIF_GUID 0x00000020
|
|
#endif
|
|
#ifndef NIF_REALTIME
|
|
#define NIF_REALTIME 0x00000040
|
|
#endif
|
|
#ifndef NIF_SHOWTIP
|
|
#define NIF_SHOWTIP 0x00000080
|
|
#endif
|
|
#ifndef NIIF_LARGE_ICON
|
|
#define NIIF_LARGE_ICON 0x00000010
|
|
#endif
|
|
#ifndef NIIF_RESPECT_QUIET_TIME
|
|
#define NIIF_RESPECT_QUIET_TIME 0x00000010
|
|
#endif
|
|
|
|
|
|
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_TASKBARMESSAGE = ::RegisterWindowMessage(wxT("TaskbarMessage"));
|
|
const UINT WM_TASKBARSHUTDOWN = ::RegisterWindowMessage(wxT("TaskbarShutdown"));
|
|
const UINT WM_TASKBARAPPRESTORE = ::RegisterWindowMessage(wxT("TaskbarAppRestore"));
|
|
|
|
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 )
|
|
DEFINE_EVENT_TYPE( wxEVT_TASKBAR_APPRESTORE )
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIconEx, wxEvtHandler)
|
|
|
|
BEGIN_EVENT_TABLE (wxTaskBarIconEx, wxEvtHandler)
|
|
EVT_CLOSE(wxTaskBarIconEx::OnClose)
|
|
EVT_TASKBAR_CREATED(wxTaskBarIconEx::OnTaskBarCreated)
|
|
END_EVENT_TABLE ()
|
|
|
|
|
|
wxTaskBarIconEx::wxTaskBarIconEx()
|
|
{
|
|
m_pTaskbarMutex = new wxMutex();
|
|
m_iTaskbarID = 0;
|
|
m_iconAdded = FALSE;
|
|
m_hWnd = CreateTaskBarWindow( wxTaskBarExWindow );
|
|
}
|
|
|
|
wxTaskBarIconEx::wxTaskBarIconEx( wxChar* szWindowTitle, wxInt32 iTaskbarID )
|
|
{
|
|
m_pTaskbarMutex = new wxMutex();
|
|
m_iTaskbarID = iTaskbarID;
|
|
m_iconAdded = FALSE;
|
|
m_hWnd = CreateTaskBarWindow( szWindowTitle );
|
|
}
|
|
|
|
wxTaskBarIconEx::~wxTaskBarIconEx()
|
|
{
|
|
if (m_iconAdded)
|
|
{
|
|
RemoveIcon();
|
|
}
|
|
|
|
if (m_hWnd)
|
|
{
|
|
::DestroyWindow((HWND) m_hWnd);
|
|
m_hWnd = 0;
|
|
}
|
|
}
|
|
|
|
// Events
|
|
void wxTaskBarIconEx::OnClose(wxCloseEvent& WXUNUSED(event))
|
|
{
|
|
::DestroyWindow((HWND) m_hWnd);
|
|
m_hWnd = 0;
|
|
}
|
|
|
|
void wxTaskBarIconEx::OnTaskBarCreated(wxTaskBarIconExEvent& WXUNUSED(event))
|
|
{
|
|
m_iconAdded = false;
|
|
UpdateIcon();
|
|
}
|
|
|
|
// Operations
|
|
bool wxTaskBarIconEx::SetIcon(const wxIcon& icon, const wxString& message)
|
|
{
|
|
if (!IsOK())
|
|
return false;
|
|
|
|
if (!icon.Ok())
|
|
return false;
|
|
|
|
memset(¬ifyData, 0, sizeof(NOTIFYICONDATA));
|
|
notifyData.cbSize = sizeof(notifyData);
|
|
notifyData.hWnd = (HWND) m_hWnd;
|
|
notifyData.uID = m_iTaskbarID;
|
|
notifyData.uCallbackMessage = WM_TASKBARMESSAGE;
|
|
notifyData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_REALTIME;
|
|
notifyData.uVersion = NOTIFYICON_VERSION;
|
|
notifyData.hIcon = (HICON) icon.GetHICON();
|
|
|
|
if (!message.empty()) {
|
|
notifyData.uFlags |= NIF_TIP;
|
|
lstrcpyn(notifyData.szTip, WXSTRINGCAST message, sizeof(notifyData.szTip));
|
|
}
|
|
|
|
UpdateIcon();
|
|
return m_iconAdded;
|
|
}
|
|
|
|
bool wxTaskBarIconEx::SetBalloon(const wxIcon& icon, const wxString title, const wxString message, unsigned int iconballoon)
|
|
{
|
|
if (!IsOK())
|
|
return false;
|
|
|
|
if (!icon.Ok())
|
|
return false;
|
|
|
|
memset(¬ifyData, 0, sizeof(NOTIFYICONDATA));
|
|
notifyData.cbSize = sizeof(notifyData);
|
|
notifyData.hWnd = (HWND) m_hWnd;
|
|
notifyData.uID = m_iTaskbarID;
|
|
notifyData.uCallbackMessage = WM_TASKBARMESSAGE;
|
|
notifyData.uFlags = NIF_MESSAGE | NIF_INFO | NIF_ICON | NIF_REALTIME;
|
|
notifyData.dwInfoFlags = iconballoon | NIIF_NOSOUND | NIIF_RESPECT_QUIET_TIME;
|
|
notifyData.uVersion = NOTIFYICON_VERSION;
|
|
notifyData.hIcon = (HICON) icon.GetHICON();
|
|
|
|
lstrcpyn(notifyData.szInfoTitle, WXSTRINGCAST title, sizeof(notifyData.szInfoTitle));
|
|
lstrcpyn(notifyData.szInfo, WXSTRINGCAST message, sizeof(notifyData.szInfo));
|
|
|
|
UpdateIcon();
|
|
return m_iconAdded;
|
|
}
|
|
|
|
bool wxTaskBarIconEx::QueueBalloon(const wxIcon& icon, const wxString title, const wxString message, unsigned int iconballoon)
|
|
{
|
|
if (!IsOK())
|
|
return false;
|
|
|
|
if (!icon.Ok())
|
|
return false;
|
|
|
|
memset(¬ifyData, 0, sizeof(NOTIFYICONDATA));
|
|
notifyData.cbSize = sizeof(notifyData);
|
|
notifyData.hWnd = (HWND) m_hWnd;
|
|
notifyData.uID = m_iTaskbarID;
|
|
notifyData.uCallbackMessage = WM_TASKBARMESSAGE;
|
|
notifyData.uFlags = NIF_MESSAGE | NIF_INFO | NIF_ICON;
|
|
notifyData.dwInfoFlags = iconballoon | NIIF_RESPECT_QUIET_TIME;
|
|
notifyData.uVersion = NOTIFYICON_VERSION;
|
|
notifyData.hIcon = (HICON) icon.GetHICON();
|
|
|
|
lstrcpyn(notifyData.szInfoTitle, WXSTRINGCAST title, sizeof(notifyData.szInfoTitle));
|
|
lstrcpyn(notifyData.szInfo, WXSTRINGCAST message, sizeof(notifyData.szInfo));
|
|
|
|
UpdateIcon();
|
|
return m_iconAdded;
|
|
}
|
|
|
|
bool wxTaskBarIconEx::RemoveIcon()
|
|
{
|
|
if (!m_iconAdded)
|
|
return FALSE;
|
|
|
|
memset(¬ifyData, 0, sizeof(NOTIFYICONDATA));
|
|
notifyData.cbSize = sizeof(notifyData);
|
|
notifyData.hWnd = (HWND) m_hWnd;
|
|
notifyData.uID = m_iTaskbarID;
|
|
|
|
m_iconAdded = FALSE;
|
|
|
|
return (Shell_NotifyIcon(NIM_DELETE, ¬ifyData) != 0);
|
|
}
|
|
|
|
void wxTaskBarIconEx::UpdateIcon()
|
|
{
|
|
if (m_iconAdded)
|
|
{
|
|
Shell_NotifyIcon(NIM_MODIFY, ¬ifyData);
|
|
}
|
|
else
|
|
{
|
|
m_iconAdded = (Shell_NotifyIcon(NIM_ADD, ¬ifyData) != 0);
|
|
if (IsBalloonsSupported())
|
|
{
|
|
Shell_NotifyIcon(NIM_SETVERSION, ¬ifyData);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool wxTaskBarIconEx::PopupMenu(wxMenu *menu)
|
|
{
|
|
wxMutexLocker lock(*m_pTaskbarMutex);
|
|
if (!lock.IsOk()) return false;
|
|
|
|
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;
|
|
|
|
return rval;
|
|
}
|
|
|
|
bool wxTaskBarIconEx::FireAppRestore()
|
|
{
|
|
HWND hWnd = ::FindWindow(wxTaskBarExWindowClass, NULL);
|
|
if (hWnd) {
|
|
::SendMessage(hWnd, WM_TASKBARAPPRESTORE, NULL, NULL);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
WXHWND wxTaskBarIconEx::CreateTaskBarWindow( wxChar* szWindowTitle )
|
|
{
|
|
HINSTANCE hInstance = GetModuleHandle(NULL);
|
|
HWND hWnd = NULL;
|
|
WNDCLASS wc;
|
|
|
|
if (!::GetClassInfo( hInstance, wxTaskBarExWindowClass, &wc )) {
|
|
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;
|
|
::RegisterClass(&wc);
|
|
}
|
|
|
|
hWnd = ::CreateWindowEx (
|
|
0,
|
|
wxTaskBarExWindowClass,
|
|
szWindowTitle,
|
|
WS_OVERLAPPED,
|
|
0,
|
|
0,
|
|
10,
|
|
10,
|
|
NULL,
|
|
(HMENU)0,
|
|
hInstance,
|
|
NULL
|
|
);
|
|
|
|
return (WXHWND)hWnd;
|
|
}
|
|
|
|
bool wxTaskBarIconEx::IsBalloonsSupported()
|
|
{
|
|
wxInt32 iMajor = 0, iMinor = 0;
|
|
if ( wxWINDOWS_NT == wxGetOsVersion( &iMajor, &iMinor ) )
|
|
{
|
|
if ( (6 >= iMajor) || ((5 >= iMajor) && (0 <= iMinor)) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
long wxTaskBarIconEx::WindowProc( WXHWND hWnd, unsigned int msg, unsigned int wParam, long lParam )
|
|
{
|
|
wxEventType eventType = 0;
|
|
long lReturnValue = 0;
|
|
|
|
if ( WM_CLOSE == msg )
|
|
{
|
|
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 )
|
|
{
|
|
eventType = wxEVT_TASKBAR_CREATED;
|
|
}
|
|
else if ( WM_TASKBARSHUTDOWN == msg )
|
|
{
|
|
eventType = wxEVT_TASKBAR_SHUTDOWN;
|
|
}
|
|
else if ( WM_TASKBARAPPRESTORE == msg )
|
|
{
|
|
eventType = wxEVT_TASKBAR_APPRESTORE;
|
|
}
|
|
else if ( WM_TASKBARMESSAGE == msg )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lReturnValue = DefWindowProc((HWND) hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
if (eventType)
|
|
{
|
|
wxTaskBarIconExEvent event(eventType, this);
|
|
lReturnValue = ProcessEvent(event);
|
|
}
|
|
|
|
return lReturnValue;
|
|
}
|
|
|
|
LRESULT APIENTRY wxTaskBarIconExWindowProc( HWND hWnd, unsigned msg, UINT wParam, LONG lParam )
|
|
{
|
|
return wxGetApp().GetTaskBarIcon()->WindowProc((WXHWND) hWnd, msg, wParam, lParam);
|
|
}
|
|
|