2009-02-10 18:37:48 +00:00
/*
Copyright ( C ) 2004 Kimmo Pekkola
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# define _WIN32_IE 0x0600
# pragma warning(disable: 4996)
# include "TrayWindow.h"
# include "Resource.h"
# include "Litestep.h"
# include "Rainmeter.h"
# include "AboutDialog.h"
# include "Error.h"
# include <io.h>
# include <ShellAPI.h>
# define TRAYTIMER 3
extern CRainmeter * Rainmeter ;
using namespace Gdiplus ;
CTrayWindow : : CTrayWindow ( HINSTANCE instance )
{
WNDCLASS wc ;
wc . style = 0 ;
wc . lpfnWndProc = ( WNDPROC ) WndProc ;
wc . cbClsExtra = 0 ;
wc . cbWndExtra = 0 ;
wc . hInstance = instance ;
wc . hIcon = NULL ;
wc . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wc . hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc . lpszMenuName = NULL ;
wc . lpszClassName = L " RainmeterTrayClass " ;
RegisterClass ( & wc ) ;
m_Window = CreateWindowEx (
WS_EX_TOOLWINDOW ,
L " RainmeterTrayClass " ,
NULL ,
WS_POPUP ,
CW_USEDEFAULT ,
CW_USEDEFAULT ,
CW_USEDEFAULT ,
CW_USEDEFAULT ,
NULL ,
NULL ,
instance ,
this ) ;
m_Instance = instance ;
m_Measure = NULL ;
m_TrayIcon = NULL ;
m_MeterType = TRAY_METER_TYPE_HISTOGRAM ;
m_TrayColor1 = Color ( 0 , 100 , 0 ) ;
m_TrayColor2 = Color ( 0 , 255 , 0 ) ;
m_Bitmap = NULL ;
# ifndef _WIN64
SetWindowLong ( m_Window , GWL_USERDATA , magicDWord ) ;
# endif
m_TrayPos = 0 ;
memset ( m_TrayValues , 0 , sizeof ( double ) * TRAYICON_SIZE ) ;
}
CTrayWindow : : ~ CTrayWindow ( )
{
KillTimer ( m_Window , TRAYTIMER ) ;
RemoveTrayIcon ( ) ;
if ( m_Bitmap ) delete m_Bitmap ;
if ( m_Measure ) delete m_Measure ;
2009-02-14 10:11:28 +00:00
for ( size_t i = 0 ; i < m_TrayIcons . size ( ) ; i + + )
2009-02-10 18:37:48 +00:00
{
DestroyIcon ( m_TrayIcons [ i ] ) ;
}
m_TrayIcons . clear ( ) ;
if ( m_Window ) DestroyWindow ( m_Window ) ;
}
BOOL CTrayWindow : : AddTrayIcon ( )
{
BOOL res = FALSE ;
NOTIFYICONDATA tnid ;
if ( m_TrayIcon )
{
DestroyIcon ( m_TrayIcon ) ;
m_TrayIcon = NULL ;
}
m_TrayIcon = CreateTrayIcon ( 0 ) ;
if ( m_TrayIcon )
{
tnid . cbSize = sizeof ( NOTIFYICONDATA ) ;
tnid . hWnd = m_Window ;
tnid . uID = IDI_TRAY ;
tnid . uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP ;
tnid . uCallbackMessage = WM_NOTIFYICON ;
tnid . hIcon = m_TrayIcon ;
lstrcpyn ( tnid . szTip , L " Rainmeter " , sizeof ( tnid . szTip ) ) ;
res = Shell_NotifyIcon ( NIM_ADD , & tnid ) ;
}
return res ;
}
BOOL CTrayWindow : : RemoveTrayIcon ( )
{
BOOL res = FALSE ;
if ( m_TrayIcon )
{
NOTIFYICONDATA tnid ;
tnid . cbSize = sizeof ( NOTIFYICONDATA ) ;
tnid . hWnd = m_Window ;
tnid . uID = IDI_TRAY ;
tnid . uFlags = 0 ;
res = Shell_NotifyIcon ( NIM_DELETE , & tnid ) ;
DestroyIcon ( m_TrayIcon ) ;
m_TrayIcon = NULL ;
}
return res ;
}
BOOL CTrayWindow : : ModifyTrayIcon ( double value )
{
BOOL res = FALSE ;
NOTIFYICONDATA tnid ;
if ( m_TrayIcon )
{
DestroyIcon ( m_TrayIcon ) ;
m_TrayIcon = NULL ;
}
m_TrayIcon = CreateTrayIcon ( value ) ;
tnid . cbSize = sizeof ( NOTIFYICONDATA ) ;
tnid . hWnd = m_Window ;
tnid . uID = IDI_TRAY ;
tnid . uFlags = NIF_ICON ;
tnid . hIcon = m_TrayIcon ;
res = Shell_NotifyIcon ( NIM_MODIFY , & tnid ) ;
return res ;
}
BOOL CTrayWindow : : ShowBalloonHelp ( )
{
BOOL res = FALSE ;
NOTIFYICONDATA nid ;
memset ( & nid , 0 , sizeof ( NOTIFYICONDATA ) ) ;
nid . hWnd = m_Window ;
nid . uID = IDI_TRAY ;
nid . cbSize = sizeof ( NOTIFYICONDATA ) ;
nid . uFlags = NIF_INFO ;
nid . uTimeout = 30000 ;
nid . dwInfoFlags = 4 ; // NIIF_USER;
nid . hIcon = LoadIcon ( m_Instance , MAKEINTRESOURCE ( IDI_TRAY ) ) ;
wcscpy ( nid . szInfo , L " There aren't any configs active at the moment. Open the context menu from Rainmeter's tray icon and select a config you want to use. " ) ;
wcscpy ( nid . szInfoTitle , L " Rainmeter " ) ;
res = Shell_NotifyIcon ( NIM_MODIFY , & nid ) ;
return res ;
}
HICON CTrayWindow : : CreateTrayIcon ( double value )
{
if ( m_Measure = = NULL )
{
return LoadIcon ( m_Instance , MAKEINTRESOURCE ( IDI_TRAY ) ) ;
}
else
{
if ( m_MeterType = = TRAY_METER_TYPE_HISTOGRAM )
{
m_TrayValues [ m_TrayPos ] = value ;
m_TrayPos = ( m_TrayPos + 1 ) % TRAYICON_SIZE ;
Bitmap trayBitmap ( TRAYICON_SIZE , TRAYICON_SIZE ) ;
Graphics graphics ( & trayBitmap ) ;
graphics . SetSmoothingMode ( SmoothingModeAntiAlias ) ;
Point points [ TRAYICON_SIZE + 2 ] ;
points [ 0 ] . X = 0 ;
points [ 0 ] . Y = TRAYICON_SIZE ;
points [ TRAYICON_SIZE + 1 ] . X = TRAYICON_SIZE - 1 ;
points [ TRAYICON_SIZE + 1 ] . Y = TRAYICON_SIZE ;
for ( int i = 0 ; i < TRAYICON_SIZE ; i + + )
{
points [ i + 1 ] . X = i ;
points [ i + 1 ] . Y = ( int ) ( TRAYICON_SIZE * ( 1.0 - m_TrayValues [ ( m_TrayPos + i ) % TRAYICON_SIZE ] ) ) ;
}
SolidBrush brush ( m_TrayColor1 ) ;
graphics . FillRectangle ( & brush , 0 , 0 , TRAYICON_SIZE , TRAYICON_SIZE ) ;
SolidBrush brush2 ( m_TrayColor2 ) ;
graphics . FillPolygon ( & brush2 , points , TRAYICON_SIZE + 2 ) ;
HICON icon ;
trayBitmap . GetHICON ( & icon ) ;
return icon ;
}
else if ( m_MeterType = = TRAY_METER_TYPE_BITMAP & & ( m_Bitmap | | m_TrayIcons . size ( ) > 0 ) )
{
if ( m_TrayIcons . size ( ) > 0 )
{
size_t frame = 0 ;
size_t frameCount = m_TrayIcons . size ( ) ;
// Select the correct frame linearly
frame = ( size_t ) ( value * frameCount ) ;
frame = min ( ( frameCount - 1 ) , frame ) ;
return CopyIcon ( m_TrayIcons [ frame ] ) ;
}
else
{
int frame = 0 ;
int frameCount = 0 ;
int newX , newY ;
if ( m_Bitmap - > GetWidth ( ) > m_Bitmap - > GetHeight ( ) )
{
frameCount = m_Bitmap - > GetWidth ( ) / TRAYICON_SIZE ;
}
else
{
frameCount = m_Bitmap - > GetHeight ( ) / TRAYICON_SIZE ;
}
// Select the correct frame linearly
frame = ( int ) ( value * frameCount ) ;
frame = min ( ( frameCount - 1 ) , frame ) ;
if ( m_Bitmap - > GetWidth ( ) > m_Bitmap - > GetHeight ( ) )
{
newX = frame * TRAYICON_SIZE ;
newY = 0 ;
}
else
{
newX = 0 ;
newY = frame * TRAYICON_SIZE ;
}
Bitmap trayBitmap ( TRAYICON_SIZE , TRAYICON_SIZE ) ;
Graphics graphics ( & trayBitmap ) ;
graphics . SetSmoothingMode ( SmoothingModeAntiAlias ) ;
// Blit the image
Rect r ( 0 , 0 , TRAYICON_SIZE , TRAYICON_SIZE ) ;
graphics . DrawImage ( m_Bitmap , r , newX , newY , TRAYICON_SIZE , TRAYICON_SIZE , UnitPixel ) ;
HICON icon ;
trayBitmap . GetHICON ( & icon ) ;
return icon ;
}
}
}
return NULL ;
}
void CTrayWindow : : ReadConfig ( CConfigParser & parser )
{
2009-02-14 10:11:28 +00:00
for ( size_t i = 0 ; i < m_TrayIcons . size ( ) ; i + + )
2009-02-10 18:37:48 +00:00
{
DestroyIcon ( m_TrayIcons [ i ] ) ;
}
m_TrayIcons . clear ( ) ;
std : : wstring measureName = parser . ReadString ( L " TrayMeasure " , L " Measure " , L " " ) ;
CConfigParser * oldParser = Rainmeter - > GetCurrentParser ( ) ;
Rainmeter - > SetCurrentParser ( & parser ) ;
if ( ! measureName . empty ( ) )
{
m_Measure = CMeasure : : Create ( measureName . c_str ( ) , NULL ) ;
m_Measure - > SetName ( L " TrayMeasure " ) ;
m_Measure - > ReadConfig ( parser , L " TrayMeasure " ) ;
}
Rainmeter - > SetCurrentParser ( oldParser ) ;
m_MeterType = TRAY_METER_TYPE_NONE ;
std : : wstring type = parser . ReadString ( L " TrayMeasure " , L " TrayMeter " , L " HISTOGRAM " ) ;
if ( wcsicmp ( type . c_str ( ) , L " HISTOGRAM " ) = = 0 )
{
m_MeterType = TRAY_METER_TYPE_HISTOGRAM ;
m_TrayColor1 = parser . ReadColor ( L " TrayMeasure " , L " TrayColor1 " , Color ( 0 , 100 , 0 ) ) ;
m_TrayColor2 = parser . ReadColor ( L " TrayMeasure " , L " TrayColor2 " , Color ( 0 , 255 , 0 ) ) ;
}
else if ( wcsicmp ( type . c_str ( ) , L " BITMAP " ) = = 0 )
{
m_MeterType = TRAY_METER_TYPE_BITMAP ;
std : : wstring imageName = parser . ReadString ( L " TrayMeasure " , L " TrayBitmap " , L " " ) ;
// Load the bitmaps if defined
if ( ! imageName . empty ( ) )
{
imageName = Rainmeter - > FixPath ( imageName , PATH_FOLDER_SKINS , L " " ) ;
if ( imageName . size ( ) > 3 )
{
std : : wstring extension = imageName . substr ( imageName . size ( ) - 3 ) ;
if ( extension = = L " ico " | | extension = = L " ICO " )
{
int count = 1 ;
HICON hIcon = NULL ;
// Load the icons
do
{
WCHAR buffer [ MAX_PATH ] ;
wsprintf ( buffer , imageName . c_str ( ) , count + + ) ;
hIcon = ( HICON ) LoadImage ( NULL , buffer , IMAGE_ICON , TRAYICON_SIZE , TRAYICON_SIZE , LR_LOADFROMFILE ) ;
if ( hIcon ) m_TrayIcons . push_back ( hIcon ) ;
if ( imageName = = buffer ) break ;
} while ( hIcon ! = NULL ) ;
}
}
if ( m_TrayIcons . size ( ) = = 0 )
{
// No icons found so load as bitmap
if ( m_Bitmap )
{
delete m_Bitmap ;
}
m_Bitmap = new Bitmap ( imageName . c_str ( ) ) ;
Status status = m_Bitmap - > GetLastStatus ( ) ;
if ( Ok ! = status )
{
DebugLog ( L " Bitmap image not found: %s " , imageName . c_str ( ) ) ;
delete m_Bitmap ;
m_Bitmap = NULL ;
}
}
}
}
else
{
DebugLog ( L " No such TrayMeter: %s " , type . c_str ( ) ) ;
}
int trayIcon = parser . ReadInt ( L " Rainmeter " , L " TrayIcon " , 1 ) ;
if ( trayIcon ! = 0 )
{
AddTrayIcon ( ) ;
SetTimer ( m_Window , TRAYTIMER , 1000 , NULL ) ; // Update the tray once per sec
}
}
LRESULT CALLBACK CTrayWindow : : WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
static CTrayWindow * tray = NULL ;
if ( uMsg = = WM_CREATE )
{
tray = ( CTrayWindow * ) ( ( LPCREATESTRUCT ) lParam ) - > lpCreateParams ;
}
switch ( uMsg )
{
case WM_COMMAND :
if ( Rainmeter & & tray )
{
if ( wParam = = ID_CONTEXT_ABOUT )
{
OpenAboutDialog ( tray - > GetWindow ( ) , Rainmeter - > GetInstance ( ) ) ;
}
else if ( wParam = = ID_CONTEXT_SHOW_HELP )
{
std : : wstring help = Rainmeter - > GetPath ( ) ;
2009-04-21 16:07:13 +00:00
help = L " \" " + help + L " Rainmeter.chm \" " ;
2009-02-10 18:37:48 +00:00
LSExecute ( NULL , help . c_str ( ) , SW_SHOWNORMAL ) ;
}
else if ( wParam = = ID_CONTEXT_REFRESH )
{
// Read skins and settings
Rainmeter - > ReloadSettings ( ) ;
// Refresh all
RainmeterRefresh ( tray - > GetWindow ( ) , NULL ) ;
}
else if ( wParam = = ID_CONTEXT_SHOWLOGFILE )
{
// Check if the file exists
std : : wstring log = Rainmeter - > GetPath ( ) ;
log + = L " Rainmeter.log " ;
if ( _waccess ( log . c_str ( ) , 0 ) ! = - 1 )
{
std : : wstring command = L " Notepad.exe " ;
command + = log ;
LSExecute ( tray - > GetWindow ( ) , command . c_str ( ) , SW_SHOWNORMAL ) ;
}
else
{
int res = MessageBox ( tray - > GetWindow ( ) , L " The log file doesn't exist. \n Do you want to create it? " , L " Rainmeter " , MB_YESNO | MB_ICONQUESTION ) ;
if ( res = = IDYES )
{
HANDLE file = CreateFile ( log . c_str ( ) , GENERIC_WRITE , 0 , NULL , CREATE_NEW , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( file ! = INVALID_HANDLE_VALUE )
{
CloseHandle ( file ) ;
ResetLoggingFlag ( ) ; // Re-enable logging
std : : wstring message ;
message = L " Created file: " ;
message + = log ;
message + = L " \n Delete it to disable Rainmeter's logging " ;
MessageBox ( tray - > GetWindow ( ) , message . c_str ( ) , L " Rainmeter " , MB_OK | MB_ICONINFORMATION ) ;
std : : wstring command = L " Notepad.exe " ;
command + = log ;
LSExecute ( tray - > GetWindow ( ) , command . c_str ( ) , SW_SHOWNORMAL ) ;
}
else
{
std : : wstring message ;
message = L " Unable to create the file: " ;
message + = log ;
MessageBox ( tray - > GetWindow ( ) , message . c_str ( ) , L " Rainmeter " , MB_OK | MB_ICONERROR ) ;
}
}
}
}
else if ( wParam = = ID_CONTEXT_EDITCONFIG )
{
std : : wstring command = Rainmeter - > GetConfigEditor ( ) ;
command + = L " \" " ;
command + = Rainmeter - > GetIniFile ( ) ;
LSExecute ( tray - > GetWindow ( ) , command . c_str ( ) , SW_SHOWNORMAL ) ;
}
else if ( wParam = = ID_CONTEXT_QUIT )
{
if ( Rainmeter - > GetDummyLitestep ( ) ) PostQuitMessage ( 0 ) ;
quitModule ( Rainmeter - > GetInstance ( ) ) ;
}
else if ( ( wParam & 0x0ffff ) > = ID_CONFIG_FIRST )
{
wParam = wParam & 0x0ffff ;
// Check which config was selected
const std : : vector < CRainmeter : : CONFIG > & configs = Rainmeter - > GetAllConfigs ( ) ;
2009-02-14 10:11:28 +00:00
for ( size_t i = 0 ; i < configs . size ( ) ; i + + )
2009-02-10 18:37:48 +00:00
{
2009-02-14 10:11:28 +00:00
for ( size_t j = 0 ; j < configs [ i ] . commands . size ( ) ; j + + )
2009-02-10 18:37:48 +00:00
{
if ( configs [ i ] . commands [ j ] = = wParam )
{
if ( configs [ i ] . active = = j + 1 )
{
CMeterWindow * meterWindow = Rainmeter - > GetMeterWindow ( configs [ i ] . config ) ;
Rainmeter - > DeactivateConfig ( meterWindow , i ) ;
}
else
{
if ( configs [ i ] . active ! = 0 )
{
CMeterWindow * meterWindow = Rainmeter - > GetMeterWindow ( configs [ i ] . config ) ;
if ( meterWindow )
{
Rainmeter - > DeactivateConfig ( meterWindow , i ) ;
}
}
Rainmeter - > ActivateConfig ( i , j ) ;
}
return 0 ;
}
}
}
}
else
{
// Forward the message to correct window
int index = ( int ) ( wParam > > 16 ) ;
std : : map < std : : wstring , CMeterWindow * > & windows = Rainmeter - > GetAllMeterWindows ( ) ;
2009-02-14 10:11:28 +00:00
if ( index < ( int ) windows . size ( ) )
2009-02-10 18:37:48 +00:00
{
std : : map < std : : wstring , CMeterWindow * > : : iterator iter = windows . begin ( ) ;
for ( ; iter ! = windows . end ( ) ; iter + + )
{
index - - ;
if ( index < 0 )
{
CMeterWindow * meterWindow = ( * iter ) . second ;
SendMessage ( meterWindow - > GetWindow ( ) , WM_COMMAND , wParam & 0x0FFFF , NULL ) ;
break ;
}
}
}
}
}
return 0 ; // Don't send WM_COMMANDS any further
case WM_NOTIFYICON :
{
UINT uMouseMsg = ( UINT ) lParam ;
std : : wstring bang ;
switch ( uMouseMsg )
{
case WM_LBUTTONDOWN :
bang = Rainmeter - > GetTrayExecuteL ( ) ;
break ;
case WM_MBUTTONDOWN :
bang = Rainmeter - > GetTrayExecuteM ( ) ;
break ;
case WM_RBUTTONDOWN :
bang = Rainmeter - > GetTrayExecuteR ( ) ;
break ;
case WM_LBUTTONDBLCLK :
bang = Rainmeter - > GetTrayExecuteDL ( ) ;
break ;
case WM_MBUTTONDBLCLK :
bang = Rainmeter - > GetTrayExecuteDM ( ) ;
break ;
case WM_RBUTTONDBLCLK :
bang = Rainmeter - > GetTrayExecuteDR ( ) ;
break ;
}
if ( ! bang . empty ( ) )
{
std : : wstring arg ;
size_t pos = bang . find ( L ' ' ) ;
if ( pos ! = std : : wstring : : npos )
{
arg = bang ;
arg . erase ( 0 , pos + 1 ) ;
bang = bang . substr ( 0 , pos ) ;
}
Rainmeter - > ExecuteBang ( bang , arg , NULL ) ;
}
else if ( uMouseMsg = = WM_RBUTTONDOWN )
{
POINT point ;
GetCursorPos ( & point ) ;
SetForegroundWindow ( tray - > m_Window ) ;
Rainmeter - > ShowContextMenu ( point , NULL ) ;
SetForegroundWindow ( tray - > m_Window ) ;
}
}
break ;
case WM_TIMER :
if ( tray & & tray - > m_Measure )
{
tray - > m_Measure - > Update ( ) ;
tray - > ModifyTrayIcon ( tray - > m_Measure - > GetRelativeValue ( ) ) ;
}
break ;
case WM_DESTROY :
if ( Rainmeter - > GetDummyLitestep ( ) ) PostQuitMessage ( 0 ) ;
break ;
case LM_GETREVID :
if ( lParam ! = NULL )
{
char * Buffer = ( char * ) lParam ;
if ( wParam = = 0 )
{
sprintf ( Buffer , " Rainmeter.dll: %s " , APPVERSION ) ;
}
else if ( wParam = = 1 )
{
sprintf ( Buffer , " Rainmeter.dll: %s %s, Rainy " , APPVERSION , __DATE__ ) ;
}
else
{
Buffer [ 0 ] = 0 ;
}
return strlen ( Buffer ) ;
}
return 0 ;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}