📄 taskbarnotifier.cpp
字号:
// TaskbarNotifier.cpp : implementation file
// By John O'Byrne
// 11 August 2002: - Timer precision is now determined automatically
// Complete change in the way the popup is showing (thanks to this,now the popup can be always on top, it shows even while watching a movie)
// The popup doesn't steal the focus anymore (by replacing ShowWindow(SW_SHOW) by ShowWindow(SW_SHOWNOACTIVATE))
// Thanks to Daniel Lohmann, update in the way the taskbar pos is determined (more flexible now)
// 17 July 2002: - Another big Change in the method for determining the pos of the taskbar (using the SHAppBarMessage function)
// 16 July 2002: - Thanks to the help of Daniel Lohmann, the Show Function timings work perfectly now ;)
// 15 July 2002: - Change in the method for determining the pos of the taskbar
// (now handles the presence of quick launch or any other bar).
// Remove the Handlers for WM_CREATE and WM_DESTROY
// SetSkin is now called SetBitmap
// 14 July 2002: - Changed the GenerateRegion func by a new one (to correct a win98 bug)
// kei-kun modifications:
// 30 October 2002: - Added event type management (TBN_*) for eMule project
// 04 November 2002: - added skin support via .ini file
#include "stdafx.h"
#include "emule.h"
#include "ini2.h"
#include "otherfunctions.h"
#include "enbitmap.h"
#include "TaskbarNotifier.h"
#include "emuledlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define IDT_HIDDEN 0
#define IDT_APPEARING 1
#define IDT_WAITING 2
#define IDT_DISAPPEARING 3
#define TASKBAR_X_TOLERANCE 10
#define TASKBAR_Y_TOLERANCE 10
inline bool NearlyEqual(int a, int b, int epsilon)
{
return abs(a - b) < epsilon / 2;
}
// CTaskbarNotifier
IMPLEMENT_DYNAMIC(CTaskbarNotifier, CWnd)
BEGIN_MESSAGE_MAP(CTaskbarNotifier, CWnd)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_SETCURSOR()
ON_WM_TIMER()
END_MESSAGE_MAP()
CTaskbarNotifier::CTaskbarNotifier()
{
m_strCaption="";
m_pWndParent=NULL;
m_bMouseIsOver=FALSE;
m_hBitmapRegion=NULL;
m_hCursor=NULL;
m_crNormalTextColor=RGB(133,146,181);
m_crSelectedTextColor=RGB(10,36,106);
m_nBitmapHeight=0;
m_nBitmapWidth=0;
m_dwTimeToStay=0;
m_dwShowEvents=0;
m_dwHideEvents=0;
m_nCurrentPosX=0;
m_nCurrentPosY=0;
m_nCurrentWidth=0;
m_nCurrentHeight=0;
m_nIncrementShow=0;
m_nIncrementHide=0;
m_dwTimeToShow=500;
m_dwTimeToStay=4000;
m_dwTimeToHide=200;
m_nTaskbarPlacement=ABE_BOTTOM;
m_nAnimStatus=IDT_HIDDEN;
m_rcText.SetRect(0,0,0,0);
m_rcCloseBtn.SetRect(0,0,0,0);
m_uTextFormat=DT_MODIFYSTRING | DT_WORDBREAK | DT_PATH_ELLIPSIS | DT_END_ELLIPSIS; // Default Text format (see DrawText in the win32 API for the different values)
m_hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(32649)); // System Hand cursor
m_nHistoryPosition = 0;
m_nActiveMessageType = TBN_NULL;
m_bTextSelected = FALSE;
m_bAutoClose = TRUE;
// If running on NT, timer precision is 10 ms, if not timer precision is 50 ms
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if (osvi.dwPlatformId==VER_PLATFORM_WIN32_NT)
m_dwTimerPrecision=10;
else
m_dwTimerPrecision=50;
SetTextDefaultFont(); // We use default GUI Font
}
CTaskbarNotifier::~CTaskbarNotifier()
{
while (m_MessageHistory.GetCount() > 0)
{
CTaskbarNotifierHistory* messagePTR = (CTaskbarNotifierHistory*)m_MessageHistory.RemoveTail();
delete messagePTR;
}
}
#ifdef _UNICODE
LRESULT CALLBACK My_AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
#endif
int CTaskbarNotifier::Create(CWnd *pWndParent)
{
ASSERT(pWndParent!=NULL);
m_pWndParent=pWndParent;
WNDCLASSEX wcx;
wcx.cbSize = sizeof(wcx);
#ifdef _UNICODE
// From: http://www.trigeminal.com/usenet/usenet031.asp?1033
// Subject: If you are using MFC 6.0 or 7.0 and you want to use MSLU...
//
// There is one additional problem that can occur if you are using AfxWndProc (MFC's main, shared window
// proc wrapper) as an actual wndproc in any of your windows. You see, MFC has code in it so that if AfxWndProc
// is called and is told that the wndproc to follow up with is AfxWndProc, it notices that it is being asked to
// call itself and forwards for DefWindowProc instead.
//
// Unfortunately, MSLU breaks this code by having its own proc be the one that shows up. MFC has no way of
// detecting this case so it calls the MSLU proc which calls AfxWndProc which calls the MSLU proc, etc., until
// the stack overflows. By using either DefWindowProc or your own proc yourself, you avoid the stack overflow.
extern bool g_bUnicoWS;
if (g_bUnicoWS)
wcx.lpfnWndProc = My_AfxWndProc;
else
wcx.lpfnWndProc = AfxWndProc;
#else
wcx.lpfnWndProc = AfxWndProc;
#endif
wcx.style = CS_DBLCLKS|CS_SAVEBITS;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = AfxGetInstanceHandle();
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL,IDC_ARROW);
wcx.hbrBackground=::GetSysColorBrush(COLOR_WINDOW);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = _T("TaskbarNotifierClass");
wcx.hIconSm = NULL;
RegisterClassEx(&wcx);
return CreateEx(WS_EX_TOPMOST,_T("TaskbarNotifierClass"),NULL,WS_POPUP,0,0,0,0,pWndParent->m_hWnd,NULL);
}
BOOL CTaskbarNotifier::LoadConfiguration(LPCTSTR szFileName)
{
TCHAR buffer[510];
int nRed, nGreen, nBlue, sRed, sGreen, sBlue;
int rcLeft, rcTop, rcRight, rcBottom;
int bmpTrasparentRed, bmpTrasparentGreen, bmpTrasparentBlue;
int fontSize;
CString fontType, bmpFullPath;
Hide();
CIni ini(szFileName,_T("CONFIG"));
_tcscpy(buffer, szFileName);
LPTSTR pszFileName = _tcsrchr(buffer, _T('\\'));
if (pszFileName != NULL) {
*(pszFileName+1) = _T('\0');
}
else
return FALSE;
nRed = ini.GetInt(_T("TextNormalRed"),255);
nGreen = ini.GetInt(_T("TextNormalGreen"),255);
nBlue = ini.GetInt(_T("TextNormalBlue"),255);
sRed = ini.GetInt(_T("TextSelectedRed"),255);
sGreen = ini.GetInt(_T("TextSelectedGreen"),255);
sBlue = ini.GetInt(_T("TextSelectedBlue"),255);
bmpTrasparentRed = ini.GetInt(_T("bmpTrasparentRed"),255);
bmpTrasparentGreen = ini.GetInt(_T("bmpTrasparentGreen"),0);
bmpTrasparentBlue = ini.GetInt(_T("bmpTrasparentBlue"),255);
fontSize = ini.GetInt(_T("TextFontSize"),85); //VeryCD版,修改默认字体大小
m_dwTimeToStay = ini.GetInt(_T("TimeToStay"), 4000);
m_dwTimeToShow = ini.GetInt(_T("TimeToShow"), 500);
m_dwTimeToHide = ini.GetInt(_T("TimeToHide"), 200);
fontType = ini.GetString(_T("FontType"), _T("Arial"));
bmpFullPath.Format(_T("%s\\%s"), buffer, ini.GetString(_T("bmpFileName"), _T("")));
// get text rectangle coordinates
rcLeft = ini.GetInt(_T("rcTextLeft"),5);
rcTop = ini.GetInt(_T("rcTextTop"),45);
rcRight = ini.GetInt(_T("rcTextRight"),220 );
rcBottom = ini.GetInt(_T("rcTextBottom"), 85);
if (rcLeft<=0) rcLeft=1;
if (rcTop<=0) rcTop=1;
if (rcRight<=0) rcRight=1;
if (rcBottom<=0) rcBottom=1;
SetTextRect(CRect(rcLeft,rcTop,rcRight,rcBottom));
// get close button rectangle coordinates
rcLeft = ini.GetInt(_T("rcCloseBtnLeft"),286);
rcTop = ini.GetInt(_T("rcCloseBtnTop"),40);
rcRight = ini.GetInt(_T("rcCloseBtnRight"), 300);
rcBottom = ini.GetInt(_T("rcCloseBtnBottom"), 54);
if (rcLeft<=0) rcLeft=1;
if (rcTop<=0) rcTop=1;
if (rcRight<=0) rcRight=1;
if (rcBottom<=0) rcBottom=1;
SetCloseBtnRect(CRect(rcLeft,rcTop,rcRight,rcBottom));
// get history button rectangle coordinates
rcLeft = ini.GetInt(_T("rcHistoryBtnLeft"),283);
rcTop = ini.GetInt(_T("rcHistoryBtnTop"),14);
rcRight = ini.GetInt(_T("rcHistoryBtnRight"), 299);
rcBottom = ini.GetInt(_T("rcHistoryBtnBottom"), 39);
if (rcLeft<=0) rcLeft=1;
if (rcTop<=0) rcTop=1;
if (rcRight<=0) rcRight=1;
if (rcBottom<=0) rcBottom=1;
SetHistoryBtnRect(CRect(rcLeft,rcTop,rcRight,rcBottom));
if (!SetBitmap(bmpFullPath, bmpTrasparentRed, bmpTrasparentGreen, bmpTrasparentBlue))
{
CEnBitmap m_imgTaskbar;
VERIFY (m_imgTaskbar.LoadImage(IDR_TASKBAR,_T("GIF")));
if (!SetBitmap(&m_imgTaskbar, bmpTrasparentRed, bmpTrasparentGreen, bmpTrasparentBlue))
return FALSE;
}
SetTextFont(fontType, fontSize,TN_TEXT_NORMAL,TN_TEXT_UNDERLINE);
SetTextColor(RGB(nRed,nGreen,nBlue),RGB(sRed,sGreen,sBlue));
return TRUE;
}
void CTaskbarNotifier::SetTextFont(LPCTSTR szFont,int nSize,int nNormalStyle,int nSelectedStyle)
{
LOGFONT lf;
m_myNormalFont.DeleteObject();
m_myNormalFont.CreatePointFont(nSize,szFont);
m_myNormalFont.GetLogFont(&lf);
// We set the Font of the unselected ITEM
if (nNormalStyle & TN_TEXT_BOLD)
lf.lfWeight = FW_BOLD;
else
lf.lfWeight = FW_NORMAL;
if (nNormalStyle & TN_TEXT_ITALIC)
lf.lfItalic=TRUE;
else
lf.lfItalic=FALSE;
if (nNormalStyle & TN_TEXT_UNDERLINE)
lf.lfUnderline=TRUE;
else
lf.lfUnderline=FALSE;
m_myNormalFont.DeleteObject();
m_myNormalFont.CreateFontIndirect(&lf);
// We set the Font of the selected ITEM
if (nSelectedStyle & TN_TEXT_BOLD)
lf.lfWeight = FW_BOLD;
else
lf.lfWeight = FW_NORMAL;
if (nSelectedStyle & TN_TEXT_ITALIC)
lf.lfItalic=TRUE;
else
lf.lfItalic=FALSE;
if (nSelectedStyle & TN_TEXT_UNDERLINE)
lf.lfUnderline=TRUE;
else
lf.lfUnderline=FALSE;
m_mySelectedFont.DeleteObject();
m_mySelectedFont.CreateFontIndirect(&lf);
}
void CTaskbarNotifier::SetTextDefaultFont()
{
LOGFONT lf;
CFont *pFont=CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
pFont->GetLogFont(&lf);
m_myNormalFont.DeleteObject();
m_mySelectedFont.DeleteObject();
m_myNormalFont.CreateFontIndirect(&lf);
lf.lfUnderline=TRUE;
m_mySelectedFont.CreateFontIndirect(&lf);
}
void CTaskbarNotifier::SetTextColor(COLORREF crNormalTextColor,COLORREF crSelectedTextColor)
{
m_crNormalTextColor=crNormalTextColor;
m_crSelectedTextColor=crSelectedTextColor;
RedrawWindow();
}
void CTaskbarNotifier::SetTextRect(RECT rcText)
{
m_rcText = rcText;
}
void CTaskbarNotifier::SetCloseBtnRect(RECT rcCloseBtn)
{
m_rcCloseBtn=rcCloseBtn;
}
void CTaskbarNotifier::SetHistoryBtnRect(RECT rcHistoryBtn)
{
m_rcHistoryBtn=rcHistoryBtn;
}
void CTaskbarNotifier::SetTextFormat(UINT uTextFormat)
{
m_uTextFormat=uTextFormat;
}
BOOL CTaskbarNotifier::SetBitmap(UINT nBitmapID,short red,short green,short blue)
{
m_bitmapBackground.DeleteObject();
if (!m_bitmapBackground.LoadBitmap(nBitmapID))
return FALSE;
BITMAP bm;
GetObject(m_bitmapBackground.GetSafeHandle(), sizeof(bm), &bm);
m_nBitmapWidth = bm.bmWidth;
m_nBitmapHeight = bm.bmHeight;
if (red!=-1 && green!=-1 && blue!=-1)
{
// No need to delete the HRGN, SetWindowRgn() owns it after being called
m_hBitmapRegion=CreateRgnFromBitmap((HBITMAP)m_bitmapBackground.GetSafeHandle(),RGB(red,green,blue));
SetWindowRgn(m_hBitmapRegion, true);
}
return TRUE;
}
BOOL CTaskbarNotifier::SetBitmap(CBitmap* Bitmap,short red,short green,short blue)
{
m_bitmapBackground.DeleteObject();
if (!m_bitmapBackground.Attach(Bitmap->Detach()))
return FALSE;
BITMAP bm;
GetObject(m_bitmapBackground.GetSafeHandle(), sizeof(bm), &bm);
m_nBitmapWidth = bm.bmWidth;
m_nBitmapHeight = bm.bmHeight;
if (red!=-1 && green!=-1 && blue!=-1)
{
// No need to delete the HRGN, SetWindowRgn() owns it after being called
m_hBitmapRegion=CreateRgnFromBitmap((HBITMAP)m_bitmapBackground.GetSafeHandle(),RGB(red,green,blue));
SetWindowRgn(m_hBitmapRegion, true);
}
return TRUE;
}
BOOL CTaskbarNotifier::SetBitmap(LPCTSTR szFileName,short red,short green,short blue)
{
if (szFileName==NULL || szFileName[0]==_T('\0'))
return FALSE;
HBITMAP hBmp = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(),szFileName,IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
if (!hBmp)
return FALSE;
m_bitmapBackground.DeleteObject();
m_bitmapBackground.Attach(hBmp);
BITMAP bm;
GetObject(m_bitmapBackground.GetSafeHandle(), sizeof(bm), &bm);
m_nBitmapWidth = bm.bmWidth;
m_nBitmapHeight = bm.bmHeight;
if (red!=-1 && green!=-1 && blue!=-1)
{
// No need to delete the HRGN, SetWindowRgn() owns it after being called
m_hBitmapRegion=CreateRgnFromBitmap((HBITMAP)m_bitmapBackground.GetSafeHandle(),RGB(red,green,blue));
SetWindowRgn(m_hBitmapRegion, true);
}
return TRUE;
}
void CTaskbarNotifier::SetAutoClose(BOOL autoClose)
{
m_bAutoClose = autoClose;
if (autoClose == TRUE) {
switch (m_nAnimStatus)
{
case IDT_APPEARING:
KillTimer(IDT_APPEARING);
break;
case IDT_WAITING:
KillTimer(IDT_WAITING);
break;
case IDT_DISAPPEARING:
KillTimer(IDT_DISAPPEARING);
break;
}
m_nAnimStatus = IDT_DISAPPEARING;
SetTimer(IDT_DISAPPEARING, m_dwHideEvents, NULL);
}
}
void CTaskbarNotifier::ShowLastHistoryMessage()
{
if (m_MessageHistory.GetCount() > 0)
{
CTaskbarNotifierHistory* messagePTR = (CTaskbarNotifierHistory*)m_MessageHistory.RemoveHead();
Show(messagePTR->m_strMessage, messagePTR->m_nMessageType, messagePTR->m_strLink);
delete messagePTR;
}
else
Show(GetResString(IDS_TBN_NOMESSAGEHISTORY), TBN_NULL, NULL);
}
void CTaskbarNotifier::Show(LPCTSTR szCaption, int nMsgType, LPCTSTR pszLink, BOOL bAutoClose)
{
if (nMsgType == TBN_NONOTIFY)
return;
UINT nScreenWidth;
UINT nScreenHeight;
UINT nEvents;
UINT nBitmapSize;
CRect rcTaskbar;
CTaskbarNotifierHistory* messagePTR;
m_strCaption = szCaption;
m_nActiveMessageType = nMsgType;
m_strLink = pszLink;
if (m_bAutoClose) // sets it only if already true, else wait for user action
m_bAutoClose = bAutoClose;
if ((nMsgType != TBN_NULL) && (nMsgType != TBN_LOG) && (nMsgType != TBN_IMPORTANTEVENT))
{
//Add element into string list. Max 5 elements.
if (m_MessageHistory.GetCount() == 5) {
messagePTR = (CTaskbarNotifierHistory*)m_MessageHistory.RemoveHead();
delete messagePTR;
messagePTR = NULL;
}
messagePTR = new CTaskbarNotifierHistory;
messagePTR->m_strMessage = m_strCaption;
messagePTR->m_nMessageType = nMsgType;
messagePTR->m_strLink = m_strLink;
m_MessageHistory.AddTail(messagePTR);
}
nScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
HWND hWndTaskbar = ::FindWindow(_T("Shell_TrayWnd"), 0);
::GetWindowRect(hWndTaskbar, &rcTaskbar);
// Daniel Lohmann: Calculate taskbar position from its window rect. However, on XP it may be that
// the taskbar is slightly larger or smaller than the screen size. Therefore we allow some tolerance here.
if (NearlyEqual(rcTaskbar.left, 0, TASKBAR_X_TOLERANCE) && NearlyEqual(rcTaskbar.right, nScreenWidth, TASKBAR_X_TOLERANCE))
{
// Taskbar is on top or on bottom
m_nTaskbarPlacement = NearlyEqual(rcTaskbar.top, 0, TASKBAR_Y_TOLERANCE) ? ABE_TOP : ABE_BOTTOM;
nBitmapSize = m_nBitmapHeight;
}
else
{
// Taskbar is on left or on right
m_nTaskbarPlacement = NearlyEqual(rcTaskbar.left, 0, TASKBAR_X_TOLERANCE) ? ABE_LEFT : ABE_RIGHT;
nBitmapSize = m_nBitmapWidth;
}
// We calculate the pixel increment and the timer value for the showing animation
if (m_dwTimeToShow > m_dwTimerPrecision)
{
nEvents = min((m_dwTimeToShow / m_dwTimerPrecision) / 2, nBitmapSize); //<<-- enkeyDEV(Ottavio84) -Reduced frames of a half-
m_dwShowEvents = m_dwTimeToShow / nEvents;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -