mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
4399 lines
110 KiB
C++
4399 lines
110 KiB
C++
/*
|
|
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "Rainmeter.h"
|
|
#include "TrayWindow.h"
|
|
#include "System.h"
|
|
#include "Error.h"
|
|
#include "DialogAbout.h"
|
|
#include "DialogManage.h"
|
|
#include "MeasureNet.h"
|
|
#include "MeterString.h"
|
|
#include "resource.h"
|
|
#include "UpdateCheck.h"
|
|
#include "../Version.h"
|
|
|
|
#include "DisableThreadLibraryCalls.h" // contains DllMain entry point
|
|
|
|
using namespace Gdiplus;
|
|
|
|
CRainmeter* Rainmeter; // The module
|
|
|
|
bool CRainmeter::c_DummyLitestep = false;
|
|
std::wstring CRainmeter::c_CmdLine;
|
|
|
|
/*
|
|
** ParseString
|
|
**
|
|
** Splits the given string into substrings
|
|
**
|
|
*/
|
|
std::vector<std::wstring> CRainmeter::ParseString(LPCTSTR str)
|
|
{
|
|
std::vector<std::wstring> result;
|
|
if (str)
|
|
{
|
|
std::wstring arg = str;
|
|
|
|
// Split the argument between first space.
|
|
// Or if string is in quotes, the after the second quote.
|
|
|
|
size_t pos;
|
|
std::wstring newStr;
|
|
while ((pos = arg.find_first_not_of(L' ')) != std::wstring::npos)
|
|
{
|
|
if (arg[pos] == L'"')
|
|
{
|
|
if (arg.size() > (pos + 2) &&
|
|
arg[pos + 1] == L'"' && arg[pos + 2] == L'"')
|
|
{
|
|
// Eat found quotes and finding ending """
|
|
arg.erase(0, pos + 3);
|
|
|
|
size_t extra = 4;
|
|
if ((pos = arg.find(L"\"\"\" ")) == std::wstring::npos)
|
|
{
|
|
extra = 3;
|
|
pos = arg.find(L"\"\"\"");
|
|
}
|
|
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
newStr.assign(arg, 0, pos);
|
|
arg.erase(0, pos + extra);
|
|
|
|
result.push_back(newStr);
|
|
}
|
|
|
|
// Skip stripping quotes
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// Eat found quote and find ending quote
|
|
arg.erase(0, pos + 1);
|
|
pos = arg.find_first_of(L'"');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pos > 0)
|
|
{
|
|
// Eat everything until non-space (and non-quote) char
|
|
arg.erase(0, pos);
|
|
}
|
|
|
|
// Find the second quote
|
|
pos = arg.find_first_of(L' ');
|
|
}
|
|
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
newStr.assign(arg, 0, pos);
|
|
arg.erase(0, pos + 1);
|
|
|
|
// Strip quotes
|
|
while ((pos = newStr.find(L'"')) != std::wstring::npos)
|
|
{
|
|
newStr.erase(pos, 1);
|
|
}
|
|
|
|
result.push_back(newStr);
|
|
}
|
|
else // quote or space not found
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (arg.size() > 0)
|
|
{
|
|
// Strip quotes
|
|
while ((pos = arg.find(L'"')) != std::wstring::npos)
|
|
{
|
|
arg.erase(pos, 1);
|
|
}
|
|
|
|
result.push_back(arg);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
** initModuleEx
|
|
**
|
|
** This is called when the plugin is initialized
|
|
**
|
|
*/
|
|
int initModuleEx(HWND ParentWnd, HINSTANCE dllInst, LPCSTR szPath)
|
|
{
|
|
int Result=1;
|
|
|
|
try
|
|
{
|
|
Rainmeter=new CRainmeter;
|
|
|
|
if (Rainmeter)
|
|
{
|
|
Result=Rainmeter->Initialize(ParentWnd, dllInst, szPath);
|
|
}
|
|
|
|
}
|
|
catch(CError& error)
|
|
{
|
|
MessageBox(ParentWnd, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
** quitModule
|
|
**
|
|
** This is called when the plugin quits.
|
|
**
|
|
*/
|
|
void quitModule(HINSTANCE dllInst)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
Rainmeter->Quit(dllInst);
|
|
delete Rainmeter;
|
|
Rainmeter = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Initialize
|
|
**
|
|
** Init Rainmeter
|
|
**
|
|
*/
|
|
void Initialize(bool DummyLS, LPCTSTR CmdLine)
|
|
{
|
|
CRainmeter::SetDummyLitestep(DummyLS);
|
|
CRainmeter::SetCommandLine(CmdLine);
|
|
}
|
|
|
|
/*
|
|
** ExecuteBang
|
|
**
|
|
** Runs a bang command. This is called from the main application
|
|
** when a command is given as a command line argument.
|
|
**
|
|
*/
|
|
void ExecuteBang(LPCTSTR szBang)
|
|
{
|
|
if (Rainmeter && szBang)
|
|
{
|
|
// ExecuteBang needs to be delayed since it crashes if done during processing.
|
|
// The receiver must free a given string buffer (lParam) by using free().
|
|
WCHAR* bang = _wcsdup(szBang);
|
|
PostMessage(Rainmeter->GetTrayWindow()->GetWindow(), WM_TRAY_DELAYED_EXECUTE, (WPARAM)NULL, (LPARAM)bang);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** ReadConfigString
|
|
**
|
|
** Reads a config string. Used by the plugins.
|
|
**
|
|
*/
|
|
LPCTSTR ReadConfigString(LPCTSTR section, LPCTSTR key, LPCTSTR defValue)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
CConfigParser* parser = Rainmeter->GetCurrentParser();
|
|
if (parser)
|
|
{
|
|
return parser->ReadString(section, key, defValue, false).c_str();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
** PluginBridge
|
|
**
|
|
** Receives a command and data from a plugin and returns a result. Used by plugins.
|
|
**
|
|
*/
|
|
LPCTSTR PluginBridge(LPCTSTR _sCommand, LPCTSTR _sData)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
static std::wstring result;
|
|
|
|
if (_sCommand == NULL || *_sCommand == L'\0')
|
|
{
|
|
return L"noop";
|
|
}
|
|
|
|
if (_sData == NULL) _sData = L"";
|
|
|
|
std::wstring sCommand = _sCommand;
|
|
std::transform(sCommand.begin(), sCommand.end(), sCommand.begin(), ::towlower);
|
|
|
|
// Command GetConfig
|
|
// Data unquoted full path and filename given to the plugin on initialize
|
|
// (note: this is CaSe-SeNsItIvE!)
|
|
// Execution none
|
|
// Result the config name if found or a blank string if not
|
|
if (sCommand == L"getconfig")
|
|
{
|
|
// returns the config name, lookup by INI file
|
|
|
|
CMeterWindow *meterWindow = Rainmeter->GetMeterWindowByINI(_sData);
|
|
if (meterWindow)
|
|
{
|
|
result = L"\"";
|
|
result += meterWindow->GetSkinName();
|
|
result += L"\"";
|
|
return result.c_str();
|
|
}
|
|
|
|
return L"";
|
|
}
|
|
|
|
// Command GetWindow
|
|
// Data [the config name]
|
|
// Execution none
|
|
// Result the HWND to the specified config window if found, 'error' otherwise
|
|
if (sCommand == L"getwindow")
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(_sData);
|
|
|
|
if (subStrings.size() >= 1)
|
|
{
|
|
const std::wstring& config = subStrings[0];
|
|
|
|
CMeterWindow *meterWindow = Rainmeter->GetMeterWindow(config);
|
|
if (meterWindow)
|
|
{
|
|
WCHAR buf1[64];
|
|
_snwprintf_s(buf1, _TRUNCATE, L"%lu", PtrToUlong(meterWindow->GetWindow()));
|
|
result = buf1;
|
|
return result.c_str();
|
|
}
|
|
}
|
|
return L"error";
|
|
}
|
|
|
|
// Command GetVariable
|
|
// Data [the config name]
|
|
// Execution none
|
|
// Result the value of the variable
|
|
if (sCommand == L"getvariable")
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(_sData);
|
|
|
|
if (subStrings.size() >= 2)
|
|
{
|
|
const std::wstring& config = subStrings[0];
|
|
|
|
CMeterWindow *meterWindow = Rainmeter->GetMeterWindow(config);
|
|
if (meterWindow)
|
|
{
|
|
const std::wstring& variable = subStrings[1];
|
|
std::wstring result_from_parser;
|
|
|
|
if (meterWindow->GetParser().GetVariable(variable, result_from_parser))
|
|
{
|
|
result = result_from_parser;
|
|
return result.c_str();
|
|
}
|
|
}
|
|
}
|
|
|
|
return L"";
|
|
}
|
|
|
|
// Command SetVariable
|
|
// Data [the config name] [variable data]
|
|
// Execution the indicated variable is updated
|
|
// Result 'success' if the config was found, 'error' otherwise
|
|
if (sCommand == L"setvariable")
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(_sData);
|
|
|
|
if (subStrings.size() >= 2)
|
|
{
|
|
const std::wstring& config = subStrings[0];
|
|
std::wstring arguments;
|
|
|
|
for (size_t i = 1, isize = subStrings.size(); i < isize; ++i)
|
|
{
|
|
if (i != 1) arguments += L" ";
|
|
arguments += subStrings[i];
|
|
}
|
|
|
|
CMeterWindow *meterWindow = Rainmeter->GetMeterWindow(config);
|
|
if (meterWindow)
|
|
{
|
|
meterWindow->RunBang(BANG_SETVARIABLE, arguments.c_str());
|
|
return L"success";
|
|
}
|
|
}
|
|
|
|
/*
|
|
result = L"er1/";
|
|
result += subStrings[0];
|
|
result += L"/";
|
|
TCHAR x[100];
|
|
_snwprintf_s(x, _TRUNCATE, L"%d", subStrings.size());
|
|
result += x;
|
|
return result.c_str();
|
|
*/
|
|
return L"error";
|
|
}
|
|
|
|
return L"noop";
|
|
}
|
|
|
|
return L"error:no rainmeter!";
|
|
}
|
|
|
|
/*
|
|
** BangWithArgs
|
|
**
|
|
** Parses Bang args
|
|
**
|
|
*/
|
|
void BangWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
size_t subStringsSize = subStrings.size();
|
|
std::wstring config;
|
|
std::wstring argument;
|
|
|
|
// Don't include the config name from the arg if there is one
|
|
for (size_t i = 0; i < numOfArgs; ++i)
|
|
{
|
|
if (i != 0) argument += L" ";
|
|
if (i < subStringsSize)
|
|
{
|
|
argument += subStrings[i];
|
|
}
|
|
}
|
|
|
|
if (subStringsSize >= numOfArgs)
|
|
{
|
|
if (subStringsSize > numOfArgs)
|
|
{
|
|
config = subStrings[numOfArgs];
|
|
}
|
|
|
|
if ((!config.empty()) && (config != L"*"))
|
|
{
|
|
// Config defined, so bang only that
|
|
CMeterWindow* meterWindow = Rainmeter->GetMeterWindow(config);
|
|
|
|
if (meterWindow)
|
|
{
|
|
if (bang == BANG_LSHOOK)
|
|
{
|
|
// LsHook is a special case
|
|
meterWindow->RunBang(bang, arg);
|
|
}
|
|
else
|
|
{
|
|
meterWindow->RunBang(bang, argument.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::wstring dbg = L"Unknown config name: " + config;
|
|
Log(LOG_NOTICE, dbg.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No config defined -> apply to all.
|
|
const std::map<std::wstring, CMeterWindow*>& windows = Rainmeter->GetAllMeterWindows();
|
|
std::map<std::wstring, CMeterWindow*>::const_iterator iter = windows.begin();
|
|
|
|
for (; iter != windows.end(); ++iter)
|
|
{
|
|
((*iter).second)->RunBang(bang, argument.c_str());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Incorrect number of arguments for the bang!");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** BangGroupWithArgs
|
|
**
|
|
** Parses Bang args for Group
|
|
**
|
|
*/
|
|
void BangGroupWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (subStrings.size() > numOfArgs)
|
|
{
|
|
std::multimap<int, CMeterWindow*> windows;
|
|
Rainmeter->GetMeterWindowsByLoadOrder(windows, subStrings[numOfArgs]);
|
|
|
|
std::multimap<int, CMeterWindow*>::const_iterator iter = windows.begin();
|
|
for (; iter != windows.end(); ++iter)
|
|
{
|
|
std::wstring argument = L"\"";
|
|
for (size_t i = 0; i < numOfArgs; ++i)
|
|
{
|
|
argument += subStrings[i];
|
|
argument += L"\" \"";
|
|
}
|
|
argument += (*iter).second->GetSkinName();
|
|
argument += L"\"";
|
|
BangWithArgs(bang, argument.c_str(), numOfArgs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Incorrect number of arguments for the group bang!");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
//
|
|
// Callbacks for Litestep
|
|
//
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
/*
|
|
** RainmeterHide
|
|
**
|
|
** Callback for the !RainmeterHide bang
|
|
**
|
|
*/
|
|
void RainmeterHide(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_HIDE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShow
|
|
**
|
|
** Callback for the !RainmeterShow bang
|
|
**
|
|
*/
|
|
void RainmeterShow(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SHOW, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggle
|
|
**
|
|
** Callback for the !RainmeterToggle bang
|
|
**
|
|
*/
|
|
void RainmeterToggle(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideFade
|
|
**
|
|
** Callback for the !RainmeterHideFade bang
|
|
**
|
|
*/
|
|
void RainmeterHideFade(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_HIDEFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowFade
|
|
**
|
|
** Callback for the !RainmeterShowFade bang
|
|
**
|
|
*/
|
|
void RainmeterShowFade(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SHOWFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleFade
|
|
**
|
|
** Callback for the !RainmeterToggleFade bang
|
|
**
|
|
*/
|
|
void RainmeterToggleFade(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideBlur
|
|
**
|
|
** Callback for the !RainmeterHideBlur bang
|
|
**
|
|
*/
|
|
void RainmeterHideBlur(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_HIDEBLUR, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowBlur
|
|
**
|
|
** Callback for the !RainmeterShowBlur bang
|
|
**
|
|
*/
|
|
void RainmeterShowBlur(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SHOWBLUR, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleBlur
|
|
**
|
|
** Callback for the !RainmeterToggleBlur bang
|
|
**
|
|
*/
|
|
void RainmeterToggleBlur(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEBLUR, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterAddBlur
|
|
**
|
|
** Callback for the !RainmeterAddBlur bang
|
|
**
|
|
*/
|
|
void RainmeterAddBlur(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_ADDBLUR, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
|
|
/*
|
|
** RainmeterRemoveBlur
|
|
**
|
|
** Callback for the !RainmeterRemoveBlur bang
|
|
**
|
|
*/
|
|
void RainmeterRemoveBlur(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_REMOVEBLUR, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideMeter
|
|
**
|
|
** Callback for the !RainmeterHideMeter bang
|
|
**
|
|
*/
|
|
void RainmeterHideMeter(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_HIDEMETER, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowMeter
|
|
**
|
|
** Callback for the !RainmeterShowMeter bang
|
|
**
|
|
*/
|
|
void RainmeterShowMeter(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SHOWMETER, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleMeter
|
|
**
|
|
** Callback for the !RainmeterToggleMeter bang
|
|
**
|
|
*/
|
|
void RainmeterToggleMeter(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMETER, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterMoveMeter
|
|
**
|
|
** Callback for the !RainmeterMoveMeter bang
|
|
**
|
|
*/
|
|
void RainmeterMoveMeter(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_MOVEMETER, ConvertToWide(arg).c_str(), 3);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdateMeter
|
|
**
|
|
** Callback for the !RainmeterUpdateMeter bang
|
|
**
|
|
*/
|
|
void RainmeterUpdateMeter(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMETER, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterDisableMeasure
|
|
**
|
|
** Callback for the !RainmeterDisableMeasure bang
|
|
**
|
|
*/
|
|
void RainmeterDisableMeasure(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_DISABLEMEASURE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterEnableMeasure
|
|
**
|
|
** Callback for the !RainmeterEnableMeasure bang
|
|
**
|
|
*/
|
|
void RainmeterEnableMeasure(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_ENABLEMEASURE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleMeasure
|
|
**
|
|
** Callback for the !RainmeterToggleMeasure bang
|
|
**
|
|
*/
|
|
void RainmeterToggleMeasure(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMEASURE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdateMeasure
|
|
**
|
|
** Callback for the !RainmeterUpdateMeasure bang
|
|
**
|
|
*/
|
|
void RainmeterUpdateMeasure(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMEASURE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterCommandMeasure
|
|
**
|
|
** Callback for the !RainmeterCommandMeasure bang
|
|
**
|
|
*/
|
|
void RainmeterCommandMeasure(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_COMMANDMEASURE, ConvertToWide(arg).c_str(), 2);
|
|
}
|
|
|
|
/*
|
|
** RainmeterRefresh
|
|
**
|
|
** Callback for the !RainmeterRefresh bang
|
|
**
|
|
*/
|
|
void RainmeterRefresh(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_REFRESH, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterRefreshApp
|
|
**
|
|
** Callback for the !RainmeterRefreshApp bang
|
|
**
|
|
*/
|
|
void RainmeterRefreshApp(HWND, const char* arg)
|
|
{
|
|
RainmeterRefreshAppWide();
|
|
}
|
|
|
|
/*
|
|
** RainmeterRedraw
|
|
**
|
|
** Callback for the !RainmeterRedraw bang
|
|
**
|
|
*/
|
|
void RainmeterRedraw(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_REDRAW, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdate
|
|
**
|
|
** Callback for the !RainmeterUpdate bang
|
|
**
|
|
*/
|
|
void RainmeterUpdate(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_UPDATE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterActivateConfig
|
|
**
|
|
** Callback for the !RainmeterActivateConfig bang
|
|
**
|
|
*/
|
|
void RainmeterActivateConfig(HWND, const char* arg)
|
|
{
|
|
RainmeterActivateConfigWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterDeactivateConfig
|
|
**
|
|
** Callback for the !RainmeterDeactivateConfig bang
|
|
**
|
|
*/
|
|
void RainmeterDeactivateConfig(HWND, const char* arg)
|
|
{
|
|
RainmeterDeactivateConfigWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleConfig
|
|
**
|
|
** Callback for the !RainmeterToggleConfig bang
|
|
**
|
|
*/
|
|
void RainmeterToggleConfig(HWND, const char* arg)
|
|
{
|
|
RainmeterToggleConfigWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterMove
|
|
**
|
|
** Callback for the !RainmeterMove bang
|
|
**
|
|
*/
|
|
void RainmeterMove(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_MOVE, ConvertToWide(arg).c_str(), 2);
|
|
}
|
|
|
|
/*
|
|
** RainmeterZPos
|
|
**
|
|
** Callback for the !RainmeterZPos bang
|
|
**
|
|
*/
|
|
void RainmeterZPos(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_ZPOS, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterClickThrough
|
|
**
|
|
** Callback for the !RainmeterClickThrough bang
|
|
**
|
|
*/
|
|
void RainmeterClickThrough(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_CLICKTHROUGH, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterDraggable
|
|
**
|
|
** Callback for the !RainmeterDraggable bang
|
|
**
|
|
*/
|
|
void RainmeterDraggable(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_DRAGGABLE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSnapEdges
|
|
**
|
|
** Callback for the !RainmeterSnapEdges bang
|
|
**
|
|
*/
|
|
void RainmeterSnapEdges(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SNAPEDGES, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterKeepOnScreen
|
|
**
|
|
** Callback for the !RainmeterKeepOnScreen bang
|
|
**
|
|
*/
|
|
void RainmeterKeepOnScreen(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_KEEPONSCREEN, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSetTransparency
|
|
**
|
|
** Callback for the !RainmeterSetTransparency bang
|
|
**
|
|
*/
|
|
void RainmeterSetTransparency(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SETTRANSPARENCY, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSetVariable
|
|
**
|
|
** Callback for the !RainmeterSetVariable bang
|
|
**
|
|
*/
|
|
void RainmeterSetVariable(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SETVARIABLE, ConvertToWide(arg).c_str(), 2);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSetOption
|
|
**
|
|
** Callback for the !RainmeterSetOption bang
|
|
**
|
|
*/
|
|
void RainmeterSetOption(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SETOPTION, ConvertToWide(arg).c_str(), 3);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideGroup
|
|
**
|
|
** Callback for the !RainmeterHideGroup bang
|
|
**
|
|
*/
|
|
void RainmeterHideGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_HIDE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowGroup
|
|
**
|
|
** Callback for the !RainmeterShowGroup bang
|
|
**
|
|
*/
|
|
void RainmeterShowGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SHOW, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleGroup
|
|
**
|
|
** Callback for the !RainmeterToggleGroup bang
|
|
**
|
|
*/
|
|
void RainmeterToggleGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_TOGGLE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideFadeGroup
|
|
**
|
|
** Callback for the !RainmeterHideFadeGroup bang
|
|
**
|
|
*/
|
|
void RainmeterHideFadeGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_HIDEFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowFadeGroup
|
|
**
|
|
** Callback for the !RainmeterShowFadeGroup bang
|
|
**
|
|
*/
|
|
void RainmeterShowFadeGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SHOWFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleFadeGroup
|
|
**
|
|
** Callback for the !RainmeterToggleFadeGroup bang
|
|
**
|
|
*/
|
|
void RainmeterToggleFadeGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_TOGGLEFADE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterHideMeterGroup
|
|
**
|
|
** Callback for the !RainmeterHideMeterGroup bang
|
|
**
|
|
*/
|
|
void RainmeterHideMeterGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_HIDEMETERGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterShowMeterGroup
|
|
**
|
|
** Callback for the !RainmeterShowMeterGroup bang
|
|
**
|
|
*/
|
|
void RainmeterShowMeterGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_SHOWMETERGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleMeterGroup
|
|
**
|
|
** Callback for the !RainmeterToggleMeterGroup bang
|
|
**
|
|
*/
|
|
void RainmeterToggleMeterGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMETERGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdateMeterGroup
|
|
**
|
|
** Callback for the !RainmeterUpdateMeterGroup bang
|
|
**
|
|
*/
|
|
void RainmeterUpdateMeterGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMETERGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterDisableMeasureGroup
|
|
**
|
|
** Callback for the !RainmeterDisableMeasureGroup bang
|
|
**
|
|
*/
|
|
void RainmeterDisableMeasureGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_DISABLEMEASUREGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterEnableMeasureGroup
|
|
**
|
|
** Callback for the !RainmeterEnableMeasureGroup bang
|
|
**
|
|
*/
|
|
void RainmeterEnableMeasureGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_ENABLEMEASUREGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleMeasureGroup
|
|
**
|
|
** Callback for the !RainmeterToggleMeasureGroup bang
|
|
**
|
|
*/
|
|
void RainmeterToggleMeasureGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMEASUREGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdateMeasureGroup
|
|
**
|
|
** Callback for the !RainmeterUpdateMeasureGroup bang
|
|
**
|
|
*/
|
|
void RainmeterUpdateMeasureGroup(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMEASUREGROUP, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterRefreshGroup
|
|
**
|
|
** Callback for the !RainmeterRefreshGroup bang
|
|
**
|
|
*/
|
|
void RainmeterRefreshGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_REFRESH, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterRedrawGroup
|
|
**
|
|
** Callback for the !RainmeterRedrawGroup bang
|
|
**
|
|
*/
|
|
void RainmeterRedrawGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_REDRAW, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterUpdateGroup
|
|
**
|
|
** Callback for the !RainmeterUpdateGroup bang
|
|
**
|
|
*/
|
|
void RainmeterUpdateGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_UPDATE, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterDeactivateConfigGroup
|
|
**
|
|
** Callback for the !RainmeterDeactivateConfigGroup bang
|
|
**
|
|
*/
|
|
void RainmeterDeactivateConfigGroup(HWND, const char* arg)
|
|
{
|
|
RainmeterDeactivateConfigGroupWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterZPosGroup
|
|
**
|
|
** Callback for the !RainmeterZPosGroup bang
|
|
**
|
|
*/
|
|
void RainmeterZPosGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_ZPOS, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterClickThroughGroup
|
|
**
|
|
** Callback for the !RainmeterClickThroughGroup bang
|
|
**
|
|
*/
|
|
void RainmeterClickThroughGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_CLICKTHROUGH, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterDraggableGroup
|
|
**
|
|
** Callback for the !RainmeterDraggableGroup bang
|
|
**
|
|
*/
|
|
void RainmeterDraggableGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_DRAGGABLE, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSnapEdgesGroup
|
|
**
|
|
** Callback for the !RainmeterSnapEdgesGroup bang
|
|
**
|
|
*/
|
|
void RainmeterSnapEdgesGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SNAPEDGES, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterKeepOnScreenGroup
|
|
**
|
|
** Callback for the !RainmeterKeepOnScreenGroup bang
|
|
**
|
|
*/
|
|
void RainmeterKeepOnScreenGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_KEEPONSCREEN, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSetTransparencyGroup
|
|
**
|
|
** Callback for the !RainmeterSetTransparencyGroup bang
|
|
**
|
|
*/
|
|
void RainmeterSetTransparencyGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SETTRANSPARENCY, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterSetVariableGroup
|
|
**
|
|
** Callback for the !RainmeterSetVariableGroup bang
|
|
**
|
|
*/
|
|
void RainmeterSetVariableGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SETVARIABLE, ConvertToWide(arg).c_str(), 2);
|
|
}
|
|
/*
|
|
** RainmeterSetOptionGroup
|
|
**
|
|
** Callback for the !RainmeterSetOptionGroup bang
|
|
**
|
|
*/
|
|
void RainmeterSetOptionGroup(HWND, const char* arg)
|
|
{
|
|
BangGroupWithArgs(BANG_SETOPTION, ConvertToWide(arg).c_str(), 3);
|
|
}
|
|
|
|
/*
|
|
** RainmeterLsHook
|
|
**
|
|
** Callback for the !RainmeterLsHook bang
|
|
**
|
|
*/
|
|
void RainmeterLsHook(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_LSHOOK, ConvertToWide(arg).c_str(), 0);
|
|
}
|
|
|
|
/*
|
|
** RainmeterAbout
|
|
**
|
|
** Callback for the !RainmeterAbout bang
|
|
**
|
|
*/
|
|
void RainmeterAbout(HWND, const char* arg)
|
|
{
|
|
RainmeterAboutWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterManage
|
|
**
|
|
** Callback for the !RainmeterManage bang
|
|
**
|
|
*/
|
|
void RainmeterManage(HWND, const char* arg)
|
|
{
|
|
RainmeterManageWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterSkinMenu
|
|
**
|
|
** Callback for the !RainmeterSkinMenu bang
|
|
**
|
|
*/
|
|
void RainmeterSkinMenu(HWND, const char* arg)
|
|
{
|
|
RainmeterSkinMenuWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterTrayMenu
|
|
**
|
|
** Callback for the !RainmeterTrayMenu bang
|
|
**
|
|
*/
|
|
void RainmeterTrayMenu(HWND, const char* arg)
|
|
{
|
|
RainmeterTrayMenuWide();
|
|
}
|
|
|
|
/*
|
|
** RainmeterResetStats
|
|
**
|
|
** Callback for the !RainmeterResetStats bang
|
|
**
|
|
*/
|
|
void RainmeterResetStats(HWND, const char* arg)
|
|
{
|
|
RainmeterResetStatsWide();
|
|
}
|
|
|
|
/*
|
|
** RainmeterWriteKeyValue
|
|
**
|
|
** Callback for the !RainmeterWriteKeyValue bang
|
|
**
|
|
*/
|
|
void RainmeterWriteKeyValue(HWND, const char* arg)
|
|
{
|
|
RainmeterWriteKeyValueWide(ConvertToWide(arg).c_str());
|
|
}
|
|
|
|
/*
|
|
** RainmeterPluginBang
|
|
**
|
|
** Callback for the !RainmeterPluginBang bang
|
|
**
|
|
*/
|
|
void RainmeterPluginBang(HWND, const char* arg)
|
|
{
|
|
BangWithArgs(BANG_PLUGIN, ConvertToWide(arg).c_str(), 1);
|
|
}
|
|
|
|
/*
|
|
** RainmeterQuit
|
|
**
|
|
** Callback for the !RainmeterQuit bang
|
|
**
|
|
*/
|
|
void RainmeterQuit(HWND, const char* arg)
|
|
{
|
|
RainmeterQuitWide();
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
//
|
|
// Callbacks for Unicode support
|
|
//
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
/*
|
|
** RainmeterActivateConfigWide
|
|
**
|
|
** Callback for the !RainmeterActivateConfig bang
|
|
**
|
|
*/
|
|
void RainmeterActivateConfigWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (subStrings.size() > 1)
|
|
{
|
|
const std::vector<CRainmeter::CONFIG>& configs = Rainmeter->GetAllConfigs();
|
|
|
|
for (int i = 0, isize = (int)configs.size(); i < isize; ++i)
|
|
{
|
|
if (_wcsicmp(configs[i].config.c_str(), subStrings[0].c_str()) == 0)
|
|
{
|
|
for (int j = 0, jsize = (int)configs[i].iniFiles.size(); j < jsize; ++j)
|
|
{
|
|
if (_wcsicmp(configs[i].iniFiles[j].c_str(), subStrings[1].c_str()) == 0)
|
|
{
|
|
Rainmeter->ActivateConfig(i, j);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LogWithArgs(LOG_NOTICE, L"No such config: \"%s\" \"%s\"", subStrings[0].c_str(), subStrings[1].c_str());
|
|
}
|
|
else
|
|
{
|
|
// If we got this far, something went wrong
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !ActivateConfig");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterDeactivateConfigWide
|
|
**
|
|
** Callback for the !RainmeterDeactivateConfig bang
|
|
**
|
|
*/
|
|
void RainmeterDeactivateConfigWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (!subStrings.empty())
|
|
{
|
|
CMeterWindow* mw = Rainmeter->GetMeterWindow(subStrings[0]);
|
|
if (mw)
|
|
{
|
|
Rainmeter->DeactivateConfig(mw, -1);
|
|
return;
|
|
}
|
|
LogWithArgs(LOG_NOTICE, L"The config is not active: \"%s\"", subStrings[0].c_str());
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !DeactivateConfig");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterToggleConfigWide
|
|
**
|
|
** Callback for the !RainmeterToggleConfig bang
|
|
**
|
|
*/
|
|
void RainmeterToggleConfigWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (subStrings.size() >= 2)
|
|
{
|
|
CMeterWindow* mw = Rainmeter->GetMeterWindow(subStrings[0]);
|
|
if (mw)
|
|
{
|
|
Rainmeter->DeactivateConfig(mw, -1);
|
|
return;
|
|
}
|
|
|
|
// If the config wasn't active, activate it
|
|
RainmeterActivateConfigWide(arg);
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !ToggleConfig");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterDeactivateConfigGroupWide
|
|
**
|
|
** Callback for the !RainmeterDeactivateConfigGroup bang
|
|
**
|
|
*/
|
|
void RainmeterDeactivateConfigGroupWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (!subStrings.empty())
|
|
{
|
|
std::multimap<int, CMeterWindow*> windows;
|
|
Rainmeter->GetMeterWindowsByLoadOrder(windows, subStrings[0]);
|
|
|
|
std::multimap<int, CMeterWindow*>::const_iterator iter = windows.begin();
|
|
for (; iter != windows.end(); ++iter)
|
|
{
|
|
Rainmeter->DeactivateConfig((*iter).second, -1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !DeactivateConfigGroup");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterRefreshAppWide
|
|
**
|
|
** Callback for the !RainmeterRefreshApp bang
|
|
**
|
|
*/
|
|
void RainmeterRefreshAppWide()
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
// Refresh needs to be delayed since it crashes if done during Update()
|
|
PostMessage(Rainmeter->GetTrayWindow()->GetWindow(), WM_TRAY_DELAYED_REFRESH_ALL, (WPARAM)NULL, (LPARAM)NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterAboutWide
|
|
**
|
|
** Callback for the !RainmeterAbout bang
|
|
**
|
|
*/
|
|
void RainmeterAboutWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
int tab = 0;
|
|
if (arg)
|
|
{
|
|
if (_wcsnicmp(arg, L"Measures", 8) == 0)
|
|
{
|
|
tab = 1;
|
|
}
|
|
else if (_wcsnicmp(arg, L"Plugins", 7) == 0)
|
|
{
|
|
tab = 2;
|
|
}
|
|
else if (_wcsnicmp(arg, L"Version", 7) == 0)
|
|
{
|
|
tab = 3;
|
|
}
|
|
}
|
|
|
|
CDialogAbout::Open(tab);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterManageWide
|
|
**
|
|
** Callback for the !RainmeterManage bang
|
|
**
|
|
*/
|
|
void RainmeterManageWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
int tab = 0;
|
|
if (arg)
|
|
{
|
|
if (_wcsnicmp(arg, L"Themes", 6) == 0)
|
|
{
|
|
tab = 1;
|
|
}
|
|
else if (_wcsnicmp(arg, L"Settings", 8) == 0)
|
|
{
|
|
tab = 2;
|
|
}
|
|
}
|
|
|
|
CDialogManage::Open(tab);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterSkinMenuWide
|
|
**
|
|
** Callback for the !RainmeterSkinMenu bang
|
|
**
|
|
*/
|
|
void RainmeterSkinMenuWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (!subStrings.empty())
|
|
{
|
|
CMeterWindow* mw = Rainmeter->GetMeterWindow(subStrings[0]);
|
|
if (mw)
|
|
{
|
|
POINT pos;
|
|
GetCursorPos(&pos);
|
|
Rainmeter->ShowContextMenu(pos, mw);
|
|
return;
|
|
}
|
|
LogWithArgs(LOG_NOTICE, L"The config is not active: \"%s\"", subStrings[0].c_str());
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !SkinMenu");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterTrayMenuWide
|
|
**
|
|
** Callback for the !RainmeterTrayMenu bang
|
|
**
|
|
*/
|
|
void RainmeterTrayMenuWide()
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
POINT pos;
|
|
GetCursorPos(&pos);
|
|
Rainmeter->ShowContextMenu(pos, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterResetStatsWide
|
|
**
|
|
** Callback for the !RainmeterResetStats bang
|
|
**
|
|
*/
|
|
void RainmeterResetStatsWide()
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
Rainmeter->ResetStats();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterWriteKeyValueWide
|
|
**
|
|
** Callback for the !RainmeterWriteKeyValue bang
|
|
**
|
|
*/
|
|
void RainmeterWriteKeyValueWide(const WCHAR* arg)
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
std::vector<std::wstring> subStrings = CRainmeter::ParseString(arg);
|
|
|
|
if (subStrings.size() > 3)
|
|
{
|
|
const std::wstring& iniFile = subStrings[3];
|
|
|
|
if (iniFile.find(L"..\\") != std::string::npos || iniFile.find(L"../") != std::string::npos)
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Illegal characters in path - \"..\\\": %s", iniFile.c_str());
|
|
return;
|
|
}
|
|
|
|
const std::wstring& skinPath = Rainmeter->GetSkinPath();
|
|
const std::wstring settingsPath = Rainmeter->GetSettingsPath();
|
|
|
|
if (_wcsnicmp(iniFile.c_str(), skinPath.c_str(), skinPath.size()) != 0 &&
|
|
_wcsnicmp(iniFile.c_str(), settingsPath.c_str(), settingsPath.size()) != 0)
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Illegal path outside of Rainmeter directories: %s", iniFile.c_str());
|
|
return;
|
|
}
|
|
|
|
// Verify whether the file exists
|
|
if (_waccess(iniFile.c_str(), 0) == -1)
|
|
{
|
|
LogWithArgs(LOG_WARNING, L"!WriteKeyValue: File not found: %s", iniFile.c_str());
|
|
return;
|
|
}
|
|
|
|
// Verify whether the file is read-only
|
|
DWORD attr = GetFileAttributes(iniFile.c_str());
|
|
if (attr == -1 || (attr & FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
LogWithArgs(LOG_WARNING, L"!WriteKeyValue: File is read-only: %s", iniFile.c_str());
|
|
return;
|
|
}
|
|
|
|
// Avoid "IniFileMapping"
|
|
std::vector<std::wstring> iniFileMappings;
|
|
CSystem::GetIniFileMappingList(iniFileMappings);
|
|
std::wstring iniWrite = CSystem::GetTemporaryFile(iniFileMappings, iniFile);
|
|
if (iniWrite == L"<>") // error occurred
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to create a temporary file: %s", iniFile.c_str());
|
|
return;
|
|
}
|
|
|
|
bool temporary = !iniWrite.empty();
|
|
|
|
if (temporary)
|
|
{
|
|
if (CRainmeter::GetDebug()) LogWithArgs(LOG_DEBUG, L"!WriteKeyValue: Writing file: %s (Temp: %s)", iniFile.c_str(), iniWrite.c_str());
|
|
}
|
|
else
|
|
{
|
|
if (CRainmeter::GetDebug()) LogWithArgs(LOG_DEBUG, L"!WriteKeyValue: Writing file: %s", iniFile.c_str());
|
|
iniWrite = iniFile;
|
|
}
|
|
|
|
const std::wstring& strSection = subStrings[0];
|
|
const std::wstring& strKey = subStrings[1];
|
|
const std::wstring& strValue = subStrings[2];
|
|
|
|
bool formula = false;
|
|
BOOL write = 0;
|
|
|
|
if (subStrings.size() > 4)
|
|
{
|
|
CMeterWindow* mw = Rainmeter->GetMeterWindow(subStrings[4]);
|
|
if (mw)
|
|
{
|
|
double value;
|
|
formula = mw->GetParser().ReadFormula(strValue, &value);
|
|
|
|
// Formula read fine
|
|
if (formula)
|
|
{
|
|
WCHAR buffer[256];
|
|
int len = _snwprintf_s(buffer, _TRUNCATE, L"%.5f", value);
|
|
CMeasure::RemoveTrailingZero(buffer, len);
|
|
|
|
const std::wstring& resultString = buffer;
|
|
|
|
write = WritePrivateProfileString(strSection.c_str(), strKey.c_str(), resultString.c_str(), iniWrite.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!formula)
|
|
{
|
|
write = WritePrivateProfileString(strSection.c_str(), strKey.c_str(), strValue.c_str(), iniWrite.c_str());
|
|
}
|
|
|
|
if (temporary)
|
|
{
|
|
if (write != 0)
|
|
{
|
|
WritePrivateProfileString(NULL, NULL, NULL, iniWrite.c_str()); // FLUSH
|
|
|
|
// Copy the file back
|
|
if (!CSystem::CopyFiles(iniWrite, iniFile))
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to copy a temporary file to the original filepath: %s (Temp: %s)", iniFile.c_str(), iniWrite.c_str());
|
|
}
|
|
}
|
|
else // failed
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to write a value to the file: %s (Temp: %s)", iniFile.c_str(), iniWrite.c_str());
|
|
}
|
|
|
|
// Remove a temporary file
|
|
CSystem::RemoveFile(iniWrite);
|
|
}
|
|
else
|
|
{
|
|
if (write == 0) // failed
|
|
{
|
|
LogWithArgs(LOG_ERROR, L"!WriteKeyValue: Failed to write a value to the file: %s", iniFile.c_str());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to parse the arguments for !WriteKeyValue");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** RainmeterQuitWide
|
|
**
|
|
** Callback for the !RainmeterQuit bang
|
|
**
|
|
*/
|
|
void RainmeterQuitWide()
|
|
{
|
|
if (Rainmeter)
|
|
{
|
|
// Quit needs to be delayed since it crashes if done during Update()
|
|
PostMessage(Rainmeter->GetTrayWindow()->GetWindow(), WM_COMMAND, MAKEWPARAM(ID_CONTEXT_QUIT, 0), (LPARAM)NULL);
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
//
|
|
// The class starts here
|
|
//
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
GlobalConfig CRainmeter::c_GlobalConfig = {0};
|
|
bool CRainmeter::c_Debug = false;
|
|
|
|
/*
|
|
** CRainmeter
|
|
**
|
|
** Constructor
|
|
**
|
|
*/
|
|
CRainmeter::CRainmeter() :
|
|
m_TrayWindow(),
|
|
m_DisableVersionCheck(false),
|
|
m_NewVersion(false),
|
|
m_DesktopWorkAreaChanged(false),
|
|
m_DesktopWorkAreaType(false),
|
|
m_MenuActive(false),
|
|
m_DisableRDP(false),
|
|
m_DisableDragging(false),
|
|
m_Logging(false),
|
|
m_CurrentParser(),
|
|
m_Instance(),
|
|
m_GDIplusToken()
|
|
{
|
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
|
|
|
InitCommonControls();
|
|
|
|
// Initialize GDI+.
|
|
GdiplusStartupInput gdiplusStartupInput;
|
|
GdiplusStartup(&m_GDIplusToken, &gdiplusStartupInput, NULL);
|
|
}
|
|
|
|
/*
|
|
** ~CRainmeter
|
|
**
|
|
** Destructor
|
|
**
|
|
*/
|
|
CRainmeter::~CRainmeter()
|
|
{
|
|
DeleteMeterWindow(NULL, false); // This removes the window from the vector
|
|
|
|
if (m_TrayWindow) delete m_TrayWindow;
|
|
|
|
CSystem::Finalize();
|
|
|
|
CMeasureNet::UpdateIFTable();
|
|
CMeasureNet::UpdateStats();
|
|
WriteStats(true);
|
|
|
|
CMeasureNet::FinalizeNewApi();
|
|
|
|
CMeterString::FreeFontCache();
|
|
|
|
// Change the work area back
|
|
if (m_DesktopWorkAreaChanged)
|
|
{
|
|
UpdateDesktopWorkArea(true);
|
|
}
|
|
|
|
FinalizeLitestep();
|
|
|
|
CoUninitialize();
|
|
|
|
GdiplusShutdown(m_GDIplusToken);
|
|
}
|
|
|
|
/*
|
|
** Initialize
|
|
**
|
|
** The main initialization function for the module.
|
|
** May throw CErrors !!!!
|
|
**
|
|
*/
|
|
int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath)
|
|
{
|
|
int Result=0;
|
|
|
|
if (Parent==NULL || Instance==NULL)
|
|
{
|
|
throw CError(CError::ERROR_NULL_PARAMETER, __LINE__, __FILE__);
|
|
}
|
|
|
|
m_Instance = Instance;
|
|
|
|
WCHAR* tmpSzPath = new WCHAR[MAX_LINE_LENGTH];
|
|
GetModuleFileName(m_Instance, tmpSzPath, MAX_LINE_LENGTH);
|
|
|
|
// Remove the module's name from the path
|
|
WCHAR* pos = wcsrchr(tmpSzPath, L'\\');
|
|
if (pos)
|
|
{
|
|
*(pos + 1) = L'\0';
|
|
}
|
|
else
|
|
{
|
|
tmpSzPath[0] = L'\0';
|
|
}
|
|
|
|
m_Path = tmpSzPath;
|
|
|
|
InitalizeLitestep();
|
|
|
|
bool bDefaultIniLocation = false;
|
|
|
|
if (c_CmdLine.empty())
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The command line defines the location of Rainmeter.ini (or whatever it calls it).
|
|
std::wstring iniFile = c_CmdLine;
|
|
if (iniFile[0] == L'\"')
|
|
{
|
|
if (iniFile.length() == 1)
|
|
{
|
|
iniFile.clear();
|
|
}
|
|
else if (iniFile[iniFile.length() - 1] == L'\"')
|
|
{
|
|
iniFile.assign(iniFile, 1, iniFile.length() - 2);
|
|
}
|
|
}
|
|
|
|
ExpandEnvironmentVariables(iniFile);
|
|
|
|
if (iniFile.empty() || iniFile[iniFile.length() - 1] == L'\\')
|
|
{
|
|
iniFile += L"Rainmeter.ini";
|
|
}
|
|
else if (iniFile.length() <= 4 || _wcsicmp(iniFile.substr(iniFile.length() - 4).c_str(), L".ini") != 0)
|
|
{
|
|
iniFile += L"\\Rainmeter.ini";
|
|
}
|
|
|
|
if (iniFile[0] != L'\\' && iniFile[0] != L'/' && 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;
|
|
}
|
|
|
|
// Set the log file and stats file location
|
|
m_LogFile = m_StatsFile = m_IniFile;
|
|
size_t logFileLen = m_LogFile.length();
|
|
if (logFileLen > 4 && _wcsicmp(m_LogFile.substr(logFileLen - 4).c_str(), L".ini") == 0)
|
|
{
|
|
m_LogFile.replace(logFileLen - 4, 4, L".log");
|
|
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());
|
|
c_Debug = 0!=GetPrivateProfileInt(L"Rainmeter", L"Debug", 0, m_IniFile.c_str());
|
|
|
|
if (m_Logging)
|
|
{
|
|
StartLogging();
|
|
}
|
|
|
|
m_PluginPath = m_AddonPath = m_SkinPath = m_Path;
|
|
m_PluginPath += L"Plugins\\";
|
|
m_AddonPath += L"Addons\\";
|
|
m_SkinPath += L"Skins\\";
|
|
|
|
// Read the skin folder from the ini file
|
|
tmpSzPath[0] = L'\0';
|
|
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())
|
|
{
|
|
WCHAR ch = m_SkinPath[m_SkinPath.size() - 1];
|
|
if (ch != L'\\' && ch != L'/')
|
|
{
|
|
m_SkinPath += L"\\";
|
|
}
|
|
}
|
|
}
|
|
else if (bDefaultIniLocation)
|
|
{
|
|
// 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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_WARNING, L"Unable to get the My Documents location.");
|
|
}
|
|
|
|
WritePrivateProfileString(L"Rainmeter", L"SkinPath", m_SkinPath.c_str(), m_IniFile.c_str());
|
|
}
|
|
|
|
delete [] tmpSzPath;
|
|
tmpSzPath = NULL;
|
|
|
|
if (!c_DummyLitestep)
|
|
{
|
|
char* tmpSz = new char[MAX_LINE_LENGTH];
|
|
|
|
// Check if step.rc has overrides these values
|
|
if (GetRCString("RainmeterIniFile", tmpSz, NULL, MAX_LINE_LENGTH - 1))
|
|
{
|
|
m_IniFile = ConvertToWide(tmpSz);
|
|
}
|
|
|
|
if (GetRCString("RainmeterSkinPath", tmpSz, NULL, MAX_LINE_LENGTH - 1))
|
|
{
|
|
m_SkinPath = ConvertToWide(tmpSz);
|
|
}
|
|
|
|
if (GetRCString("RainmeterPluginPath", tmpSz, NULL, MAX_LINE_LENGTH - 1))
|
|
{
|
|
m_PluginPath = ConvertToWide(tmpSz);
|
|
}
|
|
|
|
delete [] tmpSz;
|
|
|
|
if (!m_SkinPath.empty())
|
|
{
|
|
WCHAR ch = m_SkinPath[m_SkinPath.size() - 1];
|
|
if (ch != L'\\' && ch != L'/')
|
|
{
|
|
m_SkinPath += L"\\";
|
|
}
|
|
}
|
|
}
|
|
|
|
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());
|
|
|
|
// 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)
|
|
{
|
|
m_Drive.assign(m_Path, 0, loc + 1);
|
|
}
|
|
else if (m_Path.length() >= 2 && (m_Path[0] == L'\\' || m_Path[0] == L'/') && (m_Path[1] == L'\\' || m_Path[1] == L'/'))
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
m_Drive.assign(m_Path, 0, loc);
|
|
}
|
|
|
|
// Test that the Rainmeter.ini file is writable
|
|
TestSettingsFile(bDefaultIniLocation);
|
|
|
|
CSystem::Initialize(Instance);
|
|
CMeasureNet::InitializeNewApi();
|
|
|
|
if (c_Debug)
|
|
{
|
|
Log(LOG_DEBUG, L"Enumerating installed font families...");
|
|
CMeterString::EnumerateInstalledFontFamilies();
|
|
}
|
|
|
|
// Tray must exist before configs are read
|
|
m_TrayWindow = new CTrayWindow(m_Instance);
|
|
|
|
ScanForConfigs(m_SkinPath);
|
|
ScanForThemes(GetSettingsPath() + L"Themes");
|
|
|
|
if (m_ConfigStrings.empty())
|
|
{
|
|
std::wstring error = L"There are no available skins at:\n" + m_SkinPath;
|
|
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR);
|
|
}
|
|
|
|
ReadGeneralSettings(m_IniFile);
|
|
|
|
WritePrivateProfileString(L"Rainmeter", L"CheckUpdate", NULL , m_IniFile.c_str());
|
|
|
|
if (!m_DisableVersionCheck)
|
|
{
|
|
CheckUpdate();
|
|
}
|
|
|
|
ResetStats();
|
|
ReadStats();
|
|
|
|
// Change the work area if necessary
|
|
if (m_DesktopWorkAreaChanged)
|
|
{
|
|
UpdateDesktopWorkArea(false);
|
|
}
|
|
|
|
// If we're running as Litestep's plugin, register the !bangs
|
|
if (!c_DummyLitestep)
|
|
{
|
|
int Msgs[] = { LM_GETREVID, 0 };
|
|
// Register RevID message to Litestep
|
|
if (m_TrayWindow && m_TrayWindow->GetWindow()) ::SendMessage(GetLitestepWnd(), LM_REGISTERMESSAGE, (WPARAM)m_TrayWindow->GetWindow(), (LPARAM)Msgs);
|
|
|
|
AddBangCommand("!RainmeterRefresh", RainmeterRefresh);
|
|
AddBangCommand("!RainmeterRedraw", RainmeterRedraw);
|
|
AddBangCommand("!RainmeterUpdate", RainmeterUpdate);
|
|
AddBangCommand("!RainmeterHide", RainmeterHide);
|
|
AddBangCommand("!RainmeterShow", RainmeterShow);
|
|
AddBangCommand("!RainmeterToggle", RainmeterToggle);
|
|
AddBangCommand("!RainmeterHideFade", RainmeterHideFade);
|
|
AddBangCommand("!RainmeterShowFade", RainmeterShowFade);
|
|
AddBangCommand("!RainmeterToggleFade", RainmeterToggleFade);
|
|
AddBangCommand("!RainmeterHideBlur", RainmeterHideBlur);
|
|
AddBangCommand("!RainmeterShowBlur", RainmeterShowBlur);
|
|
AddBangCommand("!RainmeterToggleBlur", RainmeterToggleBlur);
|
|
AddBangCommand("!RainmeterAddBlur", RainmeterAddBlur);
|
|
AddBangCommand("!RainmeterRemoveBlur", RainmeterRemoveBlur);
|
|
AddBangCommand("!RainmeterHideMeter", RainmeterHideMeter);
|
|
AddBangCommand("!RainmeterShowMeter", RainmeterShowMeter);
|
|
AddBangCommand("!RainmeterToggleMeter", RainmeterToggleMeter);
|
|
AddBangCommand("!RainmeterMoveMeter", RainmeterMoveMeter);
|
|
AddBangCommand("!RainmeterUpdateMeter", RainmeterUpdateMeter);
|
|
AddBangCommand("!RainmeterDisableMeasure", RainmeterDisableMeasure);
|
|
AddBangCommand("!RainmeterEnableMeasure", RainmeterEnableMeasure);
|
|
AddBangCommand("!RainmeterToggleMeasure", RainmeterToggleMeasure);
|
|
AddBangCommand("!RainmeterUpdateMeasure", RainmeterUpdateMeasure);
|
|
AddBangCommand("!RainmeterActivateConfig", RainmeterActivateConfig);
|
|
AddBangCommand("!RainmeterDeactivateConfig", RainmeterDeactivateConfig);
|
|
AddBangCommand("!RainmeterToggleConfig", RainmeterToggleConfig);
|
|
AddBangCommand("!RainmeterMove", RainmeterMove);
|
|
AddBangCommand("!RainmeterZPos", RainmeterZPos);
|
|
AddBangCommand("!RainmeterClickThrough", RainmeterClickThrough);
|
|
AddBangCommand("!RainmeterDraggable", RainmeterDraggable);
|
|
AddBangCommand("!RainmeterSnapEdges", RainmeterSnapEdges);
|
|
AddBangCommand("!RainmeterKeepOnScreen", RainmeterKeepOnScreen);
|
|
AddBangCommand("!RainmeterSetTransparency", RainmeterSetTransparency);
|
|
AddBangCommand("!RainmeterSetVariable", RainmeterSetVariable);
|
|
|
|
AddBangCommand("!RainmeterRefreshGroup", RainmeterRefreshGroup);
|
|
AddBangCommand("!RainmeterRedrawGroup", RainmeterRedrawGroup);
|
|
AddBangCommand("!RainmeterUpdateGroup", RainmeterUpdateGroup);
|
|
AddBangCommand("!RainmeterHideGroup", RainmeterHideGroup);
|
|
AddBangCommand("!RainmeterShowGroup", RainmeterShowGroup);
|
|
AddBangCommand("!RainmeterToggleGroup", RainmeterToggleGroup);
|
|
AddBangCommand("!RainmeterHideFadeGroup", RainmeterHideFadeGroup);
|
|
AddBangCommand("!RainmeterShowFadeGroup", RainmeterShowFadeGroup);
|
|
AddBangCommand("!RainmeterToggleFadeGroup", RainmeterToggleFadeGroup);
|
|
AddBangCommand("!RainmeterHideMeterGroup", RainmeterHideMeterGroup);
|
|
AddBangCommand("!RainmeterShowMeterGroup", RainmeterShowMeterGroup);
|
|
AddBangCommand("!RainmeterToggleMeterGroup", RainmeterToggleMeterGroup);
|
|
AddBangCommand("!RainmeterUpdateMeterGroup", RainmeterUpdateMeterGroup);
|
|
AddBangCommand("!RainmeterDisableMeasureGroup", RainmeterDisableMeasureGroup);
|
|
AddBangCommand("!RainmeterEnableMeasureGroup", RainmeterEnableMeasureGroup);
|
|
AddBangCommand("!RainmeterToggleMeasureGroup", RainmeterToggleMeasureGroup);
|
|
AddBangCommand("!RainmeterUpdateMeasureGroup", RainmeterUpdateMeasureGroup);
|
|
AddBangCommand("!RainmeterDeactivateConfigGroup", RainmeterDeactivateConfigGroup);
|
|
AddBangCommand("!RainmeterZPosGroup", RainmeterZPosGroup);
|
|
AddBangCommand("!RainmeterClickThroughGroup", RainmeterClickThroughGroup);
|
|
AddBangCommand("!RainmeterDraggableGroup", RainmeterDraggableGroup);
|
|
AddBangCommand("!RainmeterSnapEdgesGroup", RainmeterSnapEdgesGroup);
|
|
AddBangCommand("!RainmeterKeepOnScreenGroup", RainmeterKeepOnScreenGroup);
|
|
AddBangCommand("!RainmeterSetTransparencyGroup", RainmeterSetTransparencyGroup);
|
|
AddBangCommand("!RainmeterSetVariableGroup", RainmeterSetVariableGroup);
|
|
|
|
AddBangCommand("!RainmeterRefreshApp", RainmeterRefreshApp);
|
|
AddBangCommand("!RainmeterLsBoxHook", RainmeterLsHook);
|
|
AddBangCommand("!RainmeterAbout", RainmeterAbout);
|
|
AddBangCommand("!RainmeterManage", RainmeterManage);
|
|
AddBangCommand("!RainmeterSkinMenu", RainmeterSkinMenu);
|
|
AddBangCommand("!RainmeterTrayMenu", RainmeterTrayMenu);
|
|
AddBangCommand("!RainmeterResetStats", RainmeterResetStats);
|
|
AddBangCommand("!RainmeterWriteKeyValue", RainmeterWriteKeyValue);
|
|
AddBangCommand("!RainmeterPluginBang", RainmeterPluginBang);
|
|
AddBangCommand("!RainmeterQuit", RainmeterQuit);
|
|
}
|
|
|
|
// Create meter windows for active configs
|
|
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
|
|
for ( ; iter != m_ConfigOrders.end(); ++iter)
|
|
{
|
|
const CONFIG& config = m_ConfigStrings[(*iter).second];
|
|
if (config.active > 0 && config.active <= (int)config.iniFiles.size())
|
|
{
|
|
ActivateConfig((*iter).second, config.active - 1);
|
|
}
|
|
}
|
|
|
|
return Result; // Alles OK
|
|
}
|
|
|
|
/*
|
|
** 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)
|
|
{
|
|
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());
|
|
}
|
|
}
|
|
|
|
void CRainmeter::ReloadSettings()
|
|
{
|
|
ScanForConfigs(m_SkinPath);
|
|
ScanForThemes(GetSettingsPath() + L"Themes");
|
|
ReadGeneralSettings(m_IniFile);
|
|
}
|
|
|
|
void CRainmeter::ActivateConfig(int configIndex, int iniIndex)
|
|
{
|
|
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size())
|
|
{
|
|
const std::wstring skinIniFile = m_ConfigStrings[configIndex].iniFiles[iniIndex];
|
|
const std::wstring skinConfig = m_ConfigStrings[configIndex].config;
|
|
const std::wstring& skinPath = m_SkinPath;
|
|
|
|
// Verify that the config is not already active
|
|
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_Meters.find(skinConfig);
|
|
if (iter != m_Meters.end())
|
|
{
|
|
if (((*iter).second)->GetSkinIniFile() == skinIniFile)
|
|
{
|
|
LogWithArgs(LOG_WARNING, L"MeterWindow \"%s\" is already active.", skinConfig.c_str());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Deactivate the existing config
|
|
DeactivateConfig((*iter).second, configIndex);
|
|
}
|
|
}
|
|
|
|
// Verify whether the ini-file exists
|
|
std::wstring skinIniPath = skinPath + skinConfig;
|
|
skinIniPath += L"\\";
|
|
skinIniPath += skinIniFile;
|
|
|
|
if (_waccess(skinIniPath.c_str(), 0) == -1)
|
|
{
|
|
std::wstring message = L"Unable to activate skin \"" + skinConfig;
|
|
message += L"\\";
|
|
message += skinIniFile;
|
|
message += L"\": Ini-file not found.";
|
|
Log(LOG_WARNING, message.c_str());
|
|
MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
return;
|
|
}
|
|
|
|
m_ConfigStrings[configIndex].active = iniIndex + 1;
|
|
WriteActive(skinConfig, iniIndex);
|
|
|
|
try
|
|
{
|
|
CreateMeterWindow(skinPath, skinConfig, skinIniFile);
|
|
}
|
|
catch(CError& error)
|
|
{
|
|
MessageBox(NULL, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CRainmeter::DeactivateConfig(CMeterWindow* meterWindow, int configIndex, bool save)
|
|
{
|
|
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size())
|
|
{
|
|
m_ConfigStrings[configIndex].active = 0; // Deactivate the config
|
|
}
|
|
else if (configIndex == -1 && meterWindow)
|
|
{
|
|
// Deactivate the config by using the meter window's config name
|
|
const std::wstring skinConfig = meterWindow->GetSkinName();
|
|
for (size_t i = 0, isize = m_ConfigStrings.size(); i < isize; ++i)
|
|
{
|
|
if (_wcsicmp(skinConfig.c_str(), m_ConfigStrings[i].config.c_str()) == 0)
|
|
{
|
|
m_ConfigStrings[i].active = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (meterWindow)
|
|
{
|
|
if (save)
|
|
{
|
|
// Disable the config in the ini-file
|
|
WriteActive(meterWindow->GetSkinName(), -1);
|
|
}
|
|
|
|
return DeleteMeterWindow(meterWindow, true);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CRainmeter::WriteActive(const std::wstring& config, int iniIndex)
|
|
{
|
|
WCHAR buffer[32];
|
|
_snwprintf_s(buffer, _TRUNCATE, L"%i", iniIndex + 1);
|
|
WritePrivateProfileString(config.c_str(), L"Active", buffer, m_IniFile.c_str());
|
|
}
|
|
|
|
void CRainmeter::CreateMeterWindow(const std::wstring& path, const std::wstring& config, const std::wstring& iniFile)
|
|
{
|
|
CMeterWindow* mw = new CMeterWindow(path, config, iniFile);
|
|
|
|
if (mw)
|
|
{
|
|
m_Meters[config] = mw;
|
|
mw->Initialize(*this);
|
|
|
|
CDialogAbout::UpdateSkins();
|
|
CDialogManage::UpdateSkins(mw);
|
|
}
|
|
}
|
|
|
|
void CRainmeter::ClearDeleteLaterList()
|
|
{
|
|
if (!m_DelayDeleteList.empty())
|
|
{
|
|
do
|
|
{
|
|
CMeterWindow* meterWindow = m_DelayDeleteList.front();
|
|
|
|
// Remove from the delete later list
|
|
m_DelayDeleteList.remove(meterWindow);
|
|
|
|
// Remove from the meter window list if it is still there
|
|
std::map<std::wstring, CMeterWindow*>::iterator iter = m_Meters.begin();
|
|
for (; iter != m_Meters.end(); ++iter)
|
|
{
|
|
if ((*iter).second == meterWindow)
|
|
{
|
|
m_Meters.erase(iter);
|
|
CDialogManage::UpdateSkins(meterWindow, true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete meterWindow;
|
|
}
|
|
while (!m_DelayDeleteList.empty());
|
|
|
|
|
|
CDialogManage::UpdateThemes();
|
|
CDialogAbout::UpdateSkins();
|
|
}
|
|
}
|
|
|
|
bool CRainmeter::DeleteMeterWindow(CMeterWindow* meterWindow, bool bLater)
|
|
{
|
|
if (bLater)
|
|
{
|
|
if (meterWindow)
|
|
{
|
|
m_DelayDeleteList.push_back(meterWindow);
|
|
meterWindow->RunBang(BANG_HIDEFADE, NULL); // Fade out the window
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (meterWindow)
|
|
{
|
|
m_DelayDeleteList.remove(meterWindow); // Remove the window from the delete later list if it is there
|
|
}
|
|
|
|
std::map<std::wstring, CMeterWindow*>::iterator iter = m_Meters.begin();
|
|
for (; iter != m_Meters.end(); ++iter)
|
|
{
|
|
if (meterWindow == NULL)
|
|
{
|
|
// Delete all meter windows
|
|
delete (*iter).second;
|
|
}
|
|
else if ((*iter).second == meterWindow)
|
|
{
|
|
m_Meters.erase(iter);
|
|
delete meterWindow;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (meterWindow == NULL)
|
|
{
|
|
m_Meters.clear();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CMeterWindow* CRainmeter::GetMeterWindow(const std::wstring& config)
|
|
{
|
|
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_Meters.begin();
|
|
for (; iter != m_Meters.end(); ++iter)
|
|
{
|
|
if (_wcsicmp((*iter).first.c_str(), config.c_str()) == 0)
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Added by Peter Souza IV / psouza4 / 2010.12.13
|
|
//
|
|
// Returns a CMeterWindow object given a config's INI path and filename. Since plugins
|
|
// get the full path and filename of an INI file on Initialize(), but not the name of
|
|
// the config, this is used to convert the INI filename to a config name.
|
|
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_Meters.begin();
|
|
for (; iter != m_Meters.end(); ++iter)
|
|
{
|
|
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;
|
|
}
|
|
|
|
CMeterWindow* CRainmeter::GetMeterWindow(HWND hwnd)
|
|
{
|
|
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_Meters.begin();
|
|
for (; iter != m_Meters.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_Meters.begin();
|
|
for (; iter != m_Meters.end(); ++iter)
|
|
{
|
|
CMeterWindow* mw = (*iter).second;
|
|
if (mw && (group.empty() || mw->BelongsToGroup(group)))
|
|
{
|
|
windows.insert(std::pair<int, CMeterWindow*>(GetLoadOrder((*iter).first), mw));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CRainmeter::SetLoadOrder(int configIndex, int order)
|
|
{
|
|
std::multimap<int, int>::iterator iter = m_ConfigOrders.begin();
|
|
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)
|
|
{
|
|
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
|
|
for ( ; iter != m_ConfigOrders.end(); ++iter)
|
|
{
|
|
if (m_ConfigStrings[(*iter).second].config == config)
|
|
{
|
|
return (*iter).first;
|
|
}
|
|
}
|
|
|
|
// LoadOrder not exists
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** Quit
|
|
**
|
|
** Called when the module quits
|
|
**
|
|
*/
|
|
void CRainmeter::Quit(HINSTANCE dllInst)
|
|
{
|
|
// If we're running as Litestep's plugin, unregister the !bangs
|
|
if (!c_DummyLitestep)
|
|
{
|
|
int Msgs[] = { LM_GETREVID, 0 };
|
|
// Unregister RevID message
|
|
if (m_TrayWindow && m_TrayWindow->GetWindow()) ::SendMessage(GetLitestepWnd(), LM_UNREGISTERMESSAGE, (WPARAM)m_TrayWindow->GetWindow(), (LPARAM)Msgs);
|
|
|
|
RemoveBangCommand("!RainmeterRefresh");
|
|
RemoveBangCommand("!RainmeterRedraw");
|
|
RemoveBangCommand("!RainmeterUpdate");
|
|
RemoveBangCommand("!RainmeterHide");
|
|
RemoveBangCommand("!RainmeterShow");
|
|
RemoveBangCommand("!RainmeterToggle");
|
|
RemoveBangCommand("!RainmeterHideFade");
|
|
RemoveBangCommand("!RainmeterShowFade");
|
|
RemoveBangCommand("!RainmeterToggleFade");
|
|
RemoveBangCommand("!RainmeterHideBlur");
|
|
RemoveBangCommand("!RainmeterShowBlur");
|
|
RemoveBangCommand("!RainmeterToggleBlur");
|
|
RemoveBangCommand("!RainmeterAddBlur");
|
|
RemoveBangCommand("!RainmeterRemoveBlur");
|
|
RemoveBangCommand("!RainmeterHideMeter");
|
|
RemoveBangCommand("!RainmeterShowMeter");
|
|
RemoveBangCommand("!RainmeterToggleMeter");
|
|
RemoveBangCommand("!RainmeterMoveMeter");
|
|
RemoveBangCommand("!RainmeterUpdateMeter");
|
|
RemoveBangCommand("!RainmeterHideMeasure");
|
|
RemoveBangCommand("!RainmeterShowMeasure");
|
|
RemoveBangCommand("!RainmeterToggleMeasure");
|
|
RemoveBangCommand("!RainmeterUpdateMeasure");
|
|
RemoveBangCommand("!RainmeterActivateConfig");
|
|
RemoveBangCommand("!RainmeterDeactivateConfig");
|
|
RemoveBangCommand("!RainmeterToggleConfig");
|
|
RemoveBangCommand("!RainmeterMove");
|
|
RemoveBangCommand("!RainmeterZPos");
|
|
RemoveBangCommand("!RainmeterClickThrough");
|
|
RemoveBangCommand("!RainmeterDraggable");
|
|
RemoveBangCommand("!RainmeterSnapEdges");
|
|
RemoveBangCommand("!RainmeterKeepOnScreen");
|
|
RemoveBangCommand("!RainmeterSetTransparency");
|
|
RemoveBangCommand("!RainmeterSetVariable");
|
|
|
|
RemoveBangCommand("!RainmeterRefreshGroup");
|
|
RemoveBangCommand("!RainmeterRedrawGroup");
|
|
RemoveBangCommand("!RainmeterUpdateGroup");
|
|
RemoveBangCommand("!RainmeterHideGroup");
|
|
RemoveBangCommand("!RainmeterShowGroup");
|
|
RemoveBangCommand("!RainmeterToggleGroup");
|
|
RemoveBangCommand("!RainmeterHideFadeGroup");
|
|
RemoveBangCommand("!RainmeterShowFadeGroup");
|
|
RemoveBangCommand("!RainmeterToggleFadeGroup");
|
|
RemoveBangCommand("!RainmeterHideMeterGroup");
|
|
RemoveBangCommand("!RainmeterShowMeterGroup");
|
|
RemoveBangCommand("!RainmeterToggleMeterGroup");
|
|
RemoveBangCommand("!RainmeterUpdateMeterGroup");
|
|
RemoveBangCommand("!RainmeterHideMeasureGroup");
|
|
RemoveBangCommand("!RainmeterShowMeasureGroup");
|
|
RemoveBangCommand("!RainmeterToggleMeasureGroup");
|
|
RemoveBangCommand("!RainmeterUpdateMeasureGroup");
|
|
RemoveBangCommand("!RainmeterDeactivateConfigGroup");
|
|
RemoveBangCommand("!RainmeterZPosGroup");
|
|
RemoveBangCommand("!RainmeterClickThroughGroup");
|
|
RemoveBangCommand("!RainmeterDraggableGroup");
|
|
RemoveBangCommand("!RainmeterSnapEdgesGroup");
|
|
RemoveBangCommand("!RainmeterKeepOnScreenGroup");
|
|
RemoveBangCommand("!RainmeterSetTransparencyGroup");
|
|
RemoveBangCommand("!RainmeterSetVariableGroup");
|
|
|
|
RemoveBangCommand("!RainmeterRefreshApp");
|
|
RemoveBangCommand("!RainmeterLsBoxHook");
|
|
RemoveBangCommand("!RainmeterAbout");
|
|
RemoveBangCommand("!RainmeterManage");
|
|
RemoveBangCommand("!RainmeterSkinMenu");
|
|
RemoveBangCommand("!RainmeterTrayMenu");
|
|
RemoveBangCommand("!RainmeterResetStats");
|
|
RemoveBangCommand("!RainmeterWriteKeyValue");
|
|
RemoveBangCommand("!RainmeterPluginBang");
|
|
RemoveBangCommand("!RainmeterQuit");
|
|
}
|
|
}
|
|
|
|
/*
|
|
** ScanForConfigs
|
|
**
|
|
** Scans all the subfolders and locates the ini-files.
|
|
*/
|
|
void CRainmeter::ScanForConfigs(const std::wstring& path)
|
|
{
|
|
m_ConfigStrings.clear();
|
|
m_ConfigMenu.clear();
|
|
m_ConfigOrders.clear();
|
|
|
|
ScanForConfigsRecursive(path, L"", 0, m_ConfigMenu, false);
|
|
}
|
|
|
|
int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector<CONFIGMENU>& menu, bool DontRecurse)
|
|
{
|
|
WIN32_FIND_DATA fileData; // Data structure describes the file found
|
|
HANDLE hSearch; // Search handle returned by FindFirstFile
|
|
std::list<std::wstring> folders;
|
|
const bool first = base.empty();
|
|
|
|
// 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)
|
|
{
|
|
CONFIG config;
|
|
config.config = base;
|
|
config.active = 0;
|
|
|
|
do
|
|
{
|
|
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (!(wcscmp(L"Backup", fileData.cFileName) == 0 && first) && // Skip the backup folder
|
|
wcscmp(L".", fileData.cFileName) != 0 &&
|
|
wcscmp(L"..", fileData.cFileName) != 0)
|
|
{
|
|
folders.push_back(fileData.cFileName);
|
|
}
|
|
}
|
|
else if (!first)
|
|
{
|
|
// Check whether the extension is ".ini"
|
|
size_t filenameLen = wcslen(fileData.cFileName);
|
|
if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0)
|
|
{
|
|
CONFIGMENU menuItem;
|
|
menuItem.name = fileData.cFileName;
|
|
menuItem.index = m_ConfigStrings.size();
|
|
menu.push_back(menuItem);
|
|
|
|
config.iniFiles.push_back(fileData.cFileName);
|
|
config.commands.push_back(ID_CONFIG_FIRST + index++);
|
|
}
|
|
}
|
|
} while (FindNextFile(hSearch, &fileData));
|
|
|
|
FindClose(hSearch);
|
|
|
|
if (!config.iniFiles.empty())
|
|
{
|
|
m_ConfigStrings.push_back(config);
|
|
}
|
|
}
|
|
|
|
if (!first)
|
|
{
|
|
base += L"\\";
|
|
}
|
|
|
|
std::list<std::wstring>::const_iterator iter = folders.begin();
|
|
for ( ; iter != folders.end(); ++iter)
|
|
{
|
|
CONFIGMENU menuItem;
|
|
menuItem.name = (*iter);
|
|
menuItem.index = -1;
|
|
menu.push_back(menuItem);
|
|
|
|
if (!DontRecurse)
|
|
{
|
|
std::vector<CONFIGMENU>::iterator iter2 = menu.end() - 1;
|
|
index = ScanForConfigsRecursive(path, base + (*iter), index, (*iter2).children, false);
|
|
|
|
// Remove menu item if it has no child
|
|
if ((*iter2).children.empty())
|
|
{
|
|
menu.erase(iter2);
|
|
}
|
|
}
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
/*
|
|
** 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
|
|
HANDLE hSearch; // Search handle returned by FindFirstFile
|
|
|
|
// Scan for folders
|
|
std::wstring folders = path + L"\\*";
|
|
|
|
hSearch = FindFirstFileEx(
|
|
folders.c_str(),
|
|
(CSystem::GetOSPlatform() >= OSPLATFORM_7) ? FindExInfoBasic : FindExInfoStandard,
|
|
&fileData,
|
|
FindExSearchNameMatch,
|
|
NULL,
|
|
0);
|
|
|
|
if (hSearch != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
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));
|
|
|
|
FindClose(hSearch);
|
|
}
|
|
}
|
|
|
|
BOOL CRainmeter::ExecuteBang(const std::wstring& bang, const std::wstring& arg, CMeterWindow* meterWindow)
|
|
{
|
|
// Skip "!Rainmeter" or "!"
|
|
LPCWSTR name = bang.c_str();
|
|
name += (_wcsnicmp(name, L"!Rainmeter", 10) == 0) ? 10 : 1;
|
|
|
|
if (_wcsicmp(name, L"Refresh") == 0)
|
|
{
|
|
BangWithArgs(BANG_REFRESH, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"RefreshApp") == 0)
|
|
{
|
|
RainmeterRefreshAppWide();
|
|
}
|
|
else if (_wcsicmp(name, L"Redraw") == 0)
|
|
{
|
|
BangWithArgs(BANG_REDRAW, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"Update") == 0)
|
|
{
|
|
BangWithArgs(BANG_UPDATE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"Hide") == 0)
|
|
{
|
|
BangWithArgs(BANG_HIDE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"Show") == 0)
|
|
{
|
|
BangWithArgs(BANG_SHOW, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"Toggle") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideFade") == 0)
|
|
{
|
|
BangWithArgs(BANG_HIDEFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowFade") == 0)
|
|
{
|
|
BangWithArgs(BANG_SHOWFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleFade") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideMeter") == 0)
|
|
{
|
|
BangWithArgs(BANG_HIDEMETER, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowMeter") == 0)
|
|
{
|
|
BangWithArgs(BANG_SHOWMETER, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleMeter") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMETER, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"MoveMeter") == 0)
|
|
{
|
|
BangWithArgs(BANG_MOVEMETER, arg.c_str(), 3);
|
|
}
|
|
else if (_wcsicmp(name, L"UpdateMeter") == 0)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMETER, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"DisableMeasure") == 0)
|
|
{
|
|
BangWithArgs(BANG_DISABLEMEASURE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"EnableMeasure") == 0)
|
|
{
|
|
BangWithArgs(BANG_ENABLEMEASURE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleMeasure") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMEASURE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"UpdateMeasure") == 0)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMEASURE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"CommandMeasure") == 0)
|
|
{
|
|
BangWithArgs(BANG_COMMANDMEASURE, arg.c_str(), 2);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowBlur") == 0)
|
|
{
|
|
BangWithArgs(BANG_SHOWBLUR, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideBlur") == 0)
|
|
{
|
|
BangWithArgs(BANG_HIDEBLUR, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleBlur") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEBLUR, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"AddBlur") == 0)
|
|
{
|
|
BangWithArgs(BANG_ADDBLUR, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"RemoveBlur") == 0)
|
|
{
|
|
BangWithArgs(BANG_REMOVEBLUR, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ActivateConfig") == 0)
|
|
{
|
|
RainmeterActivateConfigWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"DeactivateConfig") == 0)
|
|
{
|
|
RainmeterDeactivateConfigWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleConfig") == 0)
|
|
{
|
|
RainmeterToggleConfigWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"Move") == 0)
|
|
{
|
|
BangWithArgs(BANG_MOVE, arg.c_str(), 2);
|
|
}
|
|
else if (_wcsicmp(name, L"ZPos") == 0 || _wcsicmp(name, L"ChangeZPos") == 0) // For backwards compatibility
|
|
{
|
|
BangWithArgs(BANG_ZPOS, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ClickThrough") == 0)
|
|
{
|
|
BangWithArgs(BANG_CLICKTHROUGH, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"Draggable") == 0)
|
|
{
|
|
BangWithArgs(BANG_DRAGGABLE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SnapEdges") == 0)
|
|
{
|
|
BangWithArgs(BANG_SNAPEDGES, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"KeepOnScreen") == 0)
|
|
{
|
|
BangWithArgs(BANG_KEEPONSCREEN, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SetTransparency") == 0)
|
|
{
|
|
BangWithArgs(BANG_SETTRANSPARENCY, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SetVariable") == 0)
|
|
{
|
|
BangWithArgs(BANG_SETVARIABLE, arg.c_str(), 2);
|
|
}
|
|
else if (_wcsicmp(name, L"SetOption") == 0)
|
|
{
|
|
BangWithArgs(BANG_SETOPTION, arg.c_str(), 3);
|
|
}
|
|
else if (_wcsicmp(name, L"RefreshGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_REFRESH, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"UpdateGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_UPDATE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"RedrawGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_REDRAW, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_HIDE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_SHOW, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_TOGGLE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideFadeGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_HIDEFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowFadeGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_SHOWFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleFadeGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_TOGGLEFADE, arg.c_str(), 0);
|
|
}
|
|
else if (_wcsicmp(name, L"HideMeterGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_HIDEMETERGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ShowMeterGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_SHOWMETERGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleMeterGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMETERGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"UpdateMeterGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMETERGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"DisableMeasureGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_DISABLEMEASUREGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"EnableMeasureGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_ENABLEMEASUREGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ToggleMeasureGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_TOGGLEMEASUREGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"UpdateMeasureGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_UPDATEMEASUREGROUP, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"DeactivateConfigGroup") == 0)
|
|
{
|
|
RainmeterDeactivateConfigGroupWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"ZPosGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_ZPOS, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"ClickThroughGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_CLICKTHROUGH, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"DraggableGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_DRAGGABLE, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SnapEdgesGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_SNAPEDGES, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"KeepOnScreenGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_KEEPONSCREEN, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SetTransparencyGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_SETTRANSPARENCY, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"SetVariableGroup") == 0)
|
|
{
|
|
BangGroupWithArgs(BANG_SETVARIABLE, arg.c_str(), 2);
|
|
}
|
|
else if (_wcsicmp(name, L"SetOptionGroup") == 0)
|
|
{
|
|
BangWithArgs(BANG_SETOPTIONGROUP, arg.c_str(), 3);
|
|
}
|
|
else if (_wcsicmp(name, L"About") == 0)
|
|
{
|
|
RainmeterAboutWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"Manage") == 0)
|
|
{
|
|
RainmeterManageWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"SkinMenu") == 0)
|
|
{
|
|
RainmeterSkinMenuWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"TrayMenu") == 0)
|
|
{
|
|
RainmeterTrayMenuWide();
|
|
}
|
|
else if (_wcsicmp(name, L"ResetStats") == 0)
|
|
{
|
|
RainmeterResetStatsWide();
|
|
}
|
|
else if (_wcsicmp(name, L"WriteKeyValue") == 0)
|
|
{
|
|
RainmeterWriteKeyValueWide(arg.c_str());
|
|
}
|
|
else if (_wcsicmp(name, L"PluginBang") == 0)
|
|
{
|
|
BangWithArgs(BANG_PLUGIN, arg.c_str(), 1);
|
|
}
|
|
else if (_wcsicmp(name, L"LsBoxHook") == 0)
|
|
{
|
|
// Nothing to do here (this works only with Litestep)
|
|
}
|
|
else if (_wcsicmp(name, L"Quit") == 0)
|
|
{
|
|
RainmeterQuitWide();
|
|
}
|
|
else if (_wcsicmp(bang.c_str(), L"!Execute") == 0)
|
|
{
|
|
// Special case for multibang execution
|
|
std::wstring::size_type start = std::wstring::npos;
|
|
std::wstring::size_type end = std::wstring::npos;
|
|
int count = 0;
|
|
for (size_t i = 0, isize = arg.size(); i < isize; ++i)
|
|
{
|
|
if (arg[i] == L'[')
|
|
{
|
|
if (count == 0)
|
|
{
|
|
start = i;
|
|
}
|
|
++count;
|
|
}
|
|
else if (arg[i] == L']')
|
|
{
|
|
--count;
|
|
|
|
if (count == 0 && start != std::wstring::npos)
|
|
{
|
|
end = i;
|
|
|
|
std::wstring command = arg.substr(start + 1, end - (start + 1));
|
|
// trim leading whitespace
|
|
std::wstring::size_type notwhite = command.find_first_not_of(L" \t\r\n");
|
|
command.erase(0, notwhite);
|
|
ExecuteCommand(command.c_str(), meterWindow);
|
|
}
|
|
}
|
|
else if (isize > (i + 2) &&
|
|
arg[i] == L'"' && arg[i + 1] == L'"' && arg[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 "
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::wstring error = L"Unknown !bang: " + bang;
|
|
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
** ParseCommand
|
|
**
|
|
** Replaces the measure names with the actual text values.
|
|
**
|
|
*/
|
|
std::wstring CRainmeter::ParseCommand(const WCHAR* command, CMeterWindow* meterWindow)
|
|
{
|
|
std::wstring strCommand = command;
|
|
|
|
if (_wcsnicmp(L"!execute", command, 8) == 0)
|
|
{
|
|
return strCommand;
|
|
}
|
|
|
|
// Find the [measures]
|
|
size_t start = 0, end = 0;
|
|
while (start != std::wstring::npos && end != std::wstring::npos)
|
|
{
|
|
start = strCommand.find(L'[', start);
|
|
if (start != std::wstring::npos)
|
|
{
|
|
end = strCommand.find(L']', start + 1);
|
|
if (end != std::wstring::npos)
|
|
{
|
|
std::wstring measureName = strCommand.substr(start + 1, end - (start + 1));
|
|
if (!measureName.empty() && measureName[0] != L'!') // Ignore bangs
|
|
{
|
|
if (meterWindow)
|
|
{
|
|
if (strCommand[start + 1] == L'*' && strCommand[end - 1] == L'*')
|
|
{
|
|
strCommand.erase(start + 1, 1);
|
|
strCommand.erase(end - 2, 1);
|
|
start = end - 1;
|
|
}
|
|
else
|
|
{
|
|
const std::list<CMeasure*>& measures = meterWindow->GetMeasures();
|
|
std::list<CMeasure*>::const_iterator iter = measures.begin();
|
|
for ( ; iter != measures.end(); ++iter)
|
|
{
|
|
if (_wcsicmp((*iter)->GetName(), measureName.c_str()) == 0)
|
|
{
|
|
std::wstring value = (*iter)->GetStringValue(AUTOSCALE_OFF, 1, -1, false);
|
|
strCommand.replace(start, (end - start) + 1, value);
|
|
start += value.length();
|
|
break;
|
|
}
|
|
}
|
|
if (iter == measures.end())
|
|
{
|
|
//LogWithArgs(LOG_WARNING, L"No such measure [%s] for execute string: %s", measureName.c_str(), command);
|
|
start = end + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
start = end + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return strCommand;
|
|
}
|
|
|
|
/*
|
|
** ExecuteCommand
|
|
**
|
|
** Runs the given command or bang
|
|
**
|
|
*/
|
|
void CRainmeter::ExecuteCommand(const WCHAR* command, CMeterWindow* meterWindow)
|
|
{
|
|
if (command == NULL) return;
|
|
|
|
std::wstring strCommand = ParseCommand(command, meterWindow);
|
|
|
|
if (!strCommand.empty())
|
|
{
|
|
command = strCommand.c_str();
|
|
|
|
if (command[0] == L'!' && Rainmeter->GetDummyLitestep()) // Bangs
|
|
{
|
|
if (meterWindow)
|
|
{
|
|
// Fake WM_COPYDATA to deliver bangs
|
|
COPYDATASTRUCT cds;
|
|
cds.cbData = (DWORD)((wcslen(command) + 1) * sizeof(WCHAR));
|
|
cds.dwData = 1;
|
|
cds.lpData = (void*)command;
|
|
meterWindow->OnCopyData(WM_COPYDATA, NULL, (LPARAM)&cds);
|
|
}
|
|
else
|
|
{
|
|
std::wstring bang, arg;
|
|
size_t pos = strCommand.find(L' ');
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
bang.assign(strCommand, 0, pos);
|
|
strCommand.erase(0, pos + 1);
|
|
arg = strCommand;
|
|
}
|
|
else
|
|
{
|
|
bang = strCommand;
|
|
}
|
|
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')
|
|
{
|
|
strCommand = command;
|
|
|
|
// Strip the quotes
|
|
std::wstring::size_type len = strCommand.length();
|
|
if (len >= 2 && strCommand[0] == L'\"' && strCommand[len - 1] == L'\"')
|
|
{
|
|
len -= 2;
|
|
strCommand.assign(strCommand, 1, len);
|
|
}
|
|
|
|
PlaySound(strCommand.c_str(), NULL, flags);
|
|
}
|
|
return;
|
|
}
|
|
else if (_wcsnicmp(L"STOP", &command[4], 4) == 0) // PLAYSTOP
|
|
{
|
|
PlaySound(NULL, NULL, SND_PURGE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Run command
|
|
LSExecute(NULL, command, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** ReadGeneralSettings
|
|
**
|
|
** Reads the general settings from the Rainmeter.ini file
|
|
**
|
|
*/
|
|
void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile)
|
|
{
|
|
WCHAR buffer[MAX_PATH];
|
|
|
|
// Clear old settings
|
|
m_DesktopWorkAreas.clear();
|
|
|
|
CConfigParser parser;
|
|
parser.Initialize(iniFile.c_str(), this);
|
|
|
|
// Read Logging settings
|
|
m_Logging = 0!=parser.ReadInt(L"Rainmeter", L"Logging", 0);
|
|
c_Debug = 0!=parser.ReadInt(L"Rainmeter", L"Debug", 0);
|
|
|
|
if (m_Logging)
|
|
{
|
|
StartLogging();
|
|
}
|
|
|
|
if (m_TrayWindow)
|
|
{
|
|
m_TrayWindow->ReadConfig(parser);
|
|
}
|
|
|
|
c_GlobalConfig.netInSpeed = parser.ReadFloat(L"Rainmeter", L"NetInSpeed", 0.0);
|
|
c_GlobalConfig.netOutSpeed = parser.ReadFloat(L"Rainmeter", L"NetOutSpeed", 0.0);
|
|
|
|
m_DisableDragging = 0!=parser.ReadInt(L"Rainmeter", L"DisableDragging", 0);
|
|
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;
|
|
buffer[0] = L'\0';
|
|
|
|
HRESULT hr = AssocQueryString(ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, L".ini", L"open", buffer, &cchOut);
|
|
if (SUCCEEDED(hr) && cchOut > 0)
|
|
{
|
|
m_ConfigEditor = buffer;
|
|
}
|
|
else
|
|
{
|
|
m_ConfigEditor = L"Notepad";
|
|
}
|
|
}
|
|
if (!m_ConfigEditor.empty() && m_ConfigEditor[0] != L'\"')
|
|
{
|
|
m_ConfigEditor.insert(0, L"\"");
|
|
m_ConfigEditor.append(L"\"");
|
|
}
|
|
|
|
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;
|
|
buffer[0] = L'\0';
|
|
|
|
HRESULT hr = AssocQueryString(ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, L".log", L"open", buffer, &cchOut);
|
|
if (SUCCEEDED(hr) && cchOut > 0)
|
|
{
|
|
m_LogViewer = buffer;
|
|
}
|
|
else
|
|
{
|
|
m_LogViewer = L"Notepad";
|
|
}
|
|
}
|
|
if (!m_LogViewer.empty() && m_LogViewer[0] != L'\"')
|
|
{
|
|
m_LogViewer.insert(0, L"\"");
|
|
m_LogViewer.append(L"\"");
|
|
}
|
|
|
|
if (c_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);
|
|
|
|
std::wstring area = parser.ReadString(L"Rainmeter", L"DesktopWorkArea", L"");
|
|
if (!area.empty())
|
|
{
|
|
m_DesktopWorkAreas[0] = parser.ParseRECT(area.c_str());
|
|
m_DesktopWorkAreaChanged = true;
|
|
}
|
|
|
|
for (UINT i = 1; i <= CSystem::GetMonitorCount(); ++i)
|
|
{
|
|
_snwprintf_s(buffer, _TRUNCATE, L"DesktopWorkArea@%i", i);
|
|
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);
|
|
|
|
// Check which configs are active
|
|
if (!c_DummyLitestep)
|
|
{
|
|
char* tmpSz = new char[MAX_LINE_LENGTH];
|
|
std::wstring skinName;
|
|
std::wstring skinIni = L"Rainmeter.ini";
|
|
|
|
// Check if step.rc has overrides these values
|
|
if (GetRCString("RainmeterCurrentConfig", tmpSz, "", MAX_LINE_LENGTH - 1))
|
|
{
|
|
skinName = ConvertToWide(tmpSz);
|
|
}
|
|
|
|
if (GetRCString("RainmeterCurrentConfigIni", tmpSz, "Rainmeter.ini", MAX_LINE_LENGTH - 1))
|
|
{
|
|
skinIni = ConvertToWide(tmpSz);
|
|
}
|
|
|
|
delete [] tmpSz;
|
|
|
|
if (!skinName.empty())
|
|
{
|
|
if (!SetActiveConfig(skinName, skinIni))
|
|
{
|
|
std::wstring error = L"The selected skin (L" + skinName;
|
|
error += L"\\";
|
|
error += skinIni;
|
|
error += L") cannot be found.";
|
|
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
|
|
{
|
|
int active = parser.ReadInt(m_ConfigStrings[i].config.c_str(), L"Active", 0);
|
|
|
|
// Make sure there is a ini file available
|
|
if (active > 0 && active <= (int)m_ConfigStrings[i].iniFiles.size())
|
|
{
|
|
m_ConfigStrings[i].active = active;
|
|
}
|
|
|
|
int order;
|
|
if (parser.IsSectionDefined(m_ConfigStrings[i].config.c_str()))
|
|
{
|
|
std::wstring orderStr = parser.ReadString(m_ConfigStrings[i].config.c_str(), L"LoadOrder", L"", false);
|
|
if (orderStr.empty())
|
|
{
|
|
order = 0;
|
|
}
|
|
else if (_wcsicmp(orderStr.c_str(), L"LAST") == 0)
|
|
{
|
|
order = INT_MAX;
|
|
}
|
|
else if (_wcsicmp(orderStr.c_str(), L"FIRST") == 0)
|
|
{
|
|
order = INT_MIN;
|
|
}
|
|
else
|
|
{
|
|
order = _wtoi(orderStr.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
order = 0;
|
|
}
|
|
|
|
SetLoadOrder(i, order);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** SetActiveConfig
|
|
**
|
|
** Makes the given config active. If the config cannot be found this returns false.
|
|
*/
|
|
bool CRainmeter::SetActiveConfig(const std::wstring& skinName, const std::wstring& skinIni)
|
|
{
|
|
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
|
|
{
|
|
m_ConfigStrings[i].active = 0; // Disable all other configs
|
|
|
|
if (skinName == m_ConfigStrings[i].config)
|
|
{
|
|
for (int j = 0, jsize = (int)m_ConfigStrings[i].iniFiles.size(); j < jsize; ++j)
|
|
{
|
|
if (skinIni == m_ConfigStrings[i].iniFiles[j])
|
|
{
|
|
m_ConfigStrings[i].active = j + 1;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
** RefreshAll
|
|
**
|
|
** Refreshes all active meter windows.
|
|
** Note: This function calls CMeterWindow::Refresh() directly for synchronization. Be careful about crash.
|
|
**
|
|
*/
|
|
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
|
|
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;
|
|
std::wstring skinConfig = mw->GetSkinName();
|
|
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
|
|
{
|
|
if (_wcsicmp(skinConfig.c_str(), m_ConfigStrings[i].config.c_str()) == 0)
|
|
{
|
|
found = 1;
|
|
std::wstring skinIniFile = mw->GetSkinIniFile();
|
|
for (int j = 0, jsize = (int)m_ConfigStrings[i].iniFiles.size(); j < jsize; ++j)
|
|
{
|
|
if (_wcsicmp(skinIniFile.c_str(), m_ConfigStrings[i].iniFiles[j].c_str()) == 0)
|
|
{
|
|
found = 2;
|
|
if (m_ConfigStrings[i].active != j + 1)
|
|
{
|
|
// Switch to new ini-file order
|
|
m_ConfigStrings[i].active = j + 1;
|
|
WriteActive(skinConfig, j);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == 1) // Not found in ini-files
|
|
{
|
|
DeactivateConfig(mw, i);
|
|
|
|
std::wstring message = L"Unable to refresh skin \"" + skinConfig;
|
|
message += L"\\";
|
|
message += skinIniFile;
|
|
message += L"\": Ini-file not found.";
|
|
Log(LOG_WARNING, message.c_str());
|
|
MessageBox(NULL, message.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
|
|
|
|
std::wstring message = L"Unable to refresh config \"" + skinConfig;
|
|
message += L"\": Config not found.";
|
|
Log(LOG_WARNING, message.c_str());
|
|
MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
mw->Refresh(false, true);
|
|
}
|
|
catch (CError& error)
|
|
{
|
|
MessageBox(mw->GetWindow(), error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
}
|
|
|
|
CDialogManage::UpdateSkins(NULL);
|
|
}
|
|
|
|
/*
|
|
** 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 (c_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_NOTICE, 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 (c_Debug)
|
|
{
|
|
LogWithArgs(LOG_NOTICE, 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 (c_Debug)
|
|
{
|
|
std::wstring format = L"Applying DesktopWorkArea";
|
|
if (i != 0)
|
|
{
|
|
WCHAR buffer[64];
|
|
_snwprintf_s(buffer, _TRUNCATE, L"@%i", i);
|
|
format += buffer;
|
|
}
|
|
format += L": L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)";
|
|
if (!result)
|
|
{
|
|
format += L" => FAIL.";
|
|
}
|
|
LogWithArgs(LOG_NOTICE, 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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** ReadStats
|
|
**
|
|
** Reads the statistics from the ini-file
|
|
**
|
|
*/
|
|
void CRainmeter::ReadStats()
|
|
{
|
|
// If m_StatsFile doesn't exist, create it and copy the stats section from m_IniFile
|
|
if (_waccess(m_StatsFile.c_str(), 0) == -1)
|
|
{
|
|
WCHAR* tmpSz = new WCHAR[SHRT_MAX]; // Max size returned by GetPrivateProfileSection()
|
|
|
|
if (GetPrivateProfileSection(L"Statistics", tmpSz, SHRT_MAX, m_IniFile.c_str()) > 0)
|
|
{
|
|
WritePrivateProfileSection(L"Statistics", tmpSz, m_StatsFile.c_str());
|
|
WritePrivateProfileString(L"Statistics", NULL, NULL, m_IniFile.c_str());
|
|
}
|
|
|
|
delete [] tmpSz;
|
|
}
|
|
|
|
// Only Net measure has stats at the moment
|
|
CMeasureNet::ReadStats(m_StatsFile.c_str(), m_StatsDate);
|
|
}
|
|
|
|
/*
|
|
** WriteStats
|
|
**
|
|
** Writes the statistics to the ini-file. If bForce is false the stats are written only once per minute.
|
|
**
|
|
*/
|
|
void CRainmeter::WriteStats(bool bForce)
|
|
{
|
|
static ULONGLONG lastWrite = 0;
|
|
|
|
ULONGLONG ticks = CSystem::GetTickCount64();
|
|
|
|
if (bForce || (lastWrite + 1000 * 60 < ticks))
|
|
{
|
|
lastWrite = ticks;
|
|
|
|
// Only Net measure has stats at the moment
|
|
CMeasureNet::WriteStats(m_StatsFile.c_str(), m_StatsDate.c_str());
|
|
|
|
WritePrivateProfileString(NULL, NULL, NULL, m_StatsFile.c_str());
|
|
}
|
|
}
|
|
|
|
/*
|
|
** ResetStats
|
|
**
|
|
** Clears the statistics
|
|
**
|
|
*/
|
|
void CRainmeter::ResetStats()
|
|
{
|
|
// Set the stats-date string
|
|
struct tm *newtime;
|
|
time_t long_time;
|
|
time(&long_time);
|
|
newtime = localtime(&long_time);
|
|
m_StatsDate = _wasctime(newtime);
|
|
m_StatsDate.erase(m_StatsDate.size() - 1);
|
|
|
|
// Only Net measure has stats at the moment
|
|
CMeasureNet::ResetStats();
|
|
}
|
|
|
|
/*
|
|
** ShowContextMenu
|
|
**
|
|
** Opens the context menu in given coordinates.
|
|
**
|
|
*/
|
|
void CRainmeter::ShowContextMenu(POINT pos, CMeterWindow* meterWindow)
|
|
{
|
|
if (!m_MenuActive)
|
|
{
|
|
m_MenuActive = true;
|
|
|
|
// Show context menu, if no actions were executed
|
|
HMENU menu = LoadMenu(m_Instance, MAKEINTRESOURCE(IDR_CONTEXT_MENU));
|
|
|
|
if (menu)
|
|
{
|
|
HMENU subMenu = GetSubMenu(menu, 0);
|
|
if (subMenu)
|
|
{
|
|
SetMenuDefaultItem(subMenu, ID_CONTEXT_MANAGE, MF_BYCOMMAND);
|
|
|
|
if (!GetDummyLitestep())
|
|
{
|
|
// Disable Quit/Logging if ran as a Litestep plugin
|
|
EnableMenuItem(subMenu, ID_CONTEXT_QUIT, MF_BYCOMMAND | MF_GRAYED);
|
|
EnableMenuItem(subMenu, 10, MF_BYPOSITION | MF_GRAYED); // "Logging" menu
|
|
}
|
|
else
|
|
{
|
|
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 (c_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);
|
|
}
|
|
}
|
|
|
|
HMENU themeMenu = GetSubMenu(subMenu, 5);
|
|
if (themeMenu)
|
|
{
|
|
if (!m_Themes.empty())
|
|
{
|
|
DeleteMenu(themeMenu, 0, MF_BYPOSITION); // "No themes available" menuitem
|
|
CreateThemeMenu(themeMenu);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
// Create a menu for all active configs
|
|
std::map<std::wstring, CMeterWindow*>::const_iterator iter = Rainmeter->GetAllMeterWindows().begin();
|
|
|
|
int index = 0;
|
|
for (; iter != Rainmeter->GetAllMeterWindows().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)
|
|
{
|
|
InsertMenu(subMenu, 0, MF_BYPOSITION, ID_CONTEXT_NEW_VERSION, L"Update available");
|
|
HiliteMenuItem(Rainmeter->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,
|
|
TPM_RIGHTBUTTON | TPM_LEFTALIGN,
|
|
pos.x,
|
|
pos.y,
|
|
0,
|
|
hWnd,
|
|
NULL
|
|
);
|
|
|
|
if (meterWindow)
|
|
{
|
|
DestroyMenu(subMenu);
|
|
}
|
|
}
|
|
|
|
DestroyMenu(menu);
|
|
}
|
|
|
|
m_MenuActive = false;
|
|
}
|
|
}
|
|
|
|
HMENU CRainmeter::CreateConfigMenu(HMENU configMenu, std::vector<CONFIGMENU>& configMenuData)
|
|
{
|
|
if (!configMenuData.empty())
|
|
{
|
|
if (!configMenu)
|
|
{
|
|
configMenu = CreatePopupMenu();
|
|
}
|
|
|
|
bool separator = false;
|
|
for (int i = 0, j = 0, isize = (int)configMenuData.size(); i < isize; ++i)
|
|
{
|
|
if (configMenuData[i].index == -1)
|
|
{
|
|
HMENU submenu = CreateConfigMenu(NULL, configMenuData[i].children);
|
|
if (submenu)
|
|
{
|
|
if (separator)
|
|
{
|
|
// Insert a separator
|
|
InsertMenu(configMenu, i, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
|
++j;
|
|
separator = false;
|
|
}
|
|
InsertMenu(configMenu, i + j, MF_BYPOSITION | MF_POPUP, (UINT_PTR)submenu, configMenuData[i].name.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONFIG& config = m_ConfigStrings[configMenuData[i].index];
|
|
InsertMenu(configMenu, i, MF_BYPOSITION | ((config.active == i + 1) ? MF_CHECKED : MF_UNCHECKED), config.commands[i], configMenuData[i].name.c_str());
|
|
separator = true;
|
|
}
|
|
}
|
|
|
|
return configMenu;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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)
|
|
{
|
|
HMENU skinMenu = LoadMenu(m_Instance, MAKEINTRESOURCE(IDR_SKIN_MENU));
|
|
|
|
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)
|
|
{
|
|
HMENU posMenu = GetSubMenu(settingsMenu, 0);
|
|
if (posMenu)
|
|
{
|
|
switch (meterWindow->GetWindowZPosition())
|
|
{
|
|
case ZPOSITION_ONDESKTOP:
|
|
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_ONDESKTOP, MF_BYCOMMAND | MF_CHECKED);
|
|
break;
|
|
|
|
case ZPOSITION_ONBOTTOM:
|
|
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_BOTTOM, MF_BYCOMMAND | MF_CHECKED);
|
|
break;
|
|
|
|
case ZPOSITION_ONTOP:
|
|
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_TOPMOST, MF_BYCOMMAND | MF_CHECKED);
|
|
break;
|
|
|
|
case ZPOSITION_ONTOPMOST:
|
|
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_VERYTOPMOST, MF_BYCOMMAND | MF_CHECKED);
|
|
break;
|
|
|
|
default:
|
|
CheckMenuItem(posMenu, ID_CONTEXT_SKINMENU_NORMAL, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
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);
|
|
|
|
if (!c_DummyLitestep)
|
|
{
|
|
EnableMenuItem(posMenu, ID_CONTEXT_SKINMENU_ONDESKTOP, MF_BYCOMMAND | MF_GRAYED);
|
|
}
|
|
|
|
HMENU monitorMenu = GetSubMenu(posMenu, 0);
|
|
if (monitorMenu)
|
|
{
|
|
CreateMonitorMenu(monitorMenu, meterWindow);
|
|
}
|
|
}
|
|
|
|
// Tick the transparency
|
|
if (!meterWindow->GetNativeTransparency())
|
|
{
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
if (meterWindow->GetSnapEdges())
|
|
{
|
|
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
if (meterWindow->GetSavePosition())
|
|
{
|
|
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if (meterWindow->GetClickThrough())
|
|
{
|
|
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
if (meterWindow->GetKeepOnScreen())
|
|
{
|
|
CheckMenuItem(settingsMenu, ID_CONTEXT_SKINMENU_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Give the menuitem the unique id that depends on the skin
|
|
ChangeSkinIndex(skinMenu, index);
|
|
|
|
// Add the variants menu
|
|
if (variantsMenu)
|
|
{
|
|
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
|
|
{
|
|
const CONFIG& config = m_ConfigStrings[i];
|
|
if (_wcsicmp(config.config.c_str(), skinName.c_str()) == 0)
|
|
{
|
|
for (int j = 0, jsize = (int)config.iniFiles.size(); j < jsize; ++j)
|
|
{
|
|
InsertMenu(variantsMenu, j, MF_BYPOSITION | ((config.active == j + 1) ? MF_CHECKED : MF_UNCHECKED), config.commands[j], config.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];
|
|
if (GetMenuString(configMenu, i, buffer, MAX_PATH, MF_BYPOSITION))
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return skinMenu;
|
|
}
|
|
|
|
void CRainmeter::CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow)
|
|
{
|
|
bool screenDefined = meterWindow->GetXScreenDefined();
|
|
int screenIndex = meterWindow->GetXScreen();
|
|
|
|
// for the "Specified monitor" (@n)
|
|
if (CSystem::GetMonitorCount() > 0)
|
|
{
|
|
const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo();
|
|
const std::vector<MONITOR_INFO>& monitors = multimonInfo.monitors;
|
|
|
|
for (int i = 0, isize = (int)monitors.size(); i < isize; ++i)
|
|
{
|
|
WCHAR buffer[64];
|
|
_snwprintf_s(buffer, _TRUNCATE, L"@%i: ", i + 1);
|
|
std::wstring item = buffer;
|
|
|
|
size_t len = wcslen(monitors[i].monitorName);
|
|
if (len > 32)
|
|
{
|
|
item += std::wstring(monitors[i].monitorName, 32);
|
|
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());
|
|
}
|
|
}
|
|
|
|
// Tick the configs
|
|
if (!screenDefined)
|
|
{
|
|
CheckMenuItem(monitorMenu, ID_CONTEXT_SKINMENU_MONITOR_PRIMARY, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
if (screenDefined && screenIndex == 0)
|
|
{
|
|
CheckMenuItem(monitorMenu, ID_MONITOR_FIRST, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
|
|
if (meterWindow->GetAutoSelectScreen())
|
|
{
|
|
CheckMenuItem(monitorMenu, ID_CONTEXT_SKINMENU_MONITOR_AUTOSELECT, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
}
|
|
|
|
void CRainmeter::ChangeSkinIndex(HMENU menu, int index)
|
|
{
|
|
int count = GetMenuItemCount(menu);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
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);
|
|
ResetLoggingFlag(); // Re-enable logging
|
|
SetLogging(true);
|
|
|
|
std::wstring message = L"Log file created at: " + m_LogFile;
|
|
MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
|
|
}
|
|
else
|
|
{
|
|
// Disable logging
|
|
SetLogging(false);
|
|
ResetLoggingFlag();
|
|
|
|
std::wstring message = L"Unable to create log file: " + m_LogFile;
|
|
MessageBox(NULL, message.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)
|
|
{
|
|
std::wstring message = L"Do you want to delete the following log file?\n" + m_LogFile;
|
|
int res = MessageBox(NULL, message.c_str(), APPNAME, MB_YESNO | MB_TOPMOST | MB_ICONQUESTION);
|
|
if (res == IDYES)
|
|
{
|
|
// Disable logging
|
|
SetLogging(false);
|
|
ResetLoggingFlag();
|
|
|
|
CSystem::RemoveFile(m_LogFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CRainmeter::AddAboutLogInfo(int level, LPCWSTR time, LPCWSTR message)
|
|
{
|
|
// TODO: Store items in vector
|
|
|
|
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)
|
|
{
|
|
c_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)
|
|
{
|
|
WritePrivateProfileString(L"Rainmeter", L"WriteTest", L"TRUE", m_IniFile.c_str());
|
|
WritePrivateProfileString(NULL, NULL, NULL, m_IniFile.c_str()); // FLUSH
|
|
|
|
WCHAR tmpSz[5];
|
|
bool bSuccess = (GetPrivateProfileString(L"Rainmeter", L"WriteTest", L"", tmpSz, 5, m_IniFile.c_str()) > 0);
|
|
if (bSuccess)
|
|
{
|
|
bSuccess = (wcscmp(L"TRUE", tmpSz) == 0);
|
|
WritePrivateProfileString(L"Rainmeter", L"WriteTest", NULL, m_IniFile.c_str());
|
|
}
|
|
if (!bSuccess)
|
|
{
|
|
Log(LOG_WARNING, L"The Rainmeter.ini file is NOT writable.");
|
|
|
|
std::wstring error = L"The Rainmeter.ini file is not writable. This means that the\n"
|
|
L"application will not be able to save any settings permanently.\n\n";
|
|
|
|
if (!bDefaultIniLocation)
|
|
{
|
|
std::wstring strTarget = L"%APPDATA%\\Rainmeter\\";
|
|
ExpandEnvironmentVariables(strTarget);
|
|
|
|
error += L"You should quit Rainmeter and move the settings file from\n\n";
|
|
error += m_IniFile;
|
|
error += L"\n\nto\n\n";
|
|
error += strTarget;
|
|
error += L"\n\nAlternatively you can simply remove the file and\n"
|
|
L"it will be automatically recreated in the correct location\n"
|
|
L"when Rainmeter is restarted the next time (you\'ll lose your\n"
|
|
L"current settings though).\n";
|
|
}
|
|
else
|
|
{
|
|
error += L"Make sure that the settings file is not set as read-only and\n"
|
|
L"that it is located in a folder where you have write permissions.\n\n"
|
|
L"The settings file is located at:\n";
|
|
error += m_IniFile;
|
|
}
|
|
|
|
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_ICONERROR);
|
|
}
|
|
else
|
|
{
|
|
Log(LOG_NOTICE, L"The Rainmeter.ini file is writable.");
|
|
}
|
|
}
|
|
|
|
std::wstring CRainmeter::ExtractPath(const std::wstring& strFilePath)
|
|
{
|
|
std::wstring::size_type pos = strFilePath.find_last_of(L"\\/");
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
return strFilePath.substr(0, pos + 1);
|
|
}
|
|
return L".\\";
|
|
}
|
|
|
|
void CRainmeter::ExpandEnvironmentVariables(std::wstring& strPath)
|
|
{
|
|
if (strPath.find(L'%') != std::wstring::npos)
|
|
{
|
|
DWORD bufSize = 4096;
|
|
WCHAR* buffer = new WCHAR[bufSize]; // lets hope the buffer is large enough...
|
|
|
|
// %APPDATA% is a special case
|
|
std::wstring::size_type pos = strPath.find(L"%APPDATA%");
|
|
if (pos != std::wstring::npos)
|
|
{
|
|
HRESULT hr = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, buffer);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
std::wstring path = buffer;
|
|
do
|
|
{
|
|
strPath.replace(pos, 9, path);
|
|
}
|
|
while ((pos = strPath.find(L"%APPDATA%", pos + path.length())) != std::wstring::npos);
|
|
}
|
|
}
|
|
|
|
if (strPath.find(L'%') != std::wstring::npos)
|
|
{
|
|
// Expand the environment variables
|
|
DWORD ret = ExpandEnvironmentStrings(strPath.c_str(), buffer, bufSize);
|
|
if (ret != 0 && ret < bufSize)
|
|
{
|
|
strPath = buffer;
|
|
}
|
|
else
|
|
{
|
|
LogWithArgs(LOG_WARNING, L"Unable to expand the environment strings for string: %s", strPath.c_str());
|
|
}
|
|
}
|
|
|
|
delete [] buffer;
|
|
}
|
|
}
|