rainmeter-studio/Library/Rainmeter.cpp

3229 lines
81 KiB
C++
Raw Normal View History

2009-02-10 18:37:48 +00:00
/*
Copyright (C) 2001 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2009-02-10 18:37:48 +00:00
*/
#include "StdAfx.h"
2009-02-10 18:37:48 +00:00
#include "Rainmeter.h"
#include "TrayWindow.h"
#include "System.h"
2009-02-10 18:37:48 +00:00
#include "Error.h"
#include "DialogAbout.h"
#include "DialogManage.h"
2009-02-10 18:37:48 +00:00
#include "MeasureNet.h"
#include "MeterString.h"
#include "resource.h"
2009-02-10 18:37:48 +00:00
#include "UpdateCheck.h"
#include "../Version.h"
2009-02-10 18:37:48 +00:00
#include "DisableThreadLibraryCalls.h" // contains DllMain entry point
2009-02-10 18:37:48 +00:00
using namespace Gdiplus;
enum TIMER
{
TIMER_NETSTATS = 1
};
enum INTERVAL
{
INTERVAL_NETSTATS = 120000
};
2009-02-10 18:37:48 +00:00
CRainmeter* Rainmeter; // The module
/*
** RainmeterMain
**
** Initializes Rainmeter.
**
*/
2012-02-16 17:38:45 +00:00
int RainmeterMain(LPWSTR cmdLine)
{
HWND wnd = NULL;
while (wnd = FindWindowEx(NULL, wnd, RAINMETER_CLASS_NAME, RAINMETER_WINDOW_NAME))
{
COPYDATASTRUCT cds;
2012-02-15 15:23:28 +00:00
if (cmdLine[0] == L'!')
{
// Deliver bang to existing Rainmeter instance
cds.dwData = 1;
cds.cbData = (DWORD)((wcslen(cmdLine) + 1) * sizeof(WCHAR));
cds.lpData = (PVOID)cmdLine;
SendMessage(wnd, WM_COPYDATA, NULL, (LPARAM)&cds);
return 0;
}
else
{
const WCHAR* fullCmdLine = GetCommandLine();
COPYDATASTRUCT cds;
cds.dwData = SIZE_MAX;
cds.cbData = (DWORD)((wcslen(fullCmdLine) + 1) * sizeof(WCHAR));
cds.lpData = (PVOID)fullCmdLine;
if (SendMessage(wnd, WM_COPYDATA, NULL, (LPARAM)&cds) == SIZE_MAX)
{
// An instance of Rainmeter with same command-line arguments already exists
return 1;
}
}
}
2012-02-15 15:23:28 +00:00
if (cmdLine[0] == L'!' &&
_wcsicmp(L"!RainmeterQuit", cmdLine) != 0 &&
_wcsicmp(L"!Quit", cmdLine) != 0)
{
MessageBox(NULL, L"Unable to send bang: Rainmeter is not running.", L"Rainmeter", MB_OK | MB_TOPMOST | MB_ICONERROR);
return 1;
}
// Avoid loading a dll from current directory
SetDllDirectory(L"");
int ret = 1;
Rainmeter = new CRainmeter;
if (Rainmeter)
{
try
{
2012-02-16 17:38:45 +00:00
ret = Rainmeter->Initialize(cmdLine);
}
catch (CError& error)
{
MessageBox(NULL, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR);
}
if (ret == 0)
{
2012-02-16 17:38:45 +00:00
ret = Rainmeter->MessagePump();
}
delete Rainmeter;
Rainmeter = NULL;
}
return ret;
2010-12-11 16:30:49 +00:00
}
2009-02-10 18:37:48 +00:00
/*
2011-10-29 10:36:07 +00:00
** ParseString
**
2011-10-29 10:36:07 +00:00
** Splits the given string into substrings
**
*/
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> CRainmeter::ParseString(LPCTSTR str)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> result;
if (str)
{
2011-10-29 10:36:07 +00:00
std::wstring arg = str;
2011-10-29 10:36:07 +00:00
// Split the argument between first space.
// Or if string is in quotes, the after the second quote.
auto stripQuotes = [&](std::wstring& string)
{
size_t pos = 0;
do
{
pos = string.find(L'"', pos);
if (pos != std::wstring::npos)
{
string.erase(pos, 1);
}
}
while (pos != std::wstring::npos);
};
2011-10-29 10:36:07 +00:00
size_t pos;
std::wstring newStr;
while ((pos = arg.find_first_not_of(L' ')) != std::wstring::npos)
{
size_t extra = 1;
2011-10-29 10:36:07 +00:00
if (arg[pos] == L'"')
{
2011-10-29 10:36:07 +00:00
if (arg.size() > (pos + 2) &&
arg[pos + 1] == L'"' && arg[pos + 2] == L'"')
{
// Eat found quotes and finding ending """
arg.erase(0, pos + 3);
extra = 4;
2011-10-29 10:36:07 +00:00
if ((pos = arg.find(L"\"\"\" ")) == std::wstring::npos)
{
extra = 3;
pos = arg.rfind(L"\"\"\""); // search backward
2011-10-29 10:36:07 +00:00
}
}
else
{
2011-10-29 10:36:07 +00:00
// Eat found quote and find ending quote
arg.erase(0, pos + 1);
pos = arg.find_first_of(L'"');
}
}
else
{
2011-10-29 10:36:07 +00:00
if (pos > 0)
{
2011-10-29 10:36:07 +00:00
// Eat everything until non-space (and non-quote) char
arg.erase(0, pos);
}
2011-10-29 10:36:07 +00:00
// Find the second quote
pos = arg.find_first_of(L' ');
}
2011-10-29 10:36:07 +00:00
if (pos != std::wstring::npos)
{
2011-10-29 10:36:07 +00:00
newStr.assign(arg, 0, pos);
arg.erase(0, pos + extra);
2011-10-29 10:36:07 +00:00
if (extra == 1) stripQuotes(newStr);
2011-10-29 10:36:07 +00:00
result.push_back(newStr);
}
else // quote or space not found
{
newStr = arg;
arg.clear();
if (extra == 1) stripQuotes(newStr);
result.push_back(newStr);
2011-10-29 10:36:07 +00:00
break;
}
}
2011-10-29 10:36:07 +00:00
if (!arg.empty() && result.empty())
{
stripQuotes(arg);
2011-10-29 10:36:07 +00:00
result.push_back(arg);
}
}
2011-10-29 10:36:07 +00:00
return result;
}
/*
2011-10-29 10:36:07 +00:00
** BangWithArgs
**
2011-10-29 10:36:07 +00:00
** Parses Bang args
**
*/
void CRainmeter::BangWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs, CMeterWindow* meterWindow)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
const size_t subStringsSize = subStrings.size();
2011-10-29 10:36:07 +00:00
if (subStringsSize >= numOfArgs)
{
2012-02-15 07:07:50 +00:00
if (subStringsSize == numOfArgs && meterWindow)
2011-10-29 10:36:07 +00:00
{
2012-02-15 07:07:50 +00:00
meterWindow->RunBang(bang, subStrings);
2011-10-29 10:36:07 +00:00
}
2012-02-15 07:07:50 +00:00
else
{
// Use the specified window instead of meterWindow parameter
2012-02-15 07:07:50 +00:00
if (subStringsSize > numOfArgs)
{
2012-02-15 07:07:50 +00:00
const std::wstring& config = subStrings[numOfArgs];
if (!config.empty() && (config.length() != 1 || config[0] != L'*'))
{
2012-02-15 07:07:50 +00:00
CMeterWindow* meterWindow = GetMeterWindow(config);
if (meterWindow)
{
meterWindow->RunBang(bang, subStrings);
}
else
{
LogWithArgs(LOG_ERROR, L"Bang: Config \"%s\" not found", config.c_str());
}
return;
}
2011-10-29 10:36:07 +00:00
}
2012-02-15 07:07:50 +00:00
// No config defined -> apply to all.
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
2011-10-29 10:36:07 +00:00
{
2012-02-15 07:07:50 +00:00
((*iter).second)->RunBang(bang, subStrings);
2011-10-29 10:36:07 +00:00
}
}
}
2011-10-29 10:36:07 +00:00
else
{
// For backwards compatibility
if (bang == BANG_COMMANDMEASURE && subStringsSize >= 1)
{
std::wstring tmpSz = arg;
std::wstring::size_type pos = tmpSz.find_first_of(L' ');
if (pos != std::wstring::npos)
{
tmpSz.replace(pos, 1, L"\" \"");
BangWithArgs(bang, tmpSz.c_str(), numOfArgs, meterWindow);
Log(LOG_WARNING, L"!CommandMeasure: Two parameters required, only one given");
return;
}
}
2011-10-29 10:36:07 +00:00
Log(LOG_ERROR, L"Bang: Incorrect number of arugments");
}
}
/*
2011-10-29 10:36:07 +00:00
** BangGroupWithArgs
**
2011-10-29 10:36:07 +00:00
** Parses Bang args for Group
**
*/
void CRainmeter::BangGroupWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs, CMeterWindow* meterWindow)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (subStrings.size() > numOfArgs)
{
2011-10-29 10:36:07 +00:00
std::multimap<int, CMeterWindow*> windows;
GetMeterWindowsByLoadOrder(windows, subStrings[numOfArgs]);
2011-10-29 10:36:07 +00:00
std::multimap<int, CMeterWindow*>::const_iterator iter = windows.begin();
for (; iter != windows.end(); ++iter)
{
2011-12-04 22:18:40 +00:00
std::wstring argument(1, L'"');
2011-10-29 10:36:07 +00:00
for (size_t i = 0; i < numOfArgs; ++i)
{
2011-10-29 10:36:07 +00:00
argument += subStrings[i];
argument += L"\" \"";
}
2011-10-29 10:36:07 +00:00
argument += (*iter).second->GetSkinName();
2011-12-04 22:18:40 +00:00
argument += L'"';
BangWithArgs(bang, argument.c_str(), numOfArgs, meterWindow);
}
}
2011-10-29 10:36:07 +00:00
else
{
Log(LOG_ERROR, L"BangGroup: Incorrect number of arguments");
}
}
/*
2012-01-30 08:34:56 +00:00
** Bang_ActivateConfig
**
2012-01-30 08:34:56 +00:00
** !ActivateConfig bang
**
*/
2012-01-30 08:34:56 +00:00
void CRainmeter::Bang_ActivateConfig(const WCHAR* arg)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
2011-10-29 10:36:07 +00:00
if (subStrings.size() > 1)
{
std::pair<int, int> indexes = GetMeterWindowIndex(subStrings[0], subStrings[1]);
if (indexes.first != -1 && indexes.second != -1)
{
2011-10-29 10:36:07 +00:00
ActivateConfig(indexes.first, indexes.second);
return;
}
2011-10-29 10:36:07 +00:00
LogWithArgs(LOG_ERROR, L"!ActivateConfig: \"%s\\%s\" not found", subStrings[0].c_str(), subStrings[1].c_str());
}
2011-10-29 10:36:07 +00:00
else
{
2011-10-29 10:36:07 +00:00
// If we got this far, something went wrong
Log(LOG_ERROR, L"!ActivateConfig: Invalid parameters");
}
}
/*
2012-01-30 08:34:56 +00:00
** Bang_DeactivateConfig
**
2012-01-30 08:34:56 +00:00
** !DeactivateConfig bang
**
*/
void CRainmeter::Bang_DeactivateConfig(const WCHAR* arg, CMeterWindow* meterWindow)
2009-02-10 18:37:48 +00:00
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (!subStrings.empty())
{
meterWindow = GetMeterWindow(subStrings[0]);
if (!meterWindow)
{
LogWithArgs(LOG_WARNING, L"!DeactivateConfig: \"%s\" not active", subStrings[0].c_str());
2011-10-29 10:36:07 +00:00
return;
}
}
if (meterWindow)
{
DeactivateConfig(meterWindow, -1);
2011-10-29 10:36:07 +00:00
}
else
{
Log(LOG_ERROR, L"!DeactivateConfig: Invalid parameters");
}
}
/*
2012-01-30 08:34:56 +00:00
** Bang_ToggleConfig
**
2012-01-30 08:34:56 +00:00
** !ToggleConfig bang
**
*/
2012-01-30 08:34:56 +00:00
void CRainmeter::Bang_ToggleConfig(const WCHAR* arg)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (subStrings.size() >= 2)
{
2011-10-29 10:36:07 +00:00
CMeterWindow* mw = GetMeterWindow(subStrings[0]);
if (mw)
{
2011-10-29 10:36:07 +00:00
DeactivateConfig(mw, -1);
return;
}
2011-10-29 10:36:07 +00:00
// If the config wasn't active, activate it
2012-01-30 08:34:56 +00:00
Bang_ActivateConfig(arg);
2011-10-29 10:36:07 +00:00
}
else
{
Log(LOG_ERROR, L"!ToggleConfig: Invalid parameters");
}
2009-02-10 18:37:48 +00:00
}
/*
2012-01-30 08:34:56 +00:00
** Bang_DeactivateConfigGroup
**
2012-01-30 08:34:56 +00:00
** !DeactivateConfigGroup bang
**
*/
2012-01-30 08:34:56 +00:00
void CRainmeter::Bang_DeactivateConfigGroup(const WCHAR* arg)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (!subStrings.empty())
{
2011-10-29 10:36:07 +00:00
std::multimap<int, CMeterWindow*> windows;
GetMeterWindowsByLoadOrder(windows, subStrings[0]);
2011-10-29 10:36:07 +00:00
std::multimap<int, CMeterWindow*>::const_iterator iter = windows.begin();
for (; iter != windows.end(); ++iter)
{
2011-10-29 10:36:07 +00:00
DeactivateConfig((*iter).second, -1);
}
}
2011-10-29 10:36:07 +00:00
else
{
Log(LOG_ERROR, L"!DeactivateConfigGroup: Invalid parameters");
}
2009-02-10 18:37:48 +00:00
}
/*
2012-01-30 08:34:56 +00:00
** Bang_SetClip
2009-02-10 18:37:48 +00:00
**
2012-01-30 08:34:56 +00:00
** !SetClip bang
2009-02-10 18:37:48 +00:00
**
*/
2012-01-30 08:34:56 +00:00
void CRainmeter::Bang_SetClip(const WCHAR* arg)
{
std::vector<std::wstring> subStrings = ParseString(arg);
if (!subStrings.empty())
{
CSystem::SetClipboardText(subStrings[0]);
}
else
{
Log(LOG_ERROR, L"!SetClip: Invalid parameter");
}
}
/*
** Bang_SetWallpaper
**
** !SetWallpaper bang
**
*/
void CRainmeter::Bang_SetWallpaper(const WCHAR* arg)
{
std::vector<std::wstring> subStrings = ParseString(arg);
if (subStrings.size() == 1)
{
CSystem::SetWallpaper(subStrings[0], L"");
}
else if (subStrings.size() == 2)
{
CSystem::SetWallpaper(subStrings[0], subStrings[1]);
}
else
{
Log(LOG_ERROR, L"!SetWallpaper: Invalid parameters");
}
}
2012-01-30 08:34:56 +00:00
/*
** Bang_SkinMenu
**
** !SkinMenu bang
**
*/
void CRainmeter::Bang_SkinMenu(const WCHAR* arg, CMeterWindow* meterWindow)
2009-02-10 18:37:48 +00:00
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (!subStrings.empty())
{
meterWindow = GetMeterWindow(subStrings[0]);
if (!meterWindow)
2011-10-29 10:36:07 +00:00
{
LogWithArgs(LOG_WARNING, L"!SkinMenu: \"%s\" not active", subStrings[0].c_str());
2011-10-29 10:36:07 +00:00
return;
}
}
if (meterWindow)
{
POINT pos;
GetCursorPos(&pos);
ShowContextMenu(pos, meterWindow);
2011-10-29 10:36:07 +00:00
}
else
{
2011-10-29 10:36:07 +00:00
Log(LOG_ERROR, L"!SkinMenu: Invalid parameter");
}
2009-02-10 18:37:48 +00:00
}
/*
2012-01-30 08:34:56 +00:00
** Bang_TrayMenu
2009-02-10 18:37:48 +00:00
**
2012-01-30 08:34:56 +00:00
** !TrayMenu bang
2009-02-10 18:37:48 +00:00
**
*/
2012-01-30 08:34:56 +00:00
void CRainmeter::Bang_TrayMenu()
2009-02-10 18:37:48 +00:00
{
2011-10-29 10:36:07 +00:00
POINT pos;
GetCursorPos(&pos);
ShowContextMenu(pos, NULL);
2009-02-10 18:37:48 +00:00
}
/*
2012-01-30 08:34:56 +00:00
** Bang_WriteKeyValue
**
2012-01-30 08:34:56 +00:00
** !WriteKeyValue bang
**
*/
void CRainmeter::Bang_WriteKeyValue(const WCHAR* arg, CMeterWindow* meterWindow)
{
2011-10-29 10:36:07 +00:00
std::vector<std::wstring> subStrings = ParseString(arg);
if (subStrings.size() < 4)
{
if (!meterWindow) return;
// Add the config filepath to the args
std::wstring path;
path += m_SkinPath;
path += meterWindow->GetSkinName();
path += L'\\';
path += meterWindow->GetSkinIniFile();
subStrings.push_back(std::move(path));
}
2011-10-29 10:36:07 +00:00
if (subStrings.size() > 3)
{
2011-11-19 11:32:23 +00:00
const std::wstring& strIniFile = subStrings[3];
const WCHAR* iniFile = strIniFile.c_str();
2011-11-19 11:32:23 +00:00
if (strIniFile.find(L"..\\") != std::wstring::npos || strIniFile.find(L"../") != std::wstring::npos)
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Illegal path: %s", iniFile);
2011-10-29 10:36:07 +00:00
return;
}
2011-10-29 10:36:07 +00:00
const std::wstring& skinPath = GetSkinPath();
const std::wstring settingsPath = GetSettingsPath();
2011-11-19 11:32:23 +00:00
if (_wcsnicmp(iniFile, skinPath.c_str(), skinPath.size()) != 0 &&
_wcsnicmp(iniFile, settingsPath.c_str(), settingsPath.size()) != 0)
2011-10-29 10:36:07 +00:00
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Illegal path: %s", iniFile);
2011-10-29 10:36:07 +00:00
return;
}
2011-10-29 10:36:07 +00:00
// Verify whether the file exists
2011-11-19 11:32:23 +00:00
if (_waccess(iniFile, 0) == -1)
2011-10-29 10:36:07 +00:00
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: File not found: %s", iniFile);
2011-10-29 10:36:07 +00:00
return;
}
2011-10-29 10:36:07 +00:00
// Verify whether the file is read-only
2011-11-19 11:32:23 +00:00
DWORD attr = GetFileAttributes(iniFile);
2011-10-29 10:36:07 +00:00
if (attr == -1 || (attr & FILE_ATTRIBUTE_READONLY))
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_WARNING, L"!WriteKeyValue: File is read-only: %s", iniFile);
2011-10-29 10:36:07 +00:00
return;
}
2011-10-29 10:36:07 +00:00
// Avoid "IniFileMapping"
2011-11-10 13:44:19 +00:00
CSystem::UpdateIniFileMappingList();
2011-11-19 11:32:23 +00:00
std::wstring strIniWrite = CSystem::GetTemporaryFile(strIniFile);
if (strIniWrite.size() == 1 && strIniWrite[0] == L'?') // error occurred
2011-10-29 10:36:07 +00:00
{
return;
}
2011-11-19 11:32:23 +00:00
bool temporary = !strIniWrite.empty();
2011-10-29 10:36:07 +00:00
if (temporary)
{
2011-11-19 11:32:23 +00:00
if (GetDebug()) LogWithArgs(LOG_DEBUG, L"!WriteKeyValue: Writing to: %s (Temp: %s)", iniFile, strIniWrite.c_str());
2011-10-29 10:36:07 +00:00
}
else
{
2011-11-19 11:32:23 +00:00
if (GetDebug()) LogWithArgs(LOG_DEBUG, L"!WriteKeyValue: Writing to: %s", iniFile);
strIniWrite = strIniFile;
2011-10-29 10:36:07 +00:00
}
2011-11-19 11:32:23 +00:00
const WCHAR* iniWrite = strIniWrite.c_str();
const WCHAR* section = subStrings[0].c_str();
const WCHAR* key = subStrings[1].c_str();
2011-10-29 10:36:07 +00:00
const std::wstring& strValue = subStrings[2];
2011-10-29 10:36:07 +00:00
bool formula = false;
BOOL write = 0;
2011-10-29 10:36:07 +00:00
if (subStrings.size() > 4)
{
CMeterWindow* mw = GetMeterWindow(subStrings[4]);
if (mw)
{
2011-10-29 10:36:07 +00:00
double value;
formula = mw->GetParser().ParseFormula(strValue, &value);
2011-03-29 19:21:57 +00:00
2011-10-29 10:36:07 +00:00
// Formula read fine
if (formula)
{
WCHAR buffer[256];
int len = _snwprintf_s(buffer, _TRUNCATE, L"%.5f", value);
CMeasure::RemoveTrailingZero(buffer, len);
2011-11-19 11:32:23 +00:00
write = WritePrivateProfileString(section, key, buffer, iniWrite);
}
}
2011-10-29 10:36:07 +00:00
}
2011-10-29 10:36:07 +00:00
if (!formula)
{
2011-11-19 11:32:23 +00:00
write = WritePrivateProfileString(section, key, strValue.c_str(), iniWrite);
2011-10-29 10:36:07 +00:00
}
2011-10-29 10:36:07 +00:00
if (temporary)
{
if (write != 0)
{
2011-11-19 11:32:23 +00:00
WritePrivateProfileString(NULL, NULL, NULL, iniWrite); // FLUSH
2011-10-29 10:36:07 +00:00
// Copy the file back
if (!CSystem::CopyFiles(iniWrite, iniFile))
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to copy temporary file to original filepath: %s (Temp: %s)", iniFile, iniWrite);
}
}
2011-10-29 10:36:07 +00:00
else // failed
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to write to: %s (Temp: %s)", iniFile, iniWrite);
}
2011-10-29 10:36:07 +00:00
// Remove a temporary file
CSystem::RemoveFile(iniWrite);
}
else
{
2011-10-29 10:36:07 +00:00
if (write == 0) // failed
{
2011-11-19 11:32:23 +00:00
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to write to: %s", iniFile);
2011-10-29 10:36:07 +00:00
}
}
}
2011-10-29 10:36:07 +00:00
else
{
2011-10-29 10:36:07 +00:00
Log(LOG_ERROR, L"!WriteKeyValue: Invalid parameters");
}
2009-08-04 09:48:03 +00:00
}
2009-02-10 18:37:48 +00:00
// -----------------------------------------------------------------------------------------------
//
// The class starts here
//
// -----------------------------------------------------------------------------------------------
2011-03-29 19:21:57 +00:00
/*
2009-02-10 18:37:48 +00:00
** CRainmeter
**
** Constructor
**
*/
CRainmeter::CRainmeter() :
m_TrayWindow(),
m_Debug(false),
m_DisableVersionCheck(false),
m_NewVersion(false),
m_DesktopWorkAreaChanged(false),
m_DesktopWorkAreaType(false),
m_NormalStayDesktop(true),
m_MenuActive(false),
m_DisableRDP(false),
m_DisableDragging(false),
m_Logging(false),
m_CurrentParser(),
m_Instance(),
2011-09-23 16:28:38 +00:00
m_ResourceInstance(),
m_GDIplusToken(),
m_GlobalConfig()
2009-02-10 18:37:48 +00:00
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
InitCommonControls();
2009-02-10 18:37:48 +00:00
2011-03-29 19:21:57 +00:00
// Initialize GDI+.
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_GDIplusToken, &gdiplusStartupInput, NULL);
2009-02-10 18:37:48 +00:00
}
2011-03-29 19:21:57 +00:00
/*
2009-02-10 18:37:48 +00:00
** ~CRainmeter
**
** Destructor
**
*/
CRainmeter::~CRainmeter()
{
KillTimer(m_Window, TIMER_NETSTATS);
2012-02-02 12:05:14 +00:00
DeleteMeterWindow(NULL);
2009-02-10 18:37:48 +00:00
delete m_TrayWindow;
2009-02-10 18:37:48 +00:00
CSystem::Finalize();
CMeasureNet::UpdateIFTable();
CMeasureNet::UpdateStats();
WriteStats(true);
2009-02-10 18:37:48 +00:00
CMeasureNet::FinalizeNewApi();
CMeterString::FreeFontCache();
// Change the work area back
if (m_DesktopWorkAreaChanged)
{
UpdateDesktopWorkArea(true);
}
FinalizeLitestep();
2011-09-24 09:13:13 +00:00
if (m_ResourceInstance) FreeLibrary(m_ResourceInstance);
CoUninitialize();
2009-02-10 18:37:48 +00:00
GdiplusShutdown(m_GDIplusToken);
}
2011-03-29 19:21:57 +00:00
/*
2009-02-10 18:37:48 +00:00
** Initialize
**
** The main initialization function for the module.
** May throw CErrors !!!!
**
*/
2012-02-16 17:38:45 +00:00
int CRainmeter::Initialize(LPCWSTR szPath)
2009-02-10 18:37:48 +00:00
{
int result = 0;
2009-02-10 18:37:48 +00:00
2012-02-16 17:38:45 +00:00
m_Instance = GetModuleHandle(L"Rainmeter");
WNDCLASS wc = {0};
wc.lpfnWndProc = (WNDPROC)MainWndProc;
2012-02-16 17:38:45 +00:00
wc.hInstance = m_Instance;
wc.lpszClassName = RAINMETER_CLASS_NAME;
RegisterClass(&wc);
m_Window = CreateWindowEx(
WS_EX_TOOLWINDOW,
RAINMETER_CLASS_NAME,
RAINMETER_WINDOW_NAME,
WS_POPUP | WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
2012-02-16 17:38:45 +00:00
m_Instance,
NULL);
if (!m_Window) return 1;
WCHAR* tmpSzPath = new WCHAR[MAX_LINE_LENGTH];
GetModuleFileName(m_Instance, tmpSzPath, MAX_LINE_LENGTH);
2009-02-10 18:37:48 +00:00
// Remove the module's name from the path
WCHAR* pos = wcsrchr(tmpSzPath, L'\\');
2011-03-29 19:21:57 +00:00
if (pos)
2009-02-10 18:37:48 +00:00
{
*(pos + 1) = L'\0';
2011-03-29 19:21:57 +00:00
}
else
2009-02-10 18:37:48 +00:00
{
tmpSzPath[0] = L'\0';
2009-02-10 18:37:48 +00:00
}
m_Path = tmpSzPath;
InitalizeLitestep();
2009-02-10 18:37:48 +00:00
bool bDefaultIniLocation = false;
if (*szPath)
{
// The command line defines the location of Rainmeter.ini (or whatever it calls it).
std::wstring iniFile = szPath;
2011-12-04 22:18:40 +00:00
if (iniFile[0] == L'"')
{
if (iniFile.length() == 1)
{
iniFile.clear();
}
2011-12-04 22:18:40 +00:00
else if (iniFile[iniFile.length() - 1] == L'"')
{
2011-07-14 00:26:53 +00:00
iniFile.assign(iniFile, 1, iniFile.length() - 2);
}
}
ExpandEnvironmentVariables(iniFile);
2011-11-05 09:01:06 +00:00
if (iniFile.empty() || CSystem::IsPathSeparator(iniFile[iniFile.length() - 1]))
{
iniFile += L"Rainmeter.ini";
}
2011-11-10 13:44:19 +00:00
else if (iniFile.length() <= 4 || _wcsicmp(iniFile.c_str() + (iniFile.length() - 4), L".ini") != 0)
{
iniFile += L"\\Rainmeter.ini";
}
2011-11-05 09:01:06 +00:00
if (!CSystem::IsPathSeparator(iniFile[0]) && iniFile.find_first_of(L':') == std::wstring::npos)
{
// Make absolute path
iniFile.insert(0, m_Path);
}
m_IniFile = iniFile;
// If the ini file doesn't exist, create a default Rainmeter.ini file.
if (_waccess(m_IniFile.c_str(), 0) == -1)
{
CreateDefaultConfigFile(m_IniFile);
}
bDefaultIniLocation = true;
}
else
{
m_IniFile = m_Path;
m_IniFile += L"Rainmeter.ini";
// If the ini file doesn't exist in the program folder store it to the %APPDATA% instead so that things work better in Vista/Win7
if (_waccess(m_IniFile.c_str(), 0) == -1)
{
m_IniFile = L"%APPDATA%\\Rainmeter\\Rainmeter.ini";
ExpandEnvironmentVariables(m_IniFile);
bDefaultIniLocation = true;
// If the ini file doesn't exist in the %APPDATA% either, create a default Rainmeter.ini file.
if (_waccess(m_IniFile.c_str(), 0) == -1)
{
CreateDefaultConfigFile(m_IniFile);
}
}
}
2011-07-14 00:26:53 +00:00
// Set the log file and stats file location
m_LogFile = m_StatsFile = m_IniFile;
size_t logFileLen = m_LogFile.length();
2011-11-10 13:44:19 +00:00
if (logFileLen > 4 && _wcsicmp(m_LogFile.c_str() + (logFileLen - 4), L".ini") == 0)
{
m_LogFile.replace(logFileLen - 4, 4, L".log");
2011-07-14 00:26:53 +00:00
m_StatsFile.replace(logFileLen - 4, 4, L".stats");
}
else
{
m_LogFile += L".log"; // Append the extension so that we don't accidentally overwrite the ini file
m_StatsFile += L".stats";
}
// Read Logging settings beforehand
m_Logging = 0!=GetPrivateProfileInt(L"Rainmeter", L"Logging", 0, m_IniFile.c_str());
m_Debug = 0!=GetPrivateProfileInt(L"Rainmeter", L"Debug", 0, m_IniFile.c_str());
// Determine the language resource to load
std::wstring resource = m_Path + L"Languages\\";
if (GetPrivateProfileString(L"Rainmeter", L"Language", L"", tmpSzPath, MAX_LINE_LENGTH, m_IniFile.c_str()) == 0)
{
// Use whatever the user selected for the installer
DWORD size = MAX_LINE_LENGTH;
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Rainmeter", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS)
{
DWORD type = 0;
if (RegQueryValueEx(hKey, L"Language", NULL, &type, (LPBYTE)tmpSzPath, (LPDWORD)&size) != ERROR_SUCCESS ||
type != REG_SZ)
{
2011-10-23 10:41:32 +00:00
tmpSzPath[0] = L'\0';
}
RegCloseKey(hKey);
}
}
if (tmpSzPath[0] != L'\0')
{
// Try selected language
m_ResourceLCID = wcstoul(tmpSzPath, NULL, 10);
resource += tmpSzPath;
resource += L".dll";
m_ResourceInstance = LoadLibraryEx(resource.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
}
if (!m_ResourceInstance)
{
// Try English
resource = m_Path;
resource += L"Languages\\1033.dll";
m_ResourceInstance = LoadLibraryEx(resource.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
m_ResourceLCID = 1033;
if (!m_ResourceInstance)
{
throw CError(L"Unable to load language library");
}
}
// Reset log file
CSystem::RemoveFile(m_LogFile);
if (m_Logging)
{
StartLogging();
}
m_PluginPath = m_AddonPath = m_SkinPath = m_Path;
m_PluginPath += L"Plugins\\";
2010-11-25 22:00:34 +00:00
m_AddonPath += L"Addons\\";
m_SkinPath += L"Skins\\";
// Read the skin folder from the ini file
if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", tmpSzPath, MAX_LINE_LENGTH, m_IniFile.c_str()) > 0)
{
m_SkinPath = tmpSzPath;
ExpandEnvironmentVariables(m_SkinPath);
if (!m_SkinPath.empty())
{
2011-11-05 09:01:06 +00:00
if (!CSystem::IsPathSeparator(m_SkinPath[m_SkinPath.size() - 1]))
{
2011-12-04 22:18:40 +00:00
m_SkinPath += L'\\';
}
}
2011-05-01 17:10:49 +00:00
}
else if (bDefaultIniLocation)
2011-05-01 17:10:49 +00:00
{
// If the skin path is not defined in the Rainmeter.ini file use My Documents/Rainmeter/Skins
tmpSzPath[0] = L'\0';
HRESULT hr = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, tmpSzPath);
if (SUCCEEDED(hr))
{
// Make the folders if they don't exist yet
m_SkinPath = tmpSzPath;
m_SkinPath += L"\\Rainmeter";
CreateDirectory(m_SkinPath.c_str(), NULL);
m_SkinPath += L"\\Skins\\";
DWORD result = CreateDirectory(m_SkinPath.c_str(), NULL);
if (result != 0)
{
// The folder was created successfully which means that it wasn't available yet.
// Copy the default skin to the Skins folder
std::wstring strFrom(m_Path + L"Skins\\*.*");
std::wstring strTo(m_SkinPath);
CSystem::CopyFiles(strFrom, strTo);
// This shouldn't be copied
std::wstring strNote = strTo + L"Read me before copying skins here.txt";
CSystem::RemoveFile(strNote);
// Copy also the themes to the %APPDATA%
strFrom = std::wstring(m_Path + L"Themes\\*.*");
strTo = std::wstring(GetSettingsPath() + L"Themes\\");
CreateDirectory(strTo.c_str(), NULL);
CSystem::CopyFiles(strFrom, strTo);
}
}
2011-05-01 17:10:49 +00:00
else
{
Log(LOG_WARNING, L"Documents folder not found");
}
WritePrivateProfileString(L"Rainmeter", L"SkinPath", m_SkinPath.c_str(), m_IniFile.c_str());
}
delete [] tmpSzPath;
tmpSzPath = NULL;
LogWithArgs(LOG_NOTICE, L"Path: %s", m_Path.c_str());
LogWithArgs(LOG_NOTICE, L"IniFile: %s", m_IniFile.c_str());
LogWithArgs(LOG_NOTICE, L"SkinPath: %s", m_SkinPath.c_str());
2009-02-10 18:37:48 +00:00
2010-11-25 22:00:34 +00:00
// Extract volume path from program path
// E.g.:
// "C:\path\" to "C:"
// "\\server\share\" to "\\server\share"
// "\\server\C:\path\" to "\\server\C:"
std::wstring::size_type loc;
if ((loc = m_Path.find_first_of(L':')) != std::wstring::npos)
{
2011-07-14 00:26:53 +00:00
m_Drive.assign(m_Path, 0, loc + 1);
2010-11-25 22:00:34 +00:00
}
2011-11-05 09:01:06 +00:00
else if (CSystem::IsUNCPath(m_Path))
2010-11-25 22:00:34 +00:00
{
if ((loc = m_Path.find_first_of(L"\\/", 2)) != std::wstring::npos)
{
std::wstring::size_type loc2;
if ((loc2 = m_Path.find_first_of(L"\\/", loc + 1)) != std::wstring::npos || loc != (m_Path.length() - 1))
{
loc = loc2;
}
}
2011-07-14 00:26:53 +00:00
m_Drive.assign(m_Path, 0, loc);
2010-11-25 22:00:34 +00:00
}
// Test that the Rainmeter.ini file is writable
TestSettingsFile(bDefaultIniLocation);
2012-02-16 17:38:45 +00:00
CSystem::Initialize(m_Instance);
CMeasureNet::InitializeNewApi();
if (m_Debug)
{
Log(LOG_DEBUG, L"Enumerating installed font families...");
CMeterString::EnumerateInstalledFontFamilies();
}
2009-02-10 18:37:48 +00:00
// Tray must exist before configs are read
m_TrayWindow = new CTrayWindow(m_Instance);
ReloadSettings();
2011-03-29 19:21:57 +00:00
if (m_ConfigStrings.empty())
{
2011-09-23 16:28:38 +00:00
std::wstring error = GetFormattedString(ID_STR_NOAVAILABLESKINS, m_SkinPath.c_str());
2010-09-21 11:09:36 +00:00
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR);
}
WritePrivateProfileString(L"Rainmeter", L"CheckUpdate", NULL , m_IniFile.c_str());
2009-02-10 18:37:48 +00:00
ResetStats();
ReadStats();
// Change the work area if necessary
if (m_DesktopWorkAreaChanged)
{
UpdateDesktopWorkArea(false);
2009-02-10 18:37:48 +00:00
}
// Create meter windows for active configs
2011-09-04 18:06:19 +00:00
ActivateActiveConfigs();
2009-02-10 18:37:48 +00:00
if (!m_DisableVersionCheck)
{
CheckUpdate();
}
return result; // All is OK
2009-02-10 18:37:48 +00:00
}
int CRainmeter::MessagePump()
{
MSG msg;
BOOL ret;
// Run the standard window message loop
while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (ret == -1)
{
break;
}
else if (!CDialog::GetActiveDialog() || !IsDialogMessage(CDialog::GetActiveDialog(), &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK CRainmeter::MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COPYDATA:
{
COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
if (cds)
{
const WCHAR* data = (const WCHAR*)cds->lpData;
if (cds->dwData == 1 && (cds->cbData > 0))
{
Rainmeter->DelayedExecuteCommand(data);
}
else if (cds->dwData == SIZE_MAX && _wcsicmp(GetCommandLine(), data) == 0)
{
return SIZE_MAX;
}
}
}
break;
case WM_TIMER:
if (wParam == TIMER_NETSTATS)
{
CMeasureNet::UpdateIFTable();
CMeasureNet::UpdateStats();
Rainmeter->WriteStats(false);
}
break;
case WM_RAINMETER_DELAYED_REFRESH_ALL:
Rainmeter->RefreshAll();
break;
case WM_RAINMETER_DELAYED_EXECUTE:
if (lParam)
{
// Execute bang
WCHAR* bang = (WCHAR*)lParam;
Rainmeter->ExecuteCommand(bang, NULL);
free(bang); // _wcsdup()
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
void CRainmeter::SetNetworkStatisticsTimer()
{
static bool set = SetTimer(m_Window, TIMER_NETSTATS, INTERVAL_NETSTATS, NULL);
}
2011-03-29 19:21:57 +00:00
/*
** CreateDefaultConfigFile
**
** Creates the default Rainmeter.ini file with illustro\System enabled.
**
*/
void CRainmeter::CreateDefaultConfigFile(const std::wstring& strFile)
{
size_t pos = strFile.find_last_of(L'\\');
if (pos != std::wstring::npos)
{
2011-07-12 13:37:31 +00:00
std::wstring strPath(strFile, 0, pos);
CreateDirectory(strPath.c_str(), NULL);
}
std::wstring defaultIni = GetPath() + L"Default.ini";
if (_waccess(defaultIni.c_str(), 0) == -1)
{
WritePrivateProfileString(L"Rainmeter", L"\r\n[illustro\\System]\r\nActive", L"1", strFile.c_str());
}
else
{
CSystem::CopyFiles(defaultIni, GetIniFile());
}
}
2009-02-10 18:37:48 +00:00
void CRainmeter::ReloadSettings()
{
ScanForConfigs(m_SkinPath);
ScanForThemes(GetSettingsPath() + L"Themes");
2009-02-10 18:37:48 +00:00
ReadGeneralSettings(m_IniFile);
}
2011-09-04 18:06:19 +00:00
void CRainmeter::ActivateActiveConfigs()
{
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
for ( ; iter != m_ConfigOrders.end(); ++iter)
{
2011-11-18 22:40:58 +00:00
const CONFIG& configS = m_ConfigStrings[(*iter).second];
if (configS.active > 0 && configS.active <= (int)configS.iniFiles.size())
2011-09-04 18:06:19 +00:00
{
2011-11-18 22:40:58 +00:00
ActivateConfig((*iter).second, configS.active - 1);
2011-09-04 18:06:19 +00:00
}
}
}
2009-02-10 18:37:48 +00:00
void CRainmeter::ActivateConfig(int configIndex, int iniIndex)
{
2011-10-29 10:36:07 +00:00
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size() &&
iniIndex >= 0 && iniIndex < (int)m_ConfigStrings[configIndex].iniFiles.size())
2009-02-10 18:37:48 +00:00
{
const std::wstring& skinIniFile = m_ConfigStrings[configIndex].iniFiles[iniIndex];
const std::wstring& skinConfig = m_ConfigStrings[configIndex].config;
2009-02-10 18:37:48 +00:00
// Verify that the config is not already active
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.find(skinConfig);
if (iter != m_MeterWindows.end())
2009-02-10 18:37:48 +00:00
{
if (((*iter).second)->GetSkinIniFile() == skinIniFile)
{
LogWithArgs(LOG_WARNING, L"!ActivateConfig: \"%s\" already active", skinConfig.c_str());
2009-02-10 18:37:48 +00:00
return;
}
else
{
// Deactivate the existing config
2011-02-02 23:17:44 +00:00
DeactivateConfig((*iter).second, configIndex);
2009-02-10 18:37:48 +00:00
}
}
// Verify whether the ini-file exists
std::wstring skinIniPath = m_SkinPath + skinConfig;
2011-12-04 22:18:40 +00:00
skinIniPath += L'\\';
skinIniPath += skinIniFile;
if (_waccess(skinIniPath.c_str(), 0) == -1)
2009-02-10 18:37:48 +00:00
{
2011-09-23 16:28:38 +00:00
std::wstring message = GetFormattedString(ID_STR_UNABLETOACTIVATESKIN, skinConfig.c_str(), skinIniFile.c_str());
MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
return;
}
2009-02-10 18:37:48 +00:00
m_ConfigStrings[configIndex].active = iniIndex + 1;
WriteActive(skinConfig, iniIndex);
CreateMeterWindow(skinConfig, skinIniFile);
2009-02-10 18:37:48 +00:00
}
}
void CRainmeter::DeactivateConfig(CMeterWindow* meterWindow, int configIndex, bool save)
2009-02-10 18:37:48 +00:00
{
2009-02-14 10:11:28 +00:00
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size())
2009-02-10 18:37:48 +00:00
{
m_ConfigStrings[configIndex].active = 0; // Deactivate the config
}
else if (configIndex == -1 && meterWindow)
2009-02-10 18:37:48 +00:00
{
// Deactivate the config by using the meter window's config name
2011-11-16 16:47:20 +00:00
const WCHAR* skinConfig = meterWindow->GetSkinName().c_str();
for (size_t i = 0, isize = m_ConfigStrings.size(); i < isize; ++i)
2009-02-10 18:37:48 +00:00
{
2011-11-16 16:47:20 +00:00
if (_wcsicmp(skinConfig, m_ConfigStrings[i].config.c_str()) == 0)
{
m_ConfigStrings[i].active = 0;
break;
}
2009-02-10 18:37:48 +00:00
}
}
if (meterWindow)
{
if (save)
{
// Disable the config in the ini-file
WriteActive(meterWindow->GetSkinName(), -1);
}
2009-02-10 18:37:48 +00:00
2012-02-02 12:05:14 +00:00
meterWindow->Deactivate();
2009-02-10 18:37:48 +00:00
}
}
2011-10-29 10:36:07 +00:00
void CRainmeter::ToggleConfig(int configIndex, int iniIndex)
{
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size() &&
iniIndex >= 0 && iniIndex < (int)m_ConfigStrings[configIndex].iniFiles.size())
{
if (m_ConfigStrings[configIndex].active == iniIndex + 1)
{
CMeterWindow* meterWindow = Rainmeter->GetMeterWindow(m_ConfigStrings[configIndex].config);
DeactivateConfig(meterWindow, configIndex);
}
else
{
ActivateConfig(configIndex, iniIndex);
}
}
}
void CRainmeter::WriteActive(const std::wstring& config, int iniIndex)
{
WCHAR buffer[32];
_itow_s(iniIndex + 1, buffer, 10);
WritePrivateProfileString(config.c_str(), L"Active", buffer, m_IniFile.c_str());
}
void CRainmeter::CreateMeterWindow(const std::wstring& config, const std::wstring& iniFile)
2009-02-10 18:37:48 +00:00
{
CMeterWindow* mw = new CMeterWindow(config, iniFile);
2009-02-10 18:37:48 +00:00
if (mw)
{
m_MeterWindows[config] = mw;
try
{
mw->Initialize(*this);
CDialogAbout::UpdateSkins();
CDialogManage::UpdateSkins(mw);
}
catch (CError& error)
{
DeactivateConfig(mw, -1);
LogError(error);
}
2009-02-10 18:37:48 +00:00
}
}
void CRainmeter::DeleteMeterWindow(CMeterWindow* meterWindow, bool force)
2009-02-10 18:37:48 +00:00
{
std::map<std::wstring, CMeterWindow*>::iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
{
2012-02-02 12:05:14 +00:00
if (meterWindow == NULL)
{
2012-02-02 12:05:14 +00:00
// Delete all meter windows
CDialogManage::UpdateSkins((*iter).second, true);
delete (*iter).second;
}
2012-02-02 12:05:14 +00:00
else if ((*iter).second == meterWindow)
2009-02-10 18:37:48 +00:00
{
m_MeterWindows.erase(iter);
2012-02-03 10:37:26 +00:00
force = true;
break;
2009-02-10 18:37:48 +00:00
}
2012-02-02 12:05:14 +00:00
}
2009-02-10 18:37:48 +00:00
2012-02-02 12:05:14 +00:00
if (meterWindow == NULL)
{
m_MeterWindows.clear();
}
else if (force)
{
2012-02-03 10:37:26 +00:00
CDialogManage::UpdateSkins(meterWindow, true);
delete meterWindow;
2009-02-10 18:37:48 +00:00
}
CDialogAbout::UpdateSkins();
2009-02-10 18:37:48 +00:00
}
CMeterWindow* CRainmeter::GetMeterWindow(const std::wstring& config)
{
2011-11-16 16:47:20 +00:00
const WCHAR* configName = config.c_str();
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
2009-02-10 18:37:48 +00:00
{
2011-11-16 16:47:20 +00:00
if (_wcsicmp((*iter).first.c_str(), configName) == 0)
2009-02-10 18:37:48 +00:00
{
return (*iter).second;
}
}
return NULL;
}
CMeterWindow* CRainmeter::GetMeterWindowByINI(const std::wstring& ini_searching)
{
if (_wcsnicmp(m_SkinPath.c_str(), ini_searching.c_str(), m_SkinPath.length()) == 0)
{
const std::wstring config_searching = ini_searching.substr(m_SkinPath.length());
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
{
2011-12-04 22:18:40 +00:00
std::wstring config_current = (*iter).second->GetSkinName() + L'\\';
config_current += (*iter).second->GetSkinIniFile();
if (_wcsicmp(config_current.c_str(), config_searching.c_str()) == 0)
{
return (*iter).second;
}
}
}
return NULL;
}
std::pair<int, int> CRainmeter::GetMeterWindowIndex(const std::wstring& config, const std::wstring& iniFile)
{
2011-11-16 16:47:20 +00:00
const WCHAR* configName = config.c_str();
std::pair<int, int> indexes;
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
{
2011-11-18 22:40:58 +00:00
const CONFIG& configS = m_ConfigStrings[i];
if (_wcsicmp(configS.config.c_str(), configName) == 0)
{
2011-11-16 16:47:20 +00:00
const WCHAR* iniFileName = iniFile.c_str();
2011-11-18 22:40:58 +00:00
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{
2011-11-18 22:40:58 +00:00
if (_wcsicmp(configS.iniFiles[j].c_str(), iniFileName) == 0)
{
indexes = std::make_pair(i, j);
return indexes;
}
}
}
}
indexes = std::make_pair(-1, -1); // error
return indexes;
}
2011-10-29 10:36:07 +00:00
std::pair<int, int> CRainmeter::GetMeterWindowIndex(UINT menuCommand)
{
std::pair<int, int> indexes;
if (menuCommand >= ID_CONFIG_FIRST && menuCommand <= ID_CONFIG_LAST)
{
// Check which config was selected
for (size_t i = 0, isize = m_ConfigStrings.size(); i < isize; ++i)
{
2011-11-18 22:40:58 +00:00
const CONFIG& configS = m_ConfigStrings[i];
if (menuCommand >= configS.commandBase &&
menuCommand < (configS.commandBase + configS.iniFiles.size()))
2011-10-29 10:36:07 +00:00
{
2011-11-18 22:40:58 +00:00
indexes = std::make_pair(i, menuCommand - configS.commandBase);
2011-10-29 10:36:07 +00:00
return indexes;
}
}
}
indexes = std::make_pair(-1, -1); // error
return indexes;
}
CMeterWindow* CRainmeter::GetMeterWindow(HWND hwnd)
{
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
{
if ((*iter).second->GetWindow() == hwnd)
{
return (*iter).second;
}
}
return NULL;
}
void CRainmeter::GetMeterWindowsByLoadOrder(std::multimap<int, CMeterWindow*>& windows, const std::wstring& group)
{
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
{
CMeterWindow* mw = (*iter).second;
if (mw && (group.empty() || mw->BelongsToGroup(group)))
{
windows.insert(std::pair<int, CMeterWindow*>(GetLoadOrder((*iter).first), mw));
}
}
}
2011-07-15 16:54:47 +00:00
void CRainmeter::SetLoadOrder(int configIndex, int order)
{
std::multimap<int, int>::iterator iter = m_ConfigOrders.begin();
2010-03-30 22:37:05 +00:00
for ( ; iter != m_ConfigOrders.end(); ++iter)
{
if ((*iter).second == configIndex) // already exists
{
if ((*iter).first != order)
{
m_ConfigOrders.erase(iter);
break;
}
else
{
return;
}
}
}
m_ConfigOrders.insert(std::pair<int, int>(order, configIndex));
}
int CRainmeter::GetLoadOrder(const std::wstring& config)
{
2011-11-19 23:09:41 +00:00
const WCHAR* configName = config.c_str();
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
2010-03-30 22:37:05 +00:00
for ( ; iter != m_ConfigOrders.end(); ++iter)
{
2011-11-19 23:09:41 +00:00
if (wcscmp(m_ConfigStrings[(*iter).second].config.c_str(), configName) == 0)
{
return (*iter).first;
}
}
// LoadOrder not specified
return 0;
}
2011-03-29 19:21:57 +00:00
/*
2009-02-10 18:37:48 +00:00
** ScanForConfigs
**
** Scans all the subfolders and locates the ini-files.
*/
void CRainmeter::ScanForConfigs(const std::wstring& path)
2009-02-10 18:37:48 +00:00
{
m_ConfigStrings.clear();
m_ConfigMenu.clear();
m_ConfigOrders.clear();
2009-02-10 18:37:48 +00:00
ScanForConfigsRecursive(path, L"", 0, m_ConfigMenu, false);
2009-02-10 18:37:48 +00:00
}
int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector<CONFIGMENU>& menu, bool DontRecurse)
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
WIN32_FIND_DATA fileData; // Data structure describes the file found
HANDLE hSearch; // Search handle returned by FindFirstFile
2011-07-15 11:48:50 +00:00
std::list<std::wstring> folders;
const bool first = base.empty();
2009-02-10 18:37:48 +00:00
2011-07-15 11:48:50 +00:00
// Scan all .ini files and folders from the subfolder
std::wstring filter = path + base;
filter += L"\\*";
hSearch = FindFirstFileEx(
filter.c_str(),
(CSystem::GetOSPlatform() >= OSPLATFORM_7) ? FindExInfoBasic : FindExInfoStandard,
&fileData,
FindExSearchNameMatch,
NULL,
0);
if (hSearch != INVALID_HANDLE_VALUE)
2009-02-10 18:37:48 +00:00
{
CONFIG config;
config.config = base;
2011-11-19 23:09:41 +00:00
config.commandBase = ID_CONFIG_FIRST + index;
2011-07-15 11:48:50 +00:00
config.active = 0;
2009-02-10 18:37:48 +00:00
do
{
2011-11-19 23:09:41 +00:00
const std::wstring filename = fileData.cFileName;
2011-07-15 11:48:50 +00:00
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
2011-11-19 23:09:41 +00:00
if (wcscmp(L".", fileData.cFileName) != 0 &&
wcscmp(L"..", fileData.cFileName) != 0 &&
!(first && wcscmp(L"Backup", fileData.cFileName) == 0)) // Skip the backup folder
2011-07-15 11:48:50 +00:00
{
2011-11-19 23:09:41 +00:00
folders.push_back(filename);
2011-07-15 11:48:50 +00:00
}
}
else if (!first)
{
2011-07-15 11:48:50 +00:00
// Check whether the extension is ".ini"
2011-11-19 23:09:41 +00:00
size_t filenameLen = filename.size();
2011-07-15 11:48:50 +00:00
if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0)
{
CONFIGMENU menuItem;
2011-11-19 23:09:41 +00:00
menuItem.name = filename;
2011-07-15 11:48:50 +00:00
menuItem.index = m_ConfigStrings.size();
2011-12-09 03:28:19 +00:00
menu.push_back(std::move(menuItem));
2009-02-10 18:37:48 +00:00
2011-11-19 23:09:41 +00:00
config.iniFiles.push_back(filename);
2011-10-29 10:36:07 +00:00
++index;
2011-07-15 11:48:50 +00:00
}
}
}
while (FindNextFile(hSearch, &fileData));
2011-07-15 11:48:50 +00:00
FindClose(hSearch);
2009-02-10 18:37:48 +00:00
if (!config.iniFiles.empty())
{
2011-12-09 03:28:19 +00:00
m_ConfigStrings.push_back(std::move(config));
2009-02-10 18:37:48 +00:00
}
2011-07-15 11:48:50 +00:00
}
2009-02-10 18:37:48 +00:00
2011-07-15 11:48:50 +00:00
if (!first)
{
2011-12-04 22:18:40 +00:00
base += L'\\';
2009-02-10 18:37:48 +00:00
}
2011-11-18 22:40:58 +00:00
menu.reserve(menu.size() + folders.size());
2011-07-15 11:48:50 +00:00
std::list<std::wstring>::const_iterator iter = folders.begin();
for ( ; iter != folders.end(); ++iter)
2009-02-10 18:37:48 +00:00
{
2011-07-15 11:48:50 +00:00
CONFIGMENU menuItem;
menuItem.name = (*iter);
menuItem.index = -1;
2011-12-09 03:28:19 +00:00
menu.push_back(std::move(menuItem));
2009-02-10 18:37:48 +00:00
2011-07-15 11:48:50 +00:00
if (!DontRecurse)
2009-02-10 18:37:48 +00:00
{
2011-07-15 11:48:50 +00:00
std::vector<CONFIGMENU>::iterator iter2 = menu.end() - 1;
index = ScanForConfigsRecursive(path, base + (*iter), index, (*iter2).children, false);
2009-02-10 18:37:48 +00:00
2011-07-15 11:48:50 +00:00
// Remove menu item if it has no child
if ((*iter2).children.empty())
{
2011-07-15 11:48:50 +00:00
menu.erase(iter2);
}
2009-02-10 18:37:48 +00:00
}
2011-07-15 11:48:50 +00:00
}
2009-02-10 18:37:48 +00:00
return index;
}
2011-03-29 19:21:57 +00:00
/*
** ScanForThemes
**
** Scans the given folder for themes
*/
void CRainmeter::ScanForThemes(const std::wstring& path)
{
m_Themes.clear();
WIN32_FIND_DATA fileData; // Data structure describes the file found
2011-03-29 19:21:57 +00:00
HANDLE hSearch; // Search handle returned by FindFirstFile
// Scan for folders
std::wstring folders = path + L"\\*";
2011-07-15 11:48:50 +00:00
hSearch = FindFirstFileEx(
folders.c_str(),
(CSystem::GetOSPlatform() >= OSPLATFORM_7) ? FindExInfoBasic : FindExInfoStandard,
&fileData,
FindExSearchNameMatch,
NULL,
0);
if (hSearch != INVALID_HANDLE_VALUE)
{
do
{
2011-07-15 11:48:50 +00:00
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
wcscmp(L".", fileData.cFileName) != 0 &&
wcscmp(L"..", fileData.cFileName) != 0)
{
m_Themes.push_back(fileData.cFileName);
}
}
while (FindNextFile(hSearch, &fileData));
2011-07-15 11:48:50 +00:00
FindClose(hSearch);
}
}
void CRainmeter::ExecuteBang(const std::wstring& name, std::wstring& arg, CMeterWindow* meterWindow)
2009-02-10 18:37:48 +00:00
{
const WCHAR* bang = name.c_str();
2011-11-19 11:32:23 +00:00
const WCHAR* args = arg.c_str();
if (_wcsnicmp(bang, L"Rainmeter", 9) == 0)
{
// Skip "Rainmeter"
bang += 9;
}
if (_wcsicmp(bang, L"Refresh") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_REFRESH, args, 0, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"RefreshApp") == 0)
{
2011-10-29 10:36:07 +00:00
// Refresh needs to be delayed since it crashes if done during Update()
PostMessage(m_Window, WM_RAINMETER_DELAYED_REFRESH_ALL, (WPARAM)NULL, (LPARAM)NULL);
}
else if (_wcsicmp(bang, L"Redraw") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_REDRAW, args, 0, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"Update") == 0)
{
BangWithArgs(BANG_UPDATE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"Hide") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_HIDE, args, 0, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"Show") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_SHOW, args, 0, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"Toggle") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_TOGGLE, args, 0, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"HideFade") == 0)
{
BangWithArgs(BANG_HIDEFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ShowFade") == 0)
{
BangWithArgs(BANG_SHOWFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleFade") == 0)
{
BangWithArgs(BANG_TOGGLEFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"HideMeter") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_HIDEMETER, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ShowMeter") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_SHOWMETER, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ToggleMeter") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_TOGGLEMETER, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"MoveMeter") == 0)
{
BangWithArgs(BANG_MOVEMETER, args, 3, meterWindow);
}
else if (_wcsicmp(bang, L"UpdateMeter") == 0)
{
BangWithArgs(BANG_UPDATEMETER, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"DisableMeasure") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_DISABLEMEASURE, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"EnableMeasure") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_ENABLEMEASURE, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ToggleMeasure") == 0)
2009-02-10 18:37:48 +00:00
{
BangWithArgs(BANG_TOGGLEMEASURE, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"UpdateMeasure") == 0)
{
BangWithArgs(BANG_UPDATEMEASURE, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"CommandMeasure") == 0)
{
BangWithArgs(BANG_COMMANDMEASURE, args, 2, meterWindow);
}
else if (_wcsicmp(bang, L"ShowBlur") == 0)
{
BangWithArgs(BANG_SHOWBLUR, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"HideBlur") == 0)
{
BangWithArgs(BANG_HIDEBLUR, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleBlur") == 0)
{
BangWithArgs(BANG_TOGGLEBLUR, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"AddBlur") == 0)
{
BangWithArgs(BANG_ADDBLUR, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"RemoveBlur") == 0)
{
BangWithArgs(BANG_REMOVEBLUR, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"ActivateConfig") == 0)
{
2012-01-30 08:34:56 +00:00
Bang_ActivateConfig(args);
}
else if (_wcsicmp(bang, L"DeactivateConfig") == 0)
{
Bang_DeactivateConfig(args, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleConfig") == 0)
{
2012-01-30 08:34:56 +00:00
Bang_ToggleConfig(args);
}
else if (_wcsicmp(bang, L"Move") == 0)
{
BangWithArgs(BANG_MOVE, args, 2, meterWindow);
}
else if (_wcsicmp(bang, L"ZPos") == 0 || _wcsicmp(bang, L"ChangeZPos") == 0) // For backwards compatibility
{
BangWithArgs(BANG_ZPOS, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"ClickThrough") == 0)
{
BangWithArgs(BANG_CLICKTHROUGH, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"Draggable") == 0)
{
BangWithArgs(BANG_DRAGGABLE, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"SnapEdges") == 0)
{
BangWithArgs(BANG_SNAPEDGES, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"KeepOnScreen") == 0)
{
BangWithArgs(BANG_KEEPONSCREEN, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"SetTransparency") == 0)
{
BangWithArgs(BANG_SETTRANSPARENCY, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"SetVariable") == 0)
{
BangWithArgs(BANG_SETVARIABLE, args, 2, meterWindow);
}
else if (_wcsicmp(bang, L"SetOption") == 0)
{
BangWithArgs(BANG_SETOPTION, args, 3, meterWindow);
}
else if (_wcsicmp(bang, L"RefreshGroup") == 0)
{
BangGroupWithArgs(BANG_REFRESH, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"UpdateGroup") == 0)
{
BangGroupWithArgs(BANG_UPDATE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"RedrawGroup") == 0)
{
BangGroupWithArgs(BANG_REDRAW, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"HideGroup") == 0)
{
BangGroupWithArgs(BANG_HIDE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ShowGroup") == 0)
{
BangGroupWithArgs(BANG_SHOW, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleGroup") == 0)
{
BangGroupWithArgs(BANG_TOGGLE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"HideFadeGroup") == 0)
{
BangGroupWithArgs(BANG_HIDEFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ShowFadeGroup") == 0)
{
BangGroupWithArgs(BANG_SHOWFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleFadeGroup") == 0)
{
BangGroupWithArgs(BANG_TOGGLEFADE, args, 0, meterWindow);
}
else if (_wcsicmp(bang, L"HideMeterGroup") == 0)
{
BangWithArgs(BANG_HIDEMETERGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"ShowMeterGroup") == 0)
{
BangWithArgs(BANG_SHOWMETERGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleMeterGroup") == 0)
{
BangWithArgs(BANG_TOGGLEMETERGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"UpdateMeterGroup") == 0)
{
BangWithArgs(BANG_UPDATEMETERGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"DisableMeasureGroup") == 0)
{
BangWithArgs(BANG_DISABLEMEASUREGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"EnableMeasureGroup") == 0)
{
BangWithArgs(BANG_ENABLEMEASUREGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"ToggleMeasureGroup") == 0)
{
BangWithArgs(BANG_TOGGLEMEASUREGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"UpdateMeasureGroup") == 0)
{
BangWithArgs(BANG_UPDATEMEASUREGROUP, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"DeactivateConfigGroup") == 0)
2009-02-10 18:37:48 +00:00
{
2012-01-30 08:34:56 +00:00
Bang_DeactivateConfigGroup(args);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ZPosGroup") == 0)
2009-02-10 18:37:48 +00:00
{
BangGroupWithArgs(BANG_ZPOS, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ClickThroughGroup") == 0)
{
BangGroupWithArgs(BANG_CLICKTHROUGH, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"DraggableGroup") == 0)
{
BangGroupWithArgs(BANG_DRAGGABLE, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"SnapEdgesGroup") == 0)
{
BangGroupWithArgs(BANG_SNAPEDGES, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"KeepOnScreenGroup") == 0)
{
BangGroupWithArgs(BANG_KEEPONSCREEN, args, 1, meterWindow);
}
else if (_wcsicmp(bang, L"SetTransparencyGroup") == 0)
2009-02-10 18:37:48 +00:00
{
BangGroupWithArgs(BANG_SETTRANSPARENCY, args, 1, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"SetVariableGroup") == 0)
2009-02-10 18:37:48 +00:00
{
BangGroupWithArgs(BANG_SETVARIABLE, args, 2, meterWindow);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"SetOptionGroup") == 0)
{
BangWithArgs(BANG_SETOPTIONGROUP, args, 3, meterWindow);
}
else if (_wcsicmp(bang, L"WriteKeyValue") == 0)
2011-10-29 10:36:07 +00:00
{
Bang_WriteKeyValue(args, meterWindow);
2011-10-29 10:36:07 +00:00
}
else if (_wcsicmp(bang, L"PluginBang") == 0)
2011-10-29 10:36:07 +00:00
{
BangWithArgs(BANG_PLUGIN, args, 1, meterWindow);
2011-10-29 10:36:07 +00:00
}
else if (_wcsicmp(bang, L"SetClip") == 0)
2012-01-30 08:34:56 +00:00
{
Bang_SetClip(args);
}
else if (_wcsicmp(bang, L"SetWallpaper") == 0)
{
Bang_SetWallpaper(args);
}
else if (_wcsicmp(bang, L"About") == 0)
2009-02-10 18:37:48 +00:00
{
2011-11-19 11:32:23 +00:00
CDialogAbout::Open(args);
}
else if (_wcsicmp(bang, L"Manage") == 0)
{
2011-11-19 11:32:23 +00:00
CDialogManage::Open(args);
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"SkinMenu") == 0)
{
Bang_SkinMenu(args, meterWindow);
}
else if (_wcsicmp(bang, L"TrayMenu") == 0)
2009-02-10 18:37:48 +00:00
{
2012-01-30 08:34:56 +00:00
Bang_TrayMenu();
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"ResetStats") == 0)
2009-02-10 18:37:48 +00:00
{
2011-10-29 10:36:07 +00:00
ResetStats();
2009-02-10 18:37:48 +00:00
}
else if (_wcsicmp(bang, L"Quit") == 0)
2009-08-04 09:48:03 +00:00
{
2011-10-29 10:36:07 +00:00
// Quit needs to be delayed since it crashes if done during Update()
PostMessage(GetTrayWindow()->GetWindow(), WM_COMMAND, MAKEWPARAM(ID_CONTEXT_QUIT, 0), (LPARAM)NULL);
2009-08-04 09:48:03 +00:00
}
else if (_wcsicmp(name.c_str(), L"Execute") == 0)
2009-02-10 18:37:48 +00:00
{
// Special case for multibang execution
std::wstring::size_type start = std::wstring::npos;
int count = 0;
for (size_t i = 0, isize = arg.size(); i < isize; ++i)
2009-02-10 18:37:48 +00:00
{
2011-11-19 11:32:23 +00:00
if (args[i] == L'[')
2009-02-10 18:37:48 +00:00
{
if (count == 0)
{
start = i;
}
2010-03-30 22:37:05 +00:00
++count;
2009-02-10 18:37:48 +00:00
}
2011-11-19 11:32:23 +00:00
else if (args[i] == L']')
2009-02-10 18:37:48 +00:00
{
2010-03-30 22:37:05 +00:00
--count;
2009-02-10 18:37:48 +00:00
if (count == 0 && start != std::wstring::npos)
{
// Change ] to NULL
arg[i] = L'\0';
2009-02-10 18:37:48 +00:00
// Skip whitespace
start = arg.find_first_not_of(L" \t\r\n", start + 1, 4);
ExecuteCommand(arg.c_str() + start, meterWindow);
2009-02-10 18:37:48 +00:00
}
}
else if (args[i] == L'"' && isize > (i + 2) && args[i + 1] == L'"' && args[i + 2] == L'"')
{
i += 3;
std::wstring::size_type pos = arg.find(L"\"\"\"", i);
if (pos != std::wstring::npos)
{
i = pos + 2; // Skip "", loop will skip last "
}
}
2009-02-10 18:37:48 +00:00
}
}
else if (_wcsicmp(bang, L"LsBoxHook") == 0)
2011-10-29 10:36:07 +00:00
{
// Deprecated.
}
2009-02-10 18:37:48 +00:00
else
{
std::wstring error = L"Unknown bang: " + name;
2011-09-08 15:37:33 +00:00
Log(LOG_ERROR, error.c_str());
2009-02-10 18:37:48 +00:00
}
}
/*
** ExecuteCommand
**
** Runs the given command or bang
**
*/
2011-03-29 19:21:57 +00:00
void CRainmeter::ExecuteCommand(const WCHAR* command, CMeterWindow* meterWindow)
2009-02-10 18:37:48 +00:00
{
if (command[0] == L'!') // Bang
{
++command; // Skip "!"
std::wstring bang, arg;
// Find the first space
const WCHAR* pos = wcschr(command, L' ');
if (pos)
2009-02-10 18:37:48 +00:00
{
bang.assign(command, 0, pos - command);
arg.assign(pos + 1);
2009-02-10 18:37:48 +00:00
}
else
{
bang = command;
}
if (meterWindow && _wcsnicmp(L"Execute", command, 7) != 0)
{
meterWindow->GetParser().ReplaceMeasures(arg);
}
ExecuteBang(bang, arg, meterWindow);
}
else
{
// Check for built-ins
if (_wcsnicmp(L"PLAY", command, 4) == 0)
{
if (command[4] == L' ' || // PLAY
_wcsnicmp(L"LOOP ", &command[4], 5) == 0) // PLAYLOOP
{
command += 4; // Skip PLAY
DWORD flags = SND_FILENAME | SND_ASYNC;
if (command[0] != L' ')
{
flags |= SND_LOOP | SND_NODEFAULT;
command += 4; // Skip LOOP
}
++command; // Skip the space
if (command[0] != L'\0')
{
std::wstring sound = command;
// Strip the quotes
std::wstring::size_type len = sound.length();
if (len >= 2 && sound[0] == L'"' && sound[len - 1] == L'"')
{
len -= 2;
sound.assign(sound, 1, len);
}
if (meterWindow)
{
2012-02-04 14:29:51 +00:00
meterWindow->GetParser().ReplaceMeasures(sound);
meterWindow->MakePathAbsolute(sound);
}
PlaySound(sound.c_str(), NULL, flags);
}
return;
}
else if (_wcsnicmp(L"STOP", &command[4], 4) == 0) // PLAYSTOP
{
PlaySound(NULL, NULL, SND_PURGE);
return;
}
2009-02-10 18:37:48 +00:00
}
// Run command
2012-02-04 14:29:51 +00:00
if (meterWindow)
{
std::wstring tmpSz = command;
meterWindow->GetParser().ReplaceMeasures(tmpSz);
RunCommand(NULL, tmpSz.c_str(), SW_SHOWNORMAL);
}
else
{
RunCommand(NULL, command, SW_SHOWNORMAL);
}
2009-02-10 18:37:48 +00:00
}
}
/*
** DelayedExecuteCommand
**
** Executes command when current processing is done.
**
*/
void CRainmeter::DelayedExecuteCommand(const WCHAR* command)
{
WCHAR* bang = _wcsdup(command);
PostMessage(m_Window, WM_RAINMETER_DELAYED_EXECUTE, (WPARAM)NULL, (LPARAM)bang);
}
2009-02-10 18:37:48 +00:00
/*
** ReadGeneralSettings
2011-03-29 19:21:57 +00:00
**
2009-02-10 18:37:48 +00:00
** Reads the general settings from the Rainmeter.ini file
**
*/
void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile)
2009-02-10 18:37:48 +00:00
{
2010-12-21 04:49:01 +00:00
WCHAR buffer[MAX_PATH];
// Clear old settings
m_DesktopWorkAreas.clear();
2009-02-10 18:37:48 +00:00
CConfigParser parser;
parser.Initialize(iniFile.c_str(), this);
2009-02-10 18:37:48 +00:00
// Read Logging settings
m_Logging = 0!=parser.ReadInt(L"Rainmeter", L"Logging", 0);
m_Debug = 0!=parser.ReadInt(L"Rainmeter", L"Debug", 0);
if (m_Logging)
{
StartLogging();
}
2009-02-10 18:37:48 +00:00
if (m_TrayWindow)
{
m_TrayWindow->ReadConfig(parser);
}
m_GlobalConfig.netInSpeed = parser.ReadFloat(L"Rainmeter", L"NetInSpeed", 0.0);
m_GlobalConfig.netOutSpeed = parser.ReadFloat(L"Rainmeter", L"NetOutSpeed", 0.0);
2009-02-10 18:37:48 +00:00
m_DisableDragging = 0!=parser.ReadInt(L"Rainmeter", L"DisableDragging", 0);
2010-11-25 22:00:34 +00:00
m_DisableRDP = 0!=parser.ReadInt(L"Rainmeter", L"DisableRDP", 0);
m_ConfigEditor = parser.ReadString(L"Rainmeter", L"ConfigEditor", L"");
if (m_ConfigEditor.empty())
{
// Get the program path associated with .ini files
DWORD cchOut = MAX_PATH;
HRESULT hr = AssocQueryString(ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, L".ini", L"open", buffer, &cchOut);
2011-12-04 22:18:40 +00:00
m_ConfigEditor = (SUCCEEDED(hr) && cchOut > 0) ? buffer : L"Notepad";
}
2011-12-04 22:18:40 +00:00
if (!m_ConfigEditor.empty() && m_ConfigEditor[0] != L'"')
2009-09-30 03:24:29 +00:00
{
2011-12-04 22:18:40 +00:00
m_ConfigEditor.insert(0, 1, L'"');
m_ConfigEditor += L'"';
2009-09-30 03:24:29 +00:00
}
m_LogViewer = parser.ReadString(L"Rainmeter", L"LogViewer", L"");
if (m_LogViewer.empty())
{
// Get the program path associated with .log files
DWORD cchOut = MAX_PATH;
HRESULT hr = AssocQueryString(ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, L".log", L"open", buffer, &cchOut);
2011-12-04 22:18:40 +00:00
m_LogViewer = (SUCCEEDED(hr) && cchOut > 0) ? buffer : L"Notepad";
}
2011-12-04 22:18:40 +00:00
if (!m_LogViewer.empty() && m_LogViewer[0] != L'"')
{
2011-12-04 22:18:40 +00:00
m_LogViewer.insert(0, 1, L'"');
m_LogViewer += L'"';
}
if (m_Debug)
{
LogWithArgs(LOG_NOTICE, L"ConfigEditor: %s", m_ConfigEditor.c_str());
LogWithArgs(LOG_NOTICE, L"LogViewer: %s", m_LogViewer.c_str());
}
m_TrayExecuteL = parser.ReadString(L"Rainmeter", L"TrayExecuteL", L"", false);
m_TrayExecuteR = parser.ReadString(L"Rainmeter", L"TrayExecuteR", L"", false);
m_TrayExecuteM = parser.ReadString(L"Rainmeter", L"TrayExecuteM", L"", false);
m_TrayExecuteDL = parser.ReadString(L"Rainmeter", L"TrayExecuteDL", L"", false);
m_TrayExecuteDR = parser.ReadString(L"Rainmeter", L"TrayExecuteDR", L"", false);
m_TrayExecuteDM = parser.ReadString(L"Rainmeter", L"TrayExecuteDM", L"", false);
m_DisableVersionCheck = 0!=parser.ReadInt(L"Rainmeter", L"DisableVersionCheck", 0);
2011-11-16 16:47:20 +00:00
const std::wstring& area = parser.ReadString(L"Rainmeter", L"DesktopWorkArea", L"");
2009-02-10 18:37:48 +00:00
if (!area.empty())
{
m_DesktopWorkAreas[0] = parser.ParseRECT(area.c_str());
2009-02-10 18:37:48 +00:00
m_DesktopWorkAreaChanged = true;
}
for (UINT i = 1; i <= CSystem::GetMonitorCount(); ++i)
{
_snwprintf_s(buffer, _TRUNCATE, L"DesktopWorkArea@%i", i);
2011-11-16 16:47:20 +00:00
const std::wstring& area = parser.ReadString(L"Rainmeter", buffer, L"");
if (!area.empty())
{
m_DesktopWorkAreas[i] = parser.ParseRECT(area.c_str());
m_DesktopWorkAreaChanged = true;
}
}
m_DesktopWorkAreaType = 0!=parser.ReadInt(L"Rainmeter", L"DesktopWorkAreaType", 0);
m_NormalStayDesktop = 0!=parser.ReadInt(L"Rainmeter", L"NormalStayDesktop", 1);
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
2009-02-10 18:37:48 +00:00
{
2011-11-18 22:40:58 +00:00
CONFIG& configS = m_ConfigStrings[i];
int active = parser.ReadInt(configS.config.c_str(), L"Active", 0);
2009-02-10 18:37:48 +00:00
// Make sure there is a ini file available
2011-11-18 22:40:58 +00:00
if (active > 0 && active <= (int)configS.iniFiles.size())
2009-02-10 18:37:48 +00:00
{
2011-11-18 22:40:58 +00:00
configS.active = active;
2009-02-10 18:37:48 +00:00
}
2011-11-18 22:40:58 +00:00
int order = parser.ReadInt(configS.config.c_str(), L"LoadOrder", 0);
2011-07-15 16:54:47 +00:00
SetLoadOrder(i, order);
2009-02-10 18:37:48 +00:00
}
}
2011-03-29 19:21:57 +00:00
/*
** RefreshAll
**
** Refreshes all active meter windows.
** Note: This function calls CMeterWindow::Refresh() directly for synchronization. Be careful about crash.
2009-02-10 18:37:48 +00:00
**
*/
void CRainmeter::RefreshAll()
{
// Read skins and settings
ReloadSettings();
// Change the work area if necessary
if (m_DesktopWorkAreaChanged)
{
UpdateDesktopWorkArea(false);
}
// Make the sending order by using LoadOrder
std::multimap<int, CMeterWindow*> windows;
GetMeterWindowsByLoadOrder(windows);
// Prepare the helper window
2011-08-13 10:03:16 +00:00
CSystem::PrepareHelperWindow();
// Refresh all
std::multimap<int, CMeterWindow*>::const_iterator iter = windows.begin();
for ( ; iter != windows.end(); ++iter)
{
CMeterWindow* mw = (*iter).second;
if (mw)
{
// Verify whether the cached information is valid
int found = 0;
2011-11-19 11:32:23 +00:00
const WCHAR* skinConfig = mw->GetSkinName().c_str();
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
{
2011-11-18 22:40:58 +00:00
CONFIG& configS = m_ConfigStrings[i];
2011-11-19 11:32:23 +00:00
if (_wcsicmp(skinConfig, configS.config.c_str()) == 0)
{
found = 1;
2011-11-19 11:32:23 +00:00
const WCHAR* skinIniFile = mw->GetSkinIniFile().c_str();
2011-11-18 22:40:58 +00:00
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{
2011-11-19 11:32:23 +00:00
if (_wcsicmp(skinIniFile, configS.iniFiles[j].c_str()) == 0)
{
found = 2;
2011-11-18 22:40:58 +00:00
if (configS.active != j + 1)
{
// Switch to new ini-file order
2011-11-18 22:40:58 +00:00
configS.active = j + 1;
2011-11-19 11:32:23 +00:00
WriteActive(mw->GetSkinName(), j);
}
break;
}
}
if (found == 1) // Not found in ini-files
{
DeactivateConfig(mw, i);
2011-11-19 11:32:23 +00:00
std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinConfig, skinIniFile);
2011-09-23 16:28:38 +00:00
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
}
break;
}
}
if (found != 2)
{
if (found == 0) // Not found in configs
{
DeactivateConfig(mw, -2); // -2 = Deactivate the config forcibly
2011-11-19 11:32:23 +00:00
std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinConfig, L"");
2011-09-23 16:28:38 +00:00
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
}
continue;
}
try
{
mw->Refresh(false, true);
}
catch (CError& error)
{
LogError(error);
}
}
}
CDialogAbout::UpdateSkins();
CDialogManage::UpdateSkins(NULL);
}
2009-02-10 18:37:48 +00:00
void CRainmeter::LoadTheme(const std::wstring& name)
{
// Delete all meter windows
2012-02-02 12:05:14 +00:00
DeleteMeterWindow(NULL);
std::wstring backup = GetSettingsPath() + L"Themes\\Backup";
CreateDirectory(backup.c_str(), NULL);
backup += L"\\Rainmeter.thm";
if (_wcsicmp(name.c_str(), L"Backup") == 0)
{
// Just load the backup
CSystem::CopyFiles(backup, m_IniFile);
}
else
{
// Make a copy of current Rainmeter.ini
CSystem::CopyFiles(m_IniFile, backup);
// Replace Rainmeter.ini with theme
2011-10-29 10:36:07 +00:00
std::wstring theme = GetSettingsPath() + L"Themes\\";
theme += name;
std::wstring wallpaper = theme + L"\\RainThemes.bmp";
theme += L"\\Rainmeter.thm";
2011-10-29 10:36:07 +00:00
CSystem::CopyFiles(theme, GetIniFile());
PreserveSetting(backup, L"SkinPath");
PreserveSetting(backup, L"ConfigEditor");
PreserveSetting(backup, L"LogViewer");
PreserveSetting(backup, L"Logging");
PreserveSetting(backup, L"DisableVersionCheck");
2011-10-01 17:55:33 +00:00
PreserveSetting(backup, L"Language");
2011-11-16 16:47:20 +00:00
PreserveSetting(backup, L"NormalStayDesktop");
PreserveSetting(backup, L"TrayExecuteL", false);
PreserveSetting(backup, L"TrayExecuteM", false);
PreserveSetting(backup, L"TrayExecuteR", false);
PreserveSetting(backup, L"TrayExecuteDM", false);
PreserveSetting(backup, L"TrayExecuteDR", false);
// Set wallpaper if it exists
if (_waccess(wallpaper.c_str(), 0) != -1)
{
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)wallpaper.c_str(), SPIF_UPDATEINIFILE);
}
}
ReloadSettings();
// Create meter windows for active configs
2011-09-04 18:06:19 +00:00
ActivateActiveConfigs();
}
void CRainmeter::PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace)
{
WCHAR* buffer = new WCHAR[MAX_LINE_LENGTH];
if ((replace || GetPrivateProfileString(L"Rainmeter", key, L"", buffer, 4, m_IniFile.c_str()) == 0) &&
GetPrivateProfileString(L"Rainmeter", key, L"", buffer, MAX_LINE_LENGTH, from.c_str()) > 0)
{
WritePrivateProfileString(L"Rainmeter", key, buffer, m_IniFile.c_str());
}
delete [] buffer;
}
2011-03-29 19:21:57 +00:00
/*
** UpdateDesktopWorkArea
**
** Applies given DesktopWorkArea and DesktopWorkArea@n.
**
*/
void CRainmeter::UpdateDesktopWorkArea(bool reset)
{
bool changed = false;
if (reset)
{
if (!m_OldDesktopWorkAreas.empty())
{
for (size_t i = 0, isize = m_OldDesktopWorkAreas.size(); i < isize; ++i)
{
RECT r = m_OldDesktopWorkAreas[i];
BOOL result = SystemParametersInfo(SPI_SETWORKAREA, 0, &r, 0);
if (m_Debug)
{
std::wstring format = L"Resetting WorkArea@%i: L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)";
if (!result)
{
format += L" => FAIL";
}
LogWithArgs(LOG_DEBUG, format.c_str(), (int)i + 1, r.left, r.top, r.right, r.bottom, r.right - r.left, r.bottom - r.top);
}
}
changed = true;
}
}
else
{
const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo();
const std::vector<MONITOR_INFO>& monitors = multimonInfo.monitors;
if (m_OldDesktopWorkAreas.empty())
{
// Store old work areas for changing them back
for (size_t i = 0; i < CSystem::GetMonitorCount(); ++i)
{
m_OldDesktopWorkAreas.push_back(monitors[i].work);
}
}
if (m_Debug)
{
LogWithArgs(LOG_DEBUG, L"DesktopWorkAreaType: %s", m_DesktopWorkAreaType ? L"Margin" : L"Default");
}
for (UINT i = 0; i <= CSystem::GetMonitorCount(); ++i)
{
std::map<UINT, RECT>::const_iterator it = m_DesktopWorkAreas.find(i);
if (it != m_DesktopWorkAreas.end())
{
RECT r = it->second;
// Move rect to correct offset
if (m_DesktopWorkAreaType)
{
RECT margin = r;
r = (i == 0) ? monitors[multimonInfo.primary - 1].screen : monitors[i - 1].screen;
r.left += margin.left;
r.top += margin.top;
r.right -= margin.right;
r.bottom -= margin.bottom;
}
else
{
if (i != 0)
{
const RECT screenRect = monitors[i - 1].screen;
r.left += screenRect.left;
r.top += screenRect.top;
r.right += screenRect.left;
r.bottom += screenRect.top;
}
}
BOOL result = SystemParametersInfo(SPI_SETWORKAREA, 0, &r, 0);
if (result)
{
changed = true;
}
if (m_Debug)
{
std::wstring format = L"Applying DesktopWorkArea";
if (i != 0)
{
2010-09-13 20:06:52 +00:00
WCHAR buffer[64];
2011-12-09 19:49:06 +00:00
size_t len = _snwprintf_s(buffer, _TRUNCATE, L"@%i", i);
format.append(buffer, len);
}
format += L": L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)";
if (!result)
{
format += L" => FAIL";
}
LogWithArgs(LOG_DEBUG, format.c_str(), r.left, r.top, r.right, r.bottom, r.right - r.left, r.bottom - r.top);
}
}
}
}
if (changed && CSystem::GetWindow())
{
// Update CSystem::MULTIMONITOR_INFO for for work area variables
SendMessageTimeout(CSystem::GetWindow(), WM_SETTINGCHANGE, SPI_SETWORKAREA, 0, SMTO_ABORTIFHUNG, 1000, NULL);
}
}
2009-02-10 18:37:48 +00:00
/*
** ReadStats
**
** Reads the statistics from the ini-file
**
*/
void CRainmeter::ReadStats()
{
const WCHAR* statsFile = m_StatsFile.c_str();
// If m_StatsFile doesn't exist, create it and copy the stats section from m_IniFile
if (_waccess(statsFile, 0) == -1)
{
const WCHAR* iniFile = m_IniFile.c_str();
WCHAR* tmpSz = new WCHAR[SHRT_MAX]; // Max size returned by GetPrivateProfileSection()
if (GetPrivateProfileSection(L"Statistics", tmpSz, SHRT_MAX, iniFile) > 0)
{
WritePrivateProfileString(L"Statistics", NULL, NULL, iniFile);
}
else
{
tmpSz[0] = tmpSz[1] = L'\0';
}
WritePrivateProfileSection(L"Statistics", tmpSz, statsFile);
delete [] tmpSz;
}
2009-02-10 18:37:48 +00:00
// Only Net measure has stats at the moment
CMeasureNet::ReadStats(statsFile, m_StatsDate);
2009-02-10 18:37:48 +00:00
}
/*
** WriteStats
**
** Writes the statistics to the ini-file. If bForce is false the stats are written only once per an appropriate interval.
2009-02-10 18:37:48 +00:00
**
*/
void CRainmeter::WriteStats(bool bForce)
2009-02-10 18:37:48 +00:00
{
static ULONGLONG lastWrite = 0;
2009-02-10 18:37:48 +00:00
ULONGLONG ticks = CSystem::GetTickCount64();
if (bForce || (lastWrite + INTERVAL_NETSTATS < ticks))
{
lastWrite = ticks;
// Only Net measure has stats at the moment
const WCHAR* statsFile = m_StatsFile.c_str();
2011-12-09 19:49:06 +00:00
CMeasureNet::WriteStats(statsFile, m_StatsDate);
WritePrivateProfileString(NULL, NULL, NULL, statsFile);
}
2009-02-10 18:37:48 +00:00
}
/*
** ResetStats
**
** Clears the statistics
**
*/
void CRainmeter::ResetStats()
{
// Set the stats-date string
2011-11-19 11:32:23 +00:00
struct tm* newtime;
2011-03-29 19:21:57 +00:00
time_t long_time;
time(&long_time);
newtime = localtime(&long_time);
2009-02-10 18:37:48 +00:00
m_StatsDate = _wasctime(newtime);
2011-07-14 00:26:53 +00:00
m_StatsDate.erase(m_StatsDate.size() - 1);
2011-03-29 19:21:57 +00:00
2009-02-10 18:37:48 +00:00
// Only Net measure has stats at the moment
CMeasureNet::ResetStats();
}
/*
** ShowContextMenu
**
** Opens the context menu in given coordinates.
**
*/
2011-03-29 19:21:57 +00:00
void CRainmeter::ShowContextMenu(POINT pos, CMeterWindow* meterWindow)
2009-02-10 18:37:48 +00:00
{
if (!m_MenuActive)
2009-02-10 18:37:48 +00:00
{
m_MenuActive = true;
// Show context menu, if no actions were executed
2011-09-23 16:28:38 +00:00
HMENU menu = LoadMenu(m_ResourceInstance, MAKEINTRESOURCE(IDR_CONTEXT_MENU));
2011-03-29 19:21:57 +00:00
if (menu)
2009-02-10 18:37:48 +00:00
{
HMENU subMenu = GetSubMenu(menu, 0);
2011-03-29 19:21:57 +00:00
if (subMenu)
{
SetMenuDefaultItem(subMenu, ID_CONTEXT_MANAGE, MF_BYCOMMAND);
if (_waccess(m_LogFile.c_str(), 0) == -1)
{
EnableMenuItem(subMenu, ID_CONTEXT_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(subMenu, ID_CONTEXT_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(subMenu, ID_CONTEXT_STOPLOG, MF_BYCOMMAND | MF_GRAYED);
}
else
{
EnableMenuItem(subMenu, (m_Logging) ? ID_CONTEXT_STARTLOG : ID_CONTEXT_STOPLOG, MF_BYCOMMAND | MF_GRAYED);
}
if (m_Debug)
{
CheckMenuItem(subMenu, ID_CONTEXT_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED);
}
HMENU configMenu = GetSubMenu(subMenu, 4);
if (configMenu)
{
if (!m_ConfigMenu.empty())
{
DeleteMenu(configMenu, 0, MF_BYPOSITION); // "No skins available" menuitem
CreateConfigMenu(configMenu, m_ConfigMenu);
}
if (m_DisableDragging)
{
CheckMenuItem(configMenu, ID_CONTEXT_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED);
}
}
2009-02-10 18:37:48 +00:00
HMENU themeMenu = GetSubMenu(subMenu, 5);
if (themeMenu)
2009-02-10 18:37:48 +00:00
{
2011-08-29 19:35:18 +00:00
if (!m_Themes.empty())
{
DeleteMenu(themeMenu, 0, MF_BYPOSITION); // "No themes available" menuitem
2011-08-29 19:35:18 +00:00
CreateThemeMenu(themeMenu);
}
2009-02-10 18:37:48 +00:00
}
if (meterWindow)
{
HMENU rainmeterMenu = subMenu;
subMenu = CreateSkinMenu(meterWindow, 0, configMenu);
WCHAR buffer[256];
GetMenuString(menu, 0, buffer, 256, MF_BYPOSITION);
InsertMenu(subMenu, 11, MF_BYPOSITION | MF_POPUP, (UINT_PTR)rainmeterMenu, buffer);
InsertMenu(subMenu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
}
else
{
InsertMenu(subMenu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
2009-02-10 18:37:48 +00:00
// Create a menu for all active configs
int index = 0;
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.begin();
for (; iter != m_MeterWindows.end(); ++iter)
{
CMeterWindow* mw = ((*iter).second);
HMENU skinMenu = CreateSkinMenu(mw, index, configMenu);
InsertMenu(subMenu, 12, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, mw->GetSkinName().c_str());
++index;
}
// Put Update notifications in the Tray menu
if (m_NewVersion)
{
2011-09-24 09:13:13 +00:00
InsertMenu(subMenu, 0, MF_BYPOSITION, ID_CONTEXT_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE));
2011-10-29 10:36:07 +00:00
HiliteMenuItem(GetTrayWindow()->GetWindow(), subMenu, 0, MF_BYPOSITION | MF_HILITE);
InsertMenu(subMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
}
}
HWND hWnd = WindowFromPoint(pos);
if (hWnd != NULL)
{
CMeterWindow* mw = GetMeterWindow(hWnd);
if (mw)
{
// Cancel the mouse event beforehand
mw->SetMouseLeaveEvent(true);
}
}
// Set the window to foreground
hWnd = meterWindow ? meterWindow->GetWindow() : m_TrayWindow->GetWindow();
HWND hWndForeground = GetForegroundWindow();
if (hWndForeground != hWnd)
{
DWORD foregroundThreadID = GetWindowThreadProcessId(hWndForeground, NULL);
DWORD currentThreadID = GetCurrentThreadId();
AttachThreadInput(currentThreadID, foregroundThreadID, TRUE);
SetForegroundWindow(hWnd);
AttachThreadInput(currentThreadID, foregroundThreadID, FALSE);
}
// Show context menu
TrackPopupMenu(
subMenu,
2011-03-29 19:21:57 +00:00
TPM_RIGHTBUTTON | TPM_LEFTALIGN,
pos.x,
pos.y,
0,
hWnd,
NULL
);
if (meterWindow)
{
DestroyMenu(subMenu);
}
}
DestroyMenu(menu);
2009-02-10 18:37:48 +00:00
}
m_MenuActive = false;
2009-02-10 18:37:48 +00:00
}
}
2011-10-29 10:36:07 +00:00
HMENU CRainmeter::CreateConfigMenu(HMENU configMenu, const std::vector<CONFIGMENU>& configMenuData)
2009-02-10 18:37:48 +00:00
{
if (!configMenuData.empty())
2009-02-10 18:37:48 +00:00
{
if (!configMenu)
{
configMenu = CreatePopupMenu();
}
2009-02-10 18:37:48 +00:00
bool separator = false;
for (int i = 0, j = 0, isize = (int)configMenuData.size(); i < isize; ++i)
2009-02-10 18:37:48 +00:00
{
2011-11-18 22:40:58 +00:00
const CONFIGMENU& configMenuS = configMenuData[i];
if (configMenuS.index == -1)
2009-02-10 18:37:48 +00:00
{
2011-11-18 22:40:58 +00:00
HMENU submenu = CreateConfigMenu(NULL, configMenuS.children);
2009-02-10 18:37:48 +00:00
if (submenu)
{
if (separator)
{
// Insert a separator
InsertMenu(configMenu, i, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
++j;
separator = false;
}
2011-11-18 22:40:58 +00:00
InsertMenu(configMenu, i + j, MF_BYPOSITION | MF_POPUP, (UINT_PTR)submenu, configMenuS.name.c_str());
2009-02-10 18:37:48 +00:00
}
}
else
{
2011-11-18 22:40:58 +00:00
const CONFIG& configS = m_ConfigStrings[configMenuS.index];
InsertMenu(configMenu, i, MF_BYPOSITION | ((configS.active == i + 1) ? MF_CHECKED : MF_UNCHECKED), configS.commandBase + i, configMenuS.name.c_str());
separator = true;
2009-02-10 18:37:48 +00:00
}
}
return configMenu;
2009-02-10 18:37:48 +00:00
}
return NULL;
2009-02-10 18:37:48 +00:00
}
void CRainmeter::CreateThemeMenu(HMENU themeMenu)
{
for (size_t i = 0, isize = m_Themes.size(); i < isize; ++i)
{
InsertMenu(themeMenu, i, MF_BYPOSITION, ID_THEME_FIRST + i, m_Themes[i].c_str());
}
}
HMENU CRainmeter::CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu)
2009-02-10 18:37:48 +00:00
{
2011-09-23 16:28:38 +00:00
HMENU skinMenu = LoadMenu(m_ResourceInstance, MAKEINTRESOURCE(IDR_SKIN_MENU));
2009-02-10 18:37:48 +00:00
if (skinMenu)
{
HMENU subSkinMenu = GetSubMenu(skinMenu, 0);
RemoveMenu(skinMenu, 0, MF_BYPOSITION);
DestroyMenu(skinMenu);
skinMenu = subSkinMenu;
}
if (skinMenu)
{
// Tick the position
HMENU settingsMenu = GetSubMenu(skinMenu, 4);
if (settingsMenu)
2009-02-10 18:37:48 +00:00
{
HMENU posMenu = GetSubMenu(settingsMenu, 0);
if (posMenu)
2009-02-10 18:37:48 +00:00
{
switch (meterWindow->GetWindowZPosition())
{
case ZPOSITION_ONDESKTOP:
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_ONDESKTOP, MF_BYCOMMAND | MF_CHECKED);
break;
2009-02-10 18:37:48 +00:00
case ZPOSITION_ONBOTTOM:
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_BOTTOM, MF_BYCOMMAND | MF_CHECKED);
break;
2009-02-10 18:37:48 +00:00
case ZPOSITION_ONTOP:
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_TOPMOST, MF_BYCOMMAND | MF_CHECKED);
break;
2009-02-10 18:37:48 +00:00
case ZPOSITION_ONTOPMOST:
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_VERYTOPMOST, MF_BYCOMMAND | MF_CHECKED);
break;
2009-02-10 18:37:48 +00:00
default:
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_NORMAL, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
2011-03-29 19:21:57 +00:00
if (meterWindow->GetXFromRight()) CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_FROMRIGHT, MF_BYCOMMAND | MF_CHECKED);
if (meterWindow->GetYFromBottom()) CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_FROMBOTTOM, MF_BYCOMMAND | MF_CHECKED);
if (meterWindow->GetXPercentage()) CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_XPERCENTAGE, MF_BYCOMMAND | MF_CHECKED);
if (meterWindow->GetYPercentage()) CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_YPERCENTAGE, MF_BYCOMMAND | MF_CHECKED);
HMENU monitorMenu = GetSubMenu(posMenu, 0);
if (monitorMenu)
{
CreateMonitorMenu(monitorMenu, meterWindow);
}
* 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
}
2009-02-10 18:37:48 +00:00
// Tick the transparency
if (!meterWindow->GetNativeTransparency())
2009-02-10 18:37:48 +00:00
{
EnableMenuItem(settingsMenu, 1, MF_BYPOSITION | MF_GRAYED); // "Transparency" menu
EnableMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_CLICKTHROUGH, MF_BYCOMMAND | MF_GRAYED);
}
else
{
HMENU alphaMenu = GetSubMenu(settingsMenu, 1);
if (alphaMenu)
2009-02-10 18:37:48 +00:00
{
int value = (int)(10 - meterWindow->GetAlphaValue() / 25.5);
value = min(9, value);
value = max(0, value);
CheckMenuItem(alphaMenu, value, MF_BYPOSITION | MF_CHECKED);
switch (meterWindow->GetWindowHide())
{
case HIDEMODE_FADEIN:
CheckMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_CHECKED);
EnableMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED);
break;
case HIDEMODE_FADEOUT:
CheckMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_CHECKED);
EnableMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED);
break;
case HIDEMODE_HIDE:
EnableMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(alphaMenu, ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED);
break;
}
2009-02-10 18:37:48 +00:00
}
}
// Tick the configs
switch (meterWindow->GetWindowHide())
{
case HIDEMODE_HIDE:
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_HIDEONMOUSE, MF_BYCOMMAND | MF_CHECKED);
break;
case HIDEMODE_FADEIN:
case HIDEMODE_FADEOUT:
EnableMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_HIDEONMOUSE, MF_BYCOMMAND | MF_GRAYED);
break;
}
2009-02-10 18:37:48 +00:00
if (meterWindow->GetSnapEdges())
{
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
if (meterWindow->GetSavePosition())
{
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
if (m_DisableDragging)
{
EnableMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_DRAGGABLE, MF_BYCOMMAND | MF_GRAYED);
}
else if (meterWindow->GetWindowDraggable())
{
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_DRAGGABLE, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
if (meterWindow->GetClickThrough())
{
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
if (meterWindow->GetKeepOnScreen())
{
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED);
}
2009-02-10 18:37:48 +00:00
}
// Add the name of the Skin to the menu
const std::wstring& skinName = meterWindow->GetSkinName();
ModifyMenu(skinMenu, ID_CONTEXT_SKINMENU_OPENSKINSFOLDER, MF_BYCOMMAND, ID_CONTEXT_SKINMENU_OPENSKINSFOLDER, skinName.c_str());
SetMenuDefaultItem(skinMenu, ID_CONTEXT_SKINMENU_OPENSKINSFOLDER, FALSE);
// Remove dummy menuitem from the variants menu
HMENU variantsMenu = GetSubMenu(skinMenu, 2);
if (variantsMenu)
{
DeleteMenu(variantsMenu, 0, MF_BYPOSITION);
}
2011-03-29 19:21:57 +00:00
// Give the menuitem the unique id that depends on the skin
2009-02-10 18:37:48 +00:00
ChangeSkinIndex(skinMenu, index);
// Add the variants menu
if (variantsMenu)
{
2011-11-16 16:47:20 +00:00
const WCHAR* skin = skinName.c_str();
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
{
2011-11-18 22:40:58 +00:00
const CONFIG& configS = m_ConfigStrings[i];
if (_wcsicmp(configS.config.c_str(), skin) == 0)
{
2011-11-18 22:40:58 +00:00
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{
2011-11-18 22:40:58 +00:00
InsertMenu(variantsMenu, j, MF_BYPOSITION | ((configS.active == j + 1) ? MF_CHECKED : MF_UNCHECKED), configS.commandBase + j, configS.iniFiles[j].c_str());
}
break;
}
}
}
// Add config's root menu
int itemCount = GetMenuItemCount(configMenu);
if (itemCount > 0)
{
std::wstring root = meterWindow->GetSkinName();
std::wstring::size_type pos = root.find_first_of(L'\\');
if (pos != std::wstring::npos)
{
root.erase(pos);
}
for (int i = 0; i < itemCount; ++i)
{
UINT state = GetMenuState(configMenu, i, MF_BYPOSITION);
if (state == 0xFFFFFFFF || (state & MF_POPUP) == 0) break;
WCHAR buffer[MAX_PATH];
2010-12-21 04:49:01 +00:00
if (GetMenuString(configMenu, i, buffer, MAX_PATH, MF_BYPOSITION))
{
2010-09-17 08:47:22 +00:00
if (_wcsicmp(root.c_str(), buffer) == 0)
{
HMENU configRootMenu = GetSubMenu(configMenu, i);
if (configRootMenu)
{
InsertMenu(skinMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)configRootMenu, root.c_str());
}
break;
}
}
}
}
2009-02-10 18:37:48 +00:00
}
return skinMenu;
}
void CRainmeter::CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow)
* 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
{
bool screenDefined = meterWindow->GetXScreenDefined();
int screenIndex = meterWindow->GetXScreen();
// for the "Specified monitor" (@n)
if (CSystem::GetMonitorCount() > 0)
* 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
{
const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo();
* 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
const std::vector<MONITOR_INFO>& monitors = multimonInfo.monitors;
for (int i = 0, isize = (int)monitors.size(); i < isize; ++i)
* 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
{
2010-09-13 20:06:52 +00:00
WCHAR buffer[64];
2011-12-09 19:49:06 +00:00
size_t len = _snwprintf_s(buffer, _TRUNCATE, L"@%i: ", i + 1);
* 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
2011-12-09 19:49:06 +00:00
std::wstring item(buffer, len);
if (monitors[i].monitorName.size() > 32)
* 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
{
2011-12-09 19:49:06 +00:00
item.append(monitors[i].monitorName, 0, 32);
* 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
item += L"...";
}
else
{
item += monitors[i].monitorName;
}
InsertMenu(monitorMenu,
i + 3,
MF_BYPOSITION | ((screenDefined && screenIndex == i + 1) ? MF_CHECKED : MF_UNCHECKED) | ((!monitors[i].active) ? MF_GRAYED : MF_ENABLED),
ID_MONITOR_FIRST + i + 1,
item.c_str());
* 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
}
}
// Tick the configs
if (!screenDefined)
{
CheckMenuItem(monitorMenu, ID_CONTEXT_SKINMENU_MONITOR_PRIMARY, MF_BYCOMMAND | MF_CHECKED);
}
* 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
if (screenDefined && screenIndex == 0)
* 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
{
CheckMenuItem(monitorMenu, ID_MONITOR_FIRST, MF_BYCOMMAND | MF_CHECKED);
* 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
}
if (meterWindow->GetAutoSelectScreen())
{
CheckMenuItem(monitorMenu, ID_CONTEXT_SKINMENU_MONITOR_AUTOSELECT, MF_BYCOMMAND | MF_CHECKED);
}
* 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
}
2009-02-10 18:37:48 +00:00
void CRainmeter::ChangeSkinIndex(HMENU menu, int index)
{
int count = GetMenuItemCount(menu);
2010-03-30 22:37:05 +00:00
for (int i = 0; i < count; ++i)
2009-02-10 18:37:48 +00:00
{
HMENU subMenu = GetSubMenu(menu, i);
if (subMenu)
{
ChangeSkinIndex(subMenu, index);
}
else
{
WCHAR buffer[256];
GetMenuString(menu, i, buffer, 256, MF_BYPOSITION);
UINT id = GetMenuItemID(menu, i);
UINT flags = GetMenuState(menu, i, MF_BYPOSITION);
ModifyMenu(menu, i, MF_BYPOSITION | flags, id | (index << 16), buffer);
}
}
}
void CRainmeter::StartLogging()
{
// Check if the file exists
if (_waccess(m_LogFile.c_str(), 0) == -1)
{
// Create log file
HANDLE file = CreateFile(m_LogFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (file != INVALID_HANDLE_VALUE)
{
CloseHandle(file);
SetLogging(true);
// std::wstring text = GetFormattedString(ID_STR_LOGFILECREATED, m_LogFile.c_str());
// MessageBox(NULL, text.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
}
else
{
// Disable logging
SetLogging(false);
2011-09-23 16:28:38 +00:00
std::wstring text = GetFormattedString(ID_STR_LOGFILECREATEFAIL, m_LogFile.c_str());
MessageBox(NULL, text.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR);
}
}
else
{
SetLogging(true);
}
}
void CRainmeter::StopLogging()
{
SetLogging(false);
}
void CRainmeter::DeleteLogFile()
{
// Check if the file exists
if (_waccess(m_LogFile.c_str(), 0) != -1)
{
2011-09-23 16:28:38 +00:00
std::wstring text = GetFormattedString(ID_STR_LOGFILEDELETE, m_LogFile.c_str());
int res = MessageBox(NULL, text.c_str(), APPNAME, MB_YESNO | MB_TOPMOST | MB_ICONQUESTION);
if (res == IDYES)
{
// Disable logging
SetLogging(false);
CSystem::RemoveFile(m_LogFile);
}
}
}
void CRainmeter::AddAboutLogInfo(int level, LPCWSTR time, LPCWSTR message)
{
// Store 20 last items
LOG_INFO logInfo = {level, time, message};
m_LogData.push_back(logInfo);
if (m_LogData.size() > 20)
{
m_LogData.pop_front();
}
CDialogAbout::AddLogItem(level, time, message);
}
void CRainmeter::SetLogging(bool logging)
{
m_Logging = logging;
WritePrivateProfileString(L"Rainmeter", L"Logging", logging ? L"1" : L"0", m_IniFile.c_str());
}
void CRainmeter::SetDebug(bool debug)
{
m_Debug = debug;
WritePrivateProfileString(L"Rainmeter", L"Debug", debug ? L"1" : L"0", m_IniFile.c_str());
}
void CRainmeter::SetDisableDragging(bool dragging)
{
m_DisableDragging = dragging;
WritePrivateProfileString(L"Rainmeter", L"DisableDragging", dragging ? L"1" : L"0", m_IniFile.c_str());
}
void CRainmeter::SetDisableVersionCheck(bool check)
{
m_DisableVersionCheck = check;
WritePrivateProfileString(L"Rainmeter", L"DisableVersionCheck", check ? L"1" : L"0" , m_IniFile.c_str());
}
void CRainmeter::TestSettingsFile(bool bDefaultIniLocation)
2009-02-10 18:37:48 +00:00
{
2011-11-08 19:02:31 +00:00
if (!CSystem::IsFileWritable(m_IniFile.c_str()))
2009-02-10 18:37:48 +00:00
{
2011-09-24 09:13:13 +00:00
std::wstring error = GetString(ID_STR_SETTINGSNOTWRITABLE);
2009-02-10 18:37:48 +00:00
if (!bDefaultIniLocation)
{
std::wstring strTarget = L"%APPDATA%\\Rainmeter\\";
ExpandEnvironmentVariables(strTarget);
2011-09-23 16:28:38 +00:00
error += GetFormattedString(ID_STR_SETTINGSMOVEFILE, m_IniFile.c_str(), strTarget.c_str());
}
else
{
2011-09-23 16:28:38 +00:00
error += GetFormattedString(ID_STR_SETTINGSREADONLY, m_IniFile.c_str());
}
2009-02-10 18:37:48 +00:00
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_ICONERROR);
2009-02-10 18:37:48 +00:00
}
}
std::wstring CRainmeter::ExtractPath(const std::wstring& strFilePath)
{
2010-08-06 07:40:43 +00:00
std::wstring::size_type pos = strFilePath.find_last_of(L"\\/");
if (pos != std::wstring::npos)
{
return strFilePath.substr(0, pos + 1);
}
2010-08-06 07:40:43 +00:00
return L".\\";
}
void CRainmeter::ExpandEnvironmentVariables(std::wstring& strPath)
{
std::wstring::size_type pos;
if ((pos = strPath.find(L'%')) != std::wstring::npos &&
strPath.find(L'%', pos + 2) != std::wstring::npos)
{
2011-02-15 16:26:54 +00:00
DWORD bufSize = 4096;
WCHAR* buffer = new WCHAR[bufSize]; // lets hope the buffer is large enough...
// %APPDATA% is a special case
pos = strPath.find(L"%APPDATA%", pos);
if (pos != std::wstring::npos)
{
HRESULT hr = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, buffer);
if (SUCCEEDED(hr))
{
2011-11-24 00:30:56 +00:00
size_t len = wcslen(buffer);
2010-07-22 01:50:22 +00:00
do
{
2011-11-24 00:30:56 +00:00
strPath.replace(pos, 9, buffer, len);
2010-07-22 01:50:22 +00:00
}
2011-11-24 00:30:56 +00:00
while ((pos = strPath.find(L"%APPDATA%", pos + len)) != std::wstring::npos);
}
}
2011-11-24 00:30:56 +00:00
if ((pos = strPath.find(L'%')) != std::wstring::npos &&
strPath.find(L'%', pos + 2) != std::wstring::npos)
{
// Expand the environment variables
do
{
DWORD ret = ExpandEnvironmentStrings(strPath.c_str(), buffer, bufSize);
if (ret == 0) // Error
{
LogWithArgs(LOG_WARNING, L"Unable to expand environment strings in: %s", strPath.c_str());
break;
}
if (ret <= bufSize) // Fits in the buffer
{
2011-12-09 19:49:06 +00:00
strPath.assign(buffer, ret - 1);
break;
}
delete [] buffer;
bufSize = ret;
buffer = new WCHAR[bufSize];
}
while (true);
}
delete [] buffer;
}
}