rainmeter-studio/Library/TrayWindow.cpp
spx cc3ad487a7 * Changed the way to get the information of the multiple display monitors.
This change brings the order of monitors close to the order of "Display Properties" due to using EnumDisplayDevices and EnumDisplaySettings instead of EnumDisplayMonitors. (If EnumDisplayDevices failed, EnumDisplayMonitors is used as before.)

-----

* Added the "Display Monitor" submenu in [Skins Menu]-[Position].

These menus convert the present position to the relative position from the specified monitor.
(But the meter window doesn't move to the specified monitor area immediately. Only converts.)

- "Use default: Primary monitor" removes the @-directive from WindowX/Y.
- @0(@1, @2, ...) adds the specified monitor number to WindowX/Y. @0 means "The Virtual Screen". (http://msdn.microsoft.com/en-us/library/dd145136%28VS.85%29.aspx)
- If "Auto-select based on window position" is checked, the WindowX and WindowY "@n" settings are made automatically based on the position of the meter's window. If a monitor is selected directly using "Display Monitor" in the Rainmeter / skin context menu, this menu is unchecked. This setting can be manually made in either the [Rainmeter] (all configs) or individual config sections of Rainmeter.ini.

AutoSelectScreen
If set to 1, the WindowX and WindowY "@n" settings are made automatically based on the position of the meter's window. If a monitor is selected directly using "Display Monitor" in the Rainmeter / skin context menu, this setting is reset to 0.

-----

* Added the variables for multiple display monitors and the virtual screen.
All X/Y positions are represented in the virtual screen coordinates.

The following variables are for the virtual screen.

 #VSCREENAREAX# is the X-position of the left-side of the virtual screen.
 #VSCREENAREAY# is the Y-position of the top-side of the virtual screen.
 #VSCREENAREAWIDTH# is the width of the virtual screen.
 #VSCREENAREAHEIGHT# is the height of the virtual screen.

The following variables are for the PRESENT monitor.
Note that these variables automatically change by the WindowX and WindowY "@n" settings. If "@n" is not set, these variables return the value of the primary monitor.

 #WORKAREAX# is the X-position of the left-side of the work area.
 #WORKAREAY# is the Y-position of the top-side of the work area.
 #WORKAREAWIDTH# is the width of the work area.
 #WORKAREAHEIGHT# is the height of the work area.
 #SCREENAREAX# is the X-position of the left-side of the monitor screen.
 #SCREENAREAY# is the Y-position of the top-side of the monitor screen.
 #SCREENAREAWIDTH# is the width of the display resolution.
 #SCREENAREAHEIGHT# is the height of the display resolution.

The following variables are for the PRIMARY monitor.

 #PWORKAREAX# is the X-position of the left-side of the work area.
 #PWORKAREAY# is the Y-position of the top-side of the work area.
 #PWORKAREAWIDTH# is the width of the work area.
 #PWORKAREAHEIGHT# is the height of the work area.
 #PSCREENAREAX# is the X-position of the left-side of the monitor screen. (maybe, always 0)
 #PSCREENAREAY# is the Y-position of the top-side of the monitor screen. (maybe, always 0)
 #PSCREENAREAWIDTH# is the width of the display resolution.
 #PSCREENAREAHEIGHT# is the height of the display resolution.

The following variables are for the SPECIFIED monitor. (@n = @1, @2, ...)

 #WORKAREAX@n# is the X-position of the left-side of the work area.
 #WORKAREAY@n# is the Y-position of the top-side of the work area.
 #WORKAREAWIDTH@n# is the width of the work area.
 #WORKAREAHEIGHT@n# is the height of the work area.
 #SCREENAREAX@n# is the X-position of the left-side of the monitor screen.
 #SCREENAREAY@n# is the Y-position of the top-side of the monitor screen.
 #SCREENAREAWIDTH@n# is the width of the display resolution.
 #SCREENAREAHEIGHT@n# is the height of the display resolution.

-----

* Other related changes:

- Fixed the problem that the primary monitor isn't recognized correctly.

- Fixed the problem that the information of the multiple display monitors is refreshed excessively.

- For DynamicVariables, when display setting or workarea size has been changed, all variables are now updated to apply changed WORKAREA/SCREENAREA variables.

- Fixed the problem that the "On Desktop" window isn't dragged correctly when the top-left corner of the virtual screen has negative coordinates.

- Changed the way to stick the "On Desktop" window. ("SysListView32/FolderView" is used instead of "Progman/Program Manager".)

-----

* Other changes:

- When the meter window is draggable and isn't dragged, LeftMouseUpAction is now executed.

- Added MouseDoubleClickAction (LeftMouseDoubleClickAction, RightMouseDoubleClickAction, MiddleMouseDoubleClickAction). If MouseDoubleClickAction is empty when mouse button is double-clicked, MouseDownAction is executed instead.

- Fixed the problem that the Meter's hit-test code checks outside the area.

- Changed the way to set the #CURRENTCONFIG#. (CMeterWindow::GetSkinName() is now used instead of parsing the path.)
2009-12-18 05:58:37 +00:00

682 lines
17 KiB
C++

/*
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.
*/
#include "StdAfx.h"
#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;
for (size_t i = 0; i < m_TrayIcons.size(); i++)
{
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)
{
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 the default icon if there is no valid measure
return LoadIcon(m_Instance, MAKEINTRESOURCE(IDI_TRAY));
}
void CTrayWindow::ReadConfig(CConfigParser& parser)
{
for (size_t i = 0; i < m_TrayIcons.size(); i++)
{
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->GetSkinPath() + imageName;
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();
help = L"\"" + help + L"Rainmeter.chm\"";
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->GetLogFile();
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.\nDo 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"\nDelete 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();
command += L"\"";
LSExecute(tray->GetWindow(), command.c_str(), SW_SHOWNORMAL);
}
else if(wParam == ID_CONTEXT_MANAGETHEMES)
{
std::wstring command = L"\"" + Rainmeter->GetPath();
command += L"\\Addons\\RainThemes\\RainThemes.exe\"";
LSExecute(tray->GetWindow(), command.c_str(), SW_SHOWNORMAL);
}
else if(wParam == ID_CONTEXT_MANAGESKINS)
{
std::wstring command = L"\"" + Rainmeter->GetPath();
command += L"\\Addons\\RainBrowser\\RainBrowser.exe\"";
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 == ID_CONTEXT_OPENSKINSFOLDER)
{
std::wstring command;
command += L"\"";
command += Rainmeter->GetSkinPath();
command += L"\"";
LSExecute(tray->GetWindow(), command.c_str(), SW_SHOWNORMAL);
}
else if((wParam & 0x0ffff) >= ID_THEME_FIRST && (wParam & 0x0ffff) <= ID_THEME_LAST)
{
int pos = (wParam & 0x0ffff) - ID_THEME_FIRST;
const std::vector<std::wstring>& themes = Rainmeter->GetAllThemes();
if (pos >= 0 && pos < (int)themes.size())
{
std::wstring command = L"\"" + Rainmeter->GetPath();
command += L"\\Addons\\RainThemes\\RainThemes.exe\" /load \"";
command += themes[pos];
command += L"\"";
LSExecute(tray->GetWindow(), command.c_str(), SW_SHOWNORMAL);
}
}
else if((wParam & 0x0ffff) >= ID_CONFIG_FIRST && (wParam & 0x0ffff) <= ID_CONFIG_LAST)
{
wParam = wParam & 0x0ffff;
// Check which config was selected
const std::vector<CRainmeter::CONFIG>& configs = Rainmeter->GetAllConfigs();
for (size_t i = 0; i < configs.size(); i++)
{
for (size_t j = 0; j < configs[i].commands.size(); j++)
{
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();
if (index < (int)windows.size())
{
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;
// --- for CMeterWindow ---
case WM_DISPLAYCHANGE:
DebugLog(L"* Display setting has been changed.");
CMeterWindow::ClearMultiMonitorInfo();
CConfigParser::ClearMultiMonitorVariables();
case WM_SETTINGCHANGE:
if (uMsg == WM_DISPLAYCHANGE || (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA))
{
if (uMsg == WM_SETTINGCHANGE) // SPI_SETWORKAREA
{
DebugLog(L"* Work area has been changed.");
CMeterWindow::UpdateWorkareaInfo();
CConfigParser::UpdateWorkareaVariables();
}
// Deliver WM_DISPLAYCHANGE / WM_SETTINGCHANGE message to all meter windows
std::map<std::wstring, CMeterWindow*>& windows = Rainmeter->GetAllMeterWindows();
std::map<std::wstring, CMeterWindow*>::iterator iter = windows.begin();
for( ; iter != windows.end(); iter++)
{
PostMessage((*iter).second->GetWindow(), WM_DELAYED_MOVE, (WPARAM)uMsg, (LPARAM)0);
}
}
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}