diff --git a/Library/CommandHandler.cpp b/Library/CommandHandler.cpp new file mode 100644 index 00000000..69a40ad6 --- /dev/null +++ b/Library/CommandHandler.cpp @@ -0,0 +1,938 @@ +/* + Copyright (C) 2013 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "StdAfx.h" +#include "CommandHandler.h" +#include "ConfigParser.h" +#include "DialogAbout.h" +#include "DialogManage.h" +#include "Measure.h" +#include "Logger.h" +#include "Rainmeter.h" +#include "System.h" +#include "TrayWindow.h" +#include "resource.h" + +extern CRainmeter* Rainmeter; + +namespace { + +typedef void (* BangHandlerFunc)(std::vector& args, CMeterWindow* skin); + +struct BangInfo +{ + Bang bang; + WCHAR* name; + uint8_t argCount; +}; + +struct CustomBangInfo +{ + Bang bang; + WCHAR* name; + BangHandlerFunc handlerFunc; +}; + +// Bangs that are to be handled with DoBang(). +const BangInfo s_Bangs[] = +{ + { Bang::Refresh, L"Refresh", 0 }, + { Bang::Redraw, L"Redraw", 0 }, + { Bang::Update, L"Update", 0 }, + { Bang::Hide, L"Hide", 0 }, + { Bang::Show, L"Show", 0 }, + { Bang::Toggle, L"Toggle", 0 }, + { Bang::HideFade, L"HideFade", 0 }, + { Bang::ShowFade, L"ShowFade", 0 }, + { Bang::ToggleFade, L"ToggleFade", 0 }, + { Bang::HideMeter, L"HideMeter", 1 }, + { Bang::ShowMeter, L"ShowMeter", 1 }, + { Bang::ToggleMeter, L"ToggleMeter", 1 }, + { Bang::MoveMeter, L"MoveMeter", 3 }, + { Bang::UpdateMeter, L"UpdateMeter", 1 }, + { Bang::DisableMeasure, L"DisableMeasure", 1 }, + { Bang::EnableMeasure, L"EnableMeasure", 1 }, + { Bang::ToggleMeasure, L"ToggleMeasure", 1 }, + { Bang::UpdateMeasure, L"UpdateMeasure", 1 }, + { Bang::CommandMeasure, L"CommandMeasure", 2 }, + { Bang::PluginBang, L"PluginBang", 1 }, + { Bang::ShowBlur, L"ShowBlur", 0 }, + { Bang::HideBlur, L"HideBlur", 0 }, + { Bang::ToggleBlur, L"ToggleBlur", 0 }, + { Bang::AddBlur, L"AddBlur", 1 }, + { Bang::RemoveBlur, L"RemoveBlur", 1 }, + { Bang::Move, L"Move", 2 }, + { Bang::ZPos, L"ZPos", 1 }, + { Bang::ZPos, L"ChangeZPos", 1 }, // For backwards compatibility. + { Bang::ChangeZPos, L"ChangeZPos", 1 }, + { Bang::ClickThrough, L"ClickThrough", 1 }, + { Bang::Draggable, L"Draggable", 1 }, + { Bang::SnapEdges, L"SnapEdges", 1 }, + { Bang::KeepOnScreen, L"KeepOnScreen", 1 }, + { Bang::SetTransparency, L"SetTransparency", 1 }, + { Bang::SetVariable, L"SetVariable", 2 }, + { Bang::SetOption, L"SetOption", 3 }, + { Bang::SetOptionGroup, L"SetOptionGroup", 3 }, + { Bang::HideMeterGroup, L"HideMeterGroup", 1 }, + { Bang::ShowMeterGroup, L"ShowMeterGroup", 1 }, + { Bang::ToggleMeterGroup, L"ToggleMeterGroup", 1 }, + { Bang::UpdateMeterGroup, L"UpdateMeterGroup", 1 }, + { Bang::DisableMeasureGroup, L"DisableMeasureGroup", 1 }, + { Bang::EnableMeasureGroup, L"EnableMeasureGroup", 1 }, + { Bang::ToggleMeasureGroup, L"ToggleMeasureGroup", 1 }, + { Bang::UpdateMeasureGroup, L"UpdateMeasureGroup", 1 } +}; + +// Bangs that are to be handled with DoGroupBang(). +const BangInfo s_GroupBangs[] = +{ + { Bang::RefreshGroup, L"RefreshGroup", 0 }, + { Bang::UpdateGroup, L"UpdateGroup", 0 }, + { Bang::RedrawGroup, L"RedrawGroup", 0 }, + { Bang::HideGroup, L"HideGroup", 0 }, + { Bang::ShowGroup, L"ShowGroup", 0 }, + { Bang::ToggleGroup, L"ToggleGroup", 0 }, + { Bang::HideFadeGroup, L"HideFadeGroup", 0 }, + { Bang::ShowFadeGroup, L"ShowFadeGroup", 0 }, + { Bang::ToggleFadeGroup, L"ToggleFadeGroup", 0 }, + { Bang::DeactivateConfigGroup, L"DeactivateConfigGroup" }, + { Bang::ZPosGroup, L"ZPosGroup", 1 }, + { Bang::ClickThroughGroup, L"ClickThroughGroup", 1 }, + { Bang::DraggableGroup, L"DraggableGroup", 1 }, + { Bang::SnapEdgesGroup, L"SnapEdgesGroup", 1 }, + { Bang::KeepOnScreenGroup, L"KeepOnScreenGroup", 1 }, + { Bang::SetTransparencyGroup, L"SetTransparencyGroup", 1 }, + { Bang::SetVariableGroup, L"SetVariableGroup", 2 } +}; + +// Bangs that are to be handled using a custom handler function. +const CustomBangInfo s_CustomBangs[] = +{ + { Bang::ActivateConfig, L"ActivateConfig", CCommandHandler::DoActivateSkinBang }, + { Bang::DeactivateConfig, L"DeactivateConfig", CCommandHandler::DoDeactivateSkinBang }, + { Bang::ToggleConfig, L"ToggleConfig", CCommandHandler::DoToggleSkinBang }, + { Bang::WriteKeyValue, L"WriteKeyValue", CCommandHandler::DoWriteKeyValueBang }, + { Bang::LoadLayout, L"LoadLayout", CCommandHandler::DoLoadLayoutBang }, + { Bang::SetClip, L"SetClip", CCommandHandler::DoSetClipBang }, + { Bang::SetWallpaper, L"SetWallpaper", CCommandHandler::DoSetWallpaperBang }, + { Bang::About, L"About", CCommandHandler::DoAboutBang }, + { Bang::Manage, L"Manage", CCommandHandler::DoManageBang }, + { Bang::SkinMenu, L"SkinMenu", CCommandHandler::DoSkinMenuBang }, + { Bang::TrayMenu, L"TrayMenu", CCommandHandler::DoTrayMenuBang }, + { Bang::ResetStats, L"ResetStats", CCommandHandler::DoResetStatsBang }, + { Bang::Log, L"Log", CCommandHandler::DoLogBang }, + { Bang::RefreshApp, L"RefreshApp", CCommandHandler::DoRefreshApp }, + { Bang::Quit, L"Quit", CCommandHandler::DoQuitBang }, + { Bang::LsBoxHook, L"LsBoxHook", CCommandHandler::DoLsBoxHookBang } +}; + +void DoBang(const BangInfo& bangInfo, std::vector& args, CMeterWindow* skin) +{ + const size_t argsCount = args.size(); + if (argsCount >= bangInfo.argCount) + { + if (argsCount == bangInfo.argCount && skin) + { + skin->DoBang(bangInfo.bang, args); + } + else + { + // Use the specified window instead of skin parameter. + if (argsCount > bangInfo.argCount) + { + const std::wstring& folderPath = args[bangInfo.argCount]; + if (!folderPath.empty() && (folderPath.length() != 1 || folderPath[0] != L'*')) + { + CMeterWindow* skin = Rainmeter->GetMeterWindow(folderPath); + if (skin) + { + skin->DoBang(bangInfo.bang, args); + } + else + { + LogErrorF(L"!%s: Skin \"%s\" not found", folderPath.c_str(), bangInfo.name); + } + return; + } + } + + // No skin defined -> apply to all. + for (const auto& ip : Rainmeter->GetAllMeterWindows()) + { + ip.second->DoBang(bangInfo.bang, args); + } + } + } + else + { + // For backwards compatibility. + if (bangInfo.bang == Bang::CommandMeasure && argsCount >= 1) + { + std::wstring& firstArg = args[0]; + std::wstring::size_type pos = firstArg.find_first_of(L' '); + if (pos != std::wstring::npos) + { + std::wstring newArg = firstArg.substr(0, pos); + firstArg.erase(0, pos + 1); + args.insert(args.begin(), newArg); + + LogWarningF(L"!%s: Two parameters required, only one given", bangInfo.name); + DoBang(bangInfo, args, skin); + return; + } + } + + LogErrorF(L"!%s: Incorrect number of arguments", bangInfo.name); + } +} + +void DoGroupBang(const BangInfo& bangInfo, std::vector& args, CMeterWindow* skin) +{ + if (args.size() > bangInfo.argCount) + { + std::multimap windows; + Rainmeter->GetMeterWindowsByLoadOrder(windows, args[bangInfo.argCount]); + + // Remove extra parameters (including group). + args.resize(bangInfo.argCount); + + std::multimap::const_iterator iter = windows.begin(); + for (const auto& ip : windows) + { + DoBang(bangInfo, args, ip.second); + } + } + else + { + LogErrorF(L"!%s: Incorrect number of arguments", bangInfo.name); + } +} + +} // namespace + +/* +** Parses and executes the given command. +** +*/ +void CCommandHandler::ExecuteCommand(const WCHAR* command, CMeterWindow* skin, bool multi) +{ + if (command[0] == L'!') // Bang + { + ++command; // Skip "!" + + if (_wcsnicmp(L"Execute", command, 7) == 0) + { + command += 7; + command = wcschr(command, L'['); + if (!command) return; + } + else + { + if (_wcsnicmp(command, L"Rainmeter", 9) == 0) + { + // Skip "Rainmeter" for backwards compatibility + command += 9; + } + + std::wstring bang; + std::vector args; + + // Find the first space + const WCHAR* pos = wcschr(command, L' '); + if (pos) + { + bang.assign(command, 0, pos - command); + args = ParseString(pos + 1, skin ? &skin->GetParser() : NULL); + } + else + { + bang = command; + } + + ExecuteBang(bang.c_str(), args, skin); + return; + } + } + + if (multi && command[0] == L'[') // Multi-bang + { + std::wstring bangs = command; + std::wstring::size_type start = std::wstring::npos; + int count = 0; + for (size_t i = 0, isize = bangs.size(); i < isize; ++i) + { + if (bangs[i] == L'[') + { + if (count == 0) + { + start = i; + } + ++count; + } + else if (bangs[i] == L']') + { + --count; + + if (count == 0 && start != std::wstring::npos) + { + // Change ] to NULL + bangs[i] = L'\0'; + + // Skip whitespace + start = bangs.find_first_not_of(L" \t\r\n", start + 1, 4); + + ExecuteCommand(bangs.c_str() + start, skin, false); + } + } + else if (bangs[i] == L'"' && isize > (i + 2) && bangs[i + 1] == L'"' && bangs[i + 2] == L'"') + { + i += 3; + + std::wstring::size_type pos = bangs.find(L"\"\"\"", i); + if (pos != std::wstring::npos) + { + i = pos + 2; // Skip "", loop will skip last " + } + } + } + } + else + { + // Check for built-ins + if (_wcsnicmp(L"PLAY", command, 4) == 0) + { + if (command[4] == L' ' || // PLAY + _wcsnicmp(L"LOOP ", &command[4], 5) == 0) // PLAYLOOP + { + command += 4; // Skip PLAY + + DWORD flags = SND_FILENAME | SND_ASYNC; + + if (command[0] != L' ') + { + flags |= SND_LOOP | SND_NODEFAULT; + command += 4; // Skip LOOP + } + + ++command; // Skip the space + if (command[0] != L'\0') + { + std::wstring sound = command; + + // Strip the quotes + std::wstring::size_type len = sound.length(); + if (len >= 2 && sound[0] == L'"' && sound[len - 1] == L'"') + { + len -= 2; + sound.assign(sound, 1, len); + } + + if (skin) + { + skin->GetParser().ReplaceMeasures(sound); + skin->MakePathAbsolute(sound); + } + + PlaySound(sound.c_str(), NULL, flags); + } + return; + } + else if (_wcsnicmp(L"STOP", &command[4], 4) == 0) // PLAYSTOP + { + PlaySound(NULL, NULL, SND_PURGE); + return; + } + } + + // Run command + std::wstring tmpSz = command; + if (skin) + { + skin->GetParser().ReplaceMeasures(tmpSz); + } + RunCommand(tmpSz); + } +} + +/* +** Runs the given bang. +** +*/ +void CCommandHandler::ExecuteBang(const WCHAR* name, std::vector& args, CMeterWindow* skin) +{ + for (const auto& bangInfo : s_Bangs) + { + if (_wcsicmp(bangInfo.name, name) == 0) + { + DoBang(bangInfo, args, skin); + return; + } + } + + for (const auto& bangInfo : s_GroupBangs) + { + if (_wcsicmp(bangInfo.name, name) == 0) + { + DoGroupBang(bangInfo, args, skin); + return; + } + } + + for (const auto& bangInfo : s_CustomBangs) + { + if (_wcsicmp(bangInfo.name, name) == 0) + { + bangInfo.handlerFunc(args, skin); + return; + } + } + + LogErrorF(L"Invalid bang: !%s", name); +} + +/* +** Parses and runs the given command. +** +*/ +void CCommandHandler::RunCommand(std::wstring command) +{ + std::wstring args; + + size_t notwhite = command.find_first_not_of(L" \t\r\n"); + command.erase(0, notwhite); + + size_t quotePos = command.find(L'"'); + if (quotePos == 0) + { + size_t quotePos2 = command.find(L'"', quotePos + 1); + if (quotePos2 != std::wstring::npos) + { + args.assign(command, quotePos2 + 1, command.length() - (quotePos2 + 1)); + command.assign(command, quotePos + 1, quotePos2 - quotePos - 1); + } + else + { + command.erase(0, 1); + } + } + else + { + size_t spacePos = command.find(L' '); + if (spacePos != std::wstring::npos) + { + args.assign(command, spacePos + 1, command.length() - (spacePos + 1)); + command.erase(spacePos); + } + } + + if (!command.empty()) + { + RunFile(command.c_str(), args.c_str()); + } +} + +/* +** Runs a file with the given arguments. +** +*/ +void CCommandHandler::RunFile(const WCHAR* file, const WCHAR* args) +{ + SHELLEXECUTEINFO si = {sizeof(SHELLEXECUTEINFO)}; + si.lpVerb = L"open"; + si.lpFile = file; + si.nShow = SW_SHOWNORMAL; + + DWORD type = GetFileAttributes(si.lpFile); + if (type & FILE_ATTRIBUTE_DIRECTORY && type != 0xFFFFFFFF) + { + ShellExecute(si.hwnd, si.lpVerb, si.lpFile, NULL, NULL, si.nShow); + } + else + { + std::wstring dir = CRainmeter::ExtractPath(file); + si.lpDirectory = dir.c_str(); + si.lpParameters = args; + si.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI; + ShellExecuteEx(&si); + } +} + +/* +** Splits strings into parts. +** +*/ +std::vector CCommandHandler::ParseString(LPCTSTR str, CConfigParser* parser) +{ + std::vector result; + + if (str) + { + std::wstring arg = str; + + // Split the argument between first space. + // Or if string is in quotes, the after the second quote. + + auto addResult = [&](std::wstring& string, bool stripQuotes) + { + if (stripQuotes) + { + size_t pos = 0; + do + { + pos = string.find(L'"', pos); + if (pos != std::wstring::npos) + { + string.erase(pos, 1); + } + } + while (pos != std::wstring::npos); + } + + if (parser) + { + parser->ReplaceMeasures(string); + } + + result.push_back(string); + }; + + size_t pos; + std::wstring newStr; + while ((pos = arg.find_first_not_of(L' ')) != std::wstring::npos) + { + size_t extra = 1; + 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); + + extra = 4; + if ((pos = arg.find(L"\"\"\" ")) == std::wstring::npos) + { + extra = 3; + pos = arg.rfind(L"\"\"\""); // search backward + } + } + 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 + extra); + + addResult(newStr, extra == 1); + } + else // quote or space not found + { + addResult(arg, extra == 1); + arg.clear(); + break; + } + } + + if (!arg.empty() && result.empty()) + { + addResult(arg, true); + } + } + + return result; +} + +void CCommandHandler::DoActivateSkinBang(std::vector& args, CMeterWindow* skin) +{ + if (args.size() == 1) + { + int index = Rainmeter->FindSkinFolderIndex(args[0]); + if (index != -1) + { + const CRainmeter::SkinFolder& skinFolder = Rainmeter->m_SkinFolders[index]; + if (!(skinFolder.active == 1 && skinFolder.files.size() == 1)) + { + // Activate the next index. + Rainmeter->ActivateSkin(index, (skinFolder.active < skinFolder.files.size()) ? skinFolder.active : 0); + } + return; + } + } + else if (args.size() > 1) + { + std::pair indexes = Rainmeter->GetMeterWindowIndex(args[0], args[1]); + if (indexes.first != -1 && indexes.second != -1) + { + Rainmeter->ActivateSkin(indexes.first, indexes.second); + return; + } + } + + LogError(L"!ActivateConfig: Invalid parameters"); +} + +void CCommandHandler::DoDeactivateSkinBang(std::vector& args, CMeterWindow* skin) +{ + if (!args.empty()) + { + skin = Rainmeter->GetMeterWindow(args[0]); + if (!skin) + { + LogWarningF(L"!DeactivateConfig: \"%s\" not active", args[0].c_str()); + return; + } + } + + if (skin) + { + Rainmeter->DeactivateSkin(skin, -1); + } + else + { + LogError(L"!DeactivateConfig: Invalid parameters"); + } +} + +void CCommandHandler::DoToggleSkinBang(std::vector& args, CMeterWindow* skin) +{ + if (args.size() >= 2) + { + CMeterWindow* skin = Rainmeter->GetMeterWindow(args[0]); + if (skin) + { + Rainmeter->DeactivateSkin(skin, -1); + return; + } + + // If the skin wasn't active, activate it. + DoActivateSkinBang(args, nullptr); + } + else + { + LogError(L"!ToggleConfig: Invalid parameters"); + } +} + +void CCommandHandler::DoDeactivateSkinGroupBang(std::vector& args, CMeterWindow* skin) +{ + if (!args.empty()) + { + std::multimap windows; + Rainmeter->GetMeterWindowsByLoadOrder(windows, args[0]); + for (const auto& ip : windows) + { + Rainmeter->DeactivateSkin(ip.second, -1); + } + } + else + { + LogError(L"!DeactivateConfigGroup: Invalid parameters"); + } +} + +void CCommandHandler::DoLoadLayoutBang(std::vector& args, CMeterWindow* skin) +{ + if (args.size() == 1) + { + if (skin) + { + // Delay to avoid loading theme in the middle of an update. + std::wstring command = L"!LoadLayout \""; + command += args[0]; + command += L'"'; + Rainmeter->DelayedExecuteCommand(command.c_str()); + } + else + { + // Not called from a skin (or called with delay). + Rainmeter->LoadLayout(args[0]); + } + } +} + +void CCommandHandler::DoSetClipBang(std::vector& args, CMeterWindow* skin) +{ + if (!args.empty()) + { + CSystem::SetClipboardText(args[0]); + } + else + { + LogError(L"!SetClip: Invalid parameter"); + } +} + +void CCommandHandler::DoSetWallpaperBang(std::vector& args, CMeterWindow* skin) +{ + const size_t argsSize = args.size(); + if (argsSize >= 1 && argsSize <= 2) + { + std::wstring& file = args[0]; + const std::wstring& style = (argsSize == 2) ? args[1] : L""; + + if (skin) + { + skin->MakePathAbsolute(file); + } + + CSystem::SetWallpaper(file, style); + } + else + { + LogError(L"!SetWallpaper: Invalid parameters"); + } +} + +void CCommandHandler::DoAboutBang(std::vector& args, CMeterWindow* meterWindow) +{ + CDialogAbout::Open(args.empty() ? L"" : args[0].c_str()); +} + +void CCommandHandler::DoManageBang(std::vector& args, CMeterWindow* meterWindow) +{ + CDialogManage::Open(args.empty() ? L"" : args[0].c_str()); +} + +void CCommandHandler::DoSkinMenuBang(std::vector& args, CMeterWindow* skin) +{ + if (!args.empty()) + { + skin = Rainmeter->GetMeterWindow(args[0]); + if (!skin) + { + LogWarningF(L"!SkinMenu: \"%s\" not active", args[0].c_str()); + return; + } + } + + if (skin) + { + POINT pos = CSystem::GetCursorPosition(); + Rainmeter->ShowContextMenu(pos, skin); + } + else + { + LogError(L"!SkinMenu: Invalid parameter"); + } +} + +void CCommandHandler::DoTrayMenuBang(std::vector& args, CMeterWindow* skin) +{ + POINT pos = CSystem::GetCursorPosition(); + Rainmeter->ShowContextMenu(pos, NULL); +} + +void CCommandHandler::DoResetStatsBang(std::vector& args, CMeterWindow* meterWindow) +{ + Rainmeter->ResetStats(); +} + +void CCommandHandler::DoWriteKeyValueBang(std::vector& args, CMeterWindow* skin) +{ + if (args.size() == 3 && skin) + { + // Add the skin file path to the args + args.push_back(skin->GetFilePath()); + } + else if (args.size() < 4) + { + LogError(L"!WriteKeyValue: Invalid parameters"); + return; + } + + std::wstring& strIniFile = args[3]; + if (skin) + { + skin->MakePathAbsolute(strIniFile); + } + + const WCHAR* iniFile = strIniFile.c_str(); + + if (strIniFile.find(L"..\\") != std::wstring::npos || strIniFile.find(L"../") != std::wstring::npos) + { + LogErrorF(L"!WriteKeyValue: Illegal path: %s", iniFile); + return; + } + + if (_wcsnicmp(iniFile, Rainmeter->m_SkinPath.c_str(), Rainmeter->m_SkinPath.size()) != 0 && + _wcsnicmp(iniFile, Rainmeter->m_SettingsPath.c_str(), Rainmeter->m_SettingsPath.size()) != 0) + { + LogErrorF(L"!WriteKeyValue: Illegal path: %s", iniFile); + return; + } + + // Verify whether the file exists. + if (_waccess(iniFile, 0) == -1) + { + LogErrorF(L"!WriteKeyValue: File not found: %s", iniFile); + return; + } + + // Verify whether the file is read-only. + DWORD attr = GetFileAttributes(iniFile); + if (attr == -1 || (attr & FILE_ATTRIBUTE_READONLY)) + { + LogWarningF(L"!WriteKeyValue: File is read-only: %s", iniFile); + return; + } + + // Avoid "IniFileMapping" + CSystem::UpdateIniFileMappingList(); + std::wstring strIniWrite = CSystem::GetTemporaryFile(strIniFile); + if (strIniWrite.size() == 1 && strIniWrite[0] == L'?') // error occurred + { + return; + } + + bool temporary = !strIniWrite.empty(); + + if (temporary) + { + if (Rainmeter->GetDebug()) + { + LogDebugF(L"!WriteKeyValue: Writing to: %s (Temp: %s)", iniFile, strIniWrite.c_str()); + } + } + else + { + if (Rainmeter->GetDebug()) + { + LogDebugF(L"!WriteKeyValue: Writing to: %s", iniFile); + } + strIniWrite = strIniFile; + } + + const WCHAR* iniWrite = strIniWrite.c_str(); + const WCHAR* section = args[0].c_str(); + const WCHAR* key = args[1].c_str(); + const std::wstring& strValue = args[2]; + + bool formula = false; + BOOL write = 0; + + if (skin) + { + double value; + if (skin->GetParser().ParseFormula(strValue, &value)) + { + WCHAR buffer[256]; + int len = _snwprintf_s(buffer, _TRUNCATE, L"%.5f", value); + CMeasure::RemoveTrailingZero(buffer, len); + + write = WritePrivateProfileString(section, key, buffer, iniWrite); + } + } + + if (!formula) + { + write = WritePrivateProfileString(section, key, strValue.c_str(), iniWrite); + } + + if (temporary) + { + if (write != 0) + { + WritePrivateProfileString(NULL, NULL, NULL, iniWrite); // FLUSH + + // Copy the file back. + if (!CSystem::CopyFiles(strIniWrite, strIniFile)) + { + LogErrorF(L"!WriteKeyValue: Failed to copy temporary file to original filepath: %s (Temp: %s)", iniFile, iniWrite); + } + } + else // failed + { + LogErrorF(L"!WriteKeyValue: Failed to write to: %s (Temp: %s)", iniFile, iniWrite); + } + + // Remove the temporary file. + CSystem::RemoveFile(strIniWrite); + } + else + { + if (write == 0) // failed + { + LogErrorF(L"!WriteKeyValue: Failed to write to: %s", iniFile); + } + } +} + +void CCommandHandler::DoLogBang(std::vector& args, CMeterWindow* skin) +{ + if (!args.empty()) + { + CLogger::Level level = CLogger::Level::Notice; + if (args.size() > 1) + { + const WCHAR* type = args[1].c_str(); + if (_wcsicmp(type, L"ERROR") == 0) + { + level = CLogger::Level::Error; + } + else if (_wcsicmp(type, L"WARNING") == 0) + { + level = CLogger::Level::Warning; + } + else if (_wcsicmp(type, L"DEBUG") == 0) + { + level = CLogger::Level::Debug; + } + else if (_wcsicmp(type, L"NOTICE") != 0) + { + LogError(L"!Log: Invalid type"); + return; + } + } + + CLogger::GetInstance().Log(level, args[0].c_str()); + } +} + +void CCommandHandler::DoRefreshApp(std::vector& args, CMeterWindow* meterWindow) +{ + // Refresh needs to be delayed since it crashes if done during Update(). + PostMessage(Rainmeter->m_Window, WM_RAINMETER_DELAYED_REFRESH_ALL, NULL, NULL); +} + +void CCommandHandler::DoQuitBang(std::vector& args, CMeterWindow* meterWindow) +{ + // Quit needs to be delayed since it crashes if done during Update(). + PostMessage(Rainmeter->GetTrayWindow()->GetWindow(), WM_COMMAND, MAKEWPARAM(IDM_QUIT, 0), NULL); +} + +void CCommandHandler::DoLsBoxHookBang(std::vector& args, CMeterWindow* meterWindow) +{ + // Deprecated. +} diff --git a/Library/CommandHandler.h b/Library/CommandHandler.h new file mode 100644 index 00000000..237c6ddc --- /dev/null +++ b/Library/CommandHandler.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2012 Rainmeter Team + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef RM_LIBRARY_COMMANDHANDLER_H_ +#define RM_LIBRARY_COMMANDHANDLER_H_ + +#include +#include +#include + +class CConfigParser; +class CMeterWindow; + +enum class Bang +{ + Refresh, + RefreshApp, + Redraw, + Update, + Hide, + Show, + Toggle, + HideFade, + ShowFade, + ToggleFade, + HideMeter, + ShowMeter, + ToggleMeter, + MoveMeter, + UpdateMeter, + DisableMeasure, + EnableMeasure, + ToggleMeasure, + UpdateMeasure, + CommandMeasure, + PluginBang, + ShowBlur, + HideBlur, + ToggleBlur, + AddBlur, + RemoveBlur, + ActivateConfig, + DeactivateConfig, + ToggleConfig, + Move, + ZPos, + ChangeZPos, + ClickThrough, + Draggable, + SnapEdges, + KeepOnScreen, + SetTransparency, + SetVariable, + SetOption, + RefreshGroup, + UpdateGroup, + RedrawGroup, + HideGroup, + ShowGroup, + ToggleGroup, + HideFadeGroup, + ShowFadeGroup, + ToggleFadeGroup, + HideMeterGroup, + ShowMeterGroup, + ToggleMeterGroup, + UpdateMeterGroup, + DisableMeasureGroup, + EnableMeasureGroup, + ToggleMeasureGroup, + UpdateMeasureGroup, + DeactivateConfigGroup, + ZPosGroup, + ClickThroughGroup, + DraggableGroup, + SnapEdgesGroup, + KeepOnScreenGroup, + SetTransparencyGroup, + SetVariableGroup, + SetOptionGroup, + WriteKeyValue, + LoadLayout, + SetClip, + SetWallpaper, + About, + Manage, + SkinMenu, + TrayMenu, + ResetStats, + Log, + Quit, + LsBoxHook +}; + +// Parses and executes commands and bangs. +class CCommandHandler +{ +public: + void ExecuteCommand(const WCHAR* command, CMeterWindow* skin, bool multi = true); + void ExecuteBang(const WCHAR* name, std::vector& args, CMeterWindow* skin); + + static void RunCommand(std::wstring command); + static void RunFile(const WCHAR* file, const WCHAR* args = NULL); + + static std::vector ParseString(const WCHAR* str, CConfigParser* parser = NULL); + + static void DoActivateSkinBang(std::vector& args, CMeterWindow* skin); + static void DoDeactivateSkinBang(std::vector& args, CMeterWindow* skin); + static void DoToggleSkinBang(std::vector& args, CMeterWindow* skin); + static void DoDeactivateSkinGroupBang(std::vector& args, CMeterWindow* skin); + static void DoLoadLayoutBang(std::vector& args, CMeterWindow* meterWindow); + static void DoSetClipBang(std::vector& args, CMeterWindow* skin); + static void DoSetWallpaperBang(std::vector& args, CMeterWindow* meterWindow); + static void DoAboutBang(std::vector& args, CMeterWindow* meterWindow); + static void DoManageBang(std::vector& args, CMeterWindow* meterWindow); + static void DoSkinMenuBang(std::vector& args, CMeterWindow* meterWindow); + static void DoTrayMenuBang(std::vector& args, CMeterWindow* meterWindow); + static void DoResetStatsBang(std::vector& args, CMeterWindow* meterWindow); + static void DoWriteKeyValueBang(std::vector& args, CMeterWindow* meterWindow); + static void DoLogBang(std::vector& args, CMeterWindow* meterWindow); + static void DoRefreshApp(std::vector& args, CMeterWindow* skin); + static void DoQuitBang(std::vector& args, CMeterWindow* meterWindow); + static void DoLsBoxHookBang(std::vector& args, CMeterWindow* meterWindow); +}; + +#endif diff --git a/Library/DialogAbout.cpp b/Library/DialogAbout.cpp index 57911e6a..c9e7c5eb 100644 --- a/Library/DialogAbout.cpp +++ b/Library/DialogAbout.cpp @@ -1252,11 +1252,11 @@ INT_PTR CDialogAbout::CTabVersion::OnNotify(WPARAM wParam, LPARAM lParam) case NM_CLICK: if (nm->idFrom == Id_HomeLink) { - RunFile(L"http://rainmeter.net"); + CCommandHandler::RunFile(L"http://rainmeter.net"); } else if (nm->idFrom == Id_HomeLink) { - RunFile(L"http://gnu.org/licenses"); + CCommandHandler::RunFile(L"http://gnu.org/licenses"); } break; diff --git a/Library/DialogAbout.h b/Library/DialogAbout.h index a244caf3..2f8b779c 100644 --- a/Library/DialogAbout.h +++ b/Library/DialogAbout.h @@ -20,6 +20,8 @@ #define __DIALOGABOUT_H__ #include "../Common/Dialog.h" +#include "Logger.h" +#include "MeterWindow.h" class CDialogAbout : public CDialog { diff --git a/Library/DialogManage.cpp b/Library/DialogManage.cpp index 2bbdfd6c..03a11627 100644 --- a/Library/DialogManage.cpp +++ b/Library/DialogManage.cpp @@ -1041,7 +1041,7 @@ INT_PTR CDialogManage::CTabSkins::OnCommand(WPARAM wParam, LPARAM lParam) case Id_CreateSkinPackageButton: { std::wstring file = Rainmeter->GetPath() + L"SkinInstaller.exe"; - RunFile(file.c_str(), L"/Packager"); + CCommandHandler::RunFile(file.c_str(), L"/Packager"); } break; @@ -1733,7 +1733,7 @@ INT_PTR CDialogManage::CTabLayouts::OnCommand(WPARAM wParam, LPARAM lParam) args += layouts[sel]; args += L"\\Rainmeter.ini"; args += L'"'; - RunFile(Rainmeter->GetSkinEditor().c_str(), args.c_str()); + CCommandHandler::RunFile(Rainmeter->GetSkinEditor().c_str(), args.c_str()); } break; diff --git a/Library/Export.cpp b/Library/Export.cpp index a34babe1..8c622adb 100644 --- a/Library/Export.cpp +++ b/Library/Export.cpp @@ -161,7 +161,7 @@ LPCWSTR PluginBridge(LPCWSTR command, LPCWSTR data) } else if (_wcsicmp(command, L"GetWindow") == 0) { - std::vector subStrings = CRainmeter::ParseString(data); + std::vector subStrings = CCommandHandler::ParseString(data); if (subStrings.size() >= 1) { @@ -181,7 +181,7 @@ LPCWSTR PluginBridge(LPCWSTR command, LPCWSTR data) } else if (_wcsicmp(command, L"GetVariable") == 0) { - std::vector subStrings = CRainmeter::ParseString(data); + std::vector subStrings = CCommandHandler::ParseString(data); if (subStrings.size() >= 2) { @@ -204,7 +204,7 @@ LPCWSTR PluginBridge(LPCWSTR command, LPCWSTR data) } else if (_wcsicmp(command, L"SetVariable") == 0) { - std::vector subStrings = CRainmeter::ParseString(data); + std::vector subStrings = CCommandHandler::ParseString(data); if (subStrings.size() == 3) { diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 0bd18030..402f2719 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -84,6 +84,9 @@ + + Use + Use @@ -312,6 +315,7 @@ + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index 961e53d7..8cb14987 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -393,6 +393,9 @@ Source Files + + Source Files + @@ -686,6 +689,9 @@ Header Files + + Header Files + diff --git a/Library/Litestep.cpp b/Library/Litestep.cpp index ddd8f01a..65c3315b 100644 --- a/Library/Litestep.cpp +++ b/Library/Litestep.cpp @@ -30,65 +30,6 @@ UINT GetUniqueID() return id++; } -void RunCommand(std::wstring command) -{ - std::wstring args; - - size_t notwhite = command.find_first_not_of(L" \t\r\n"); - command.erase(0, notwhite); - - size_t quotePos = command.find(L'"'); - if (quotePos == 0) - { - size_t quotePos2 = command.find(L'"', quotePos + 1); - if (quotePos2 != std::wstring::npos) - { - args.assign(command, quotePos2 + 1, command.length() - (quotePos2 + 1)); - command.assign(command, quotePos + 1, quotePos2 - quotePos - 1); - } - else - { - command.erase(0, 1); - } - } - else - { - size_t spacePos = command.find(L' '); - if (spacePos != std::wstring::npos) - { - args.assign(command, spacePos + 1, command.length() - (spacePos + 1)); - command.erase(spacePos); - } - } - - if (!command.empty()) - { - RunFile(command.c_str(), args.c_str()); - } -} - -void RunFile(const WCHAR* file, const WCHAR* args) -{ - SHELLEXECUTEINFO si = {sizeof(SHELLEXECUTEINFO)}; - si.lpVerb = L"open"; - si.lpFile = file; - si.nShow = SW_SHOWNORMAL; - - DWORD type = GetFileAttributes(si.lpFile); - if (type & FILE_ATTRIBUTE_DIRECTORY && type != 0xFFFFFFFF) - { - ShellExecute(si.hwnd, si.lpVerb, si.lpFile, NULL, NULL, si.nShow); - } - else - { - std::wstring dir = CRainmeter::ExtractPath(file); - si.lpDirectory = dir.c_str(); - si.lpParameters = args; - si.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI; - ShellExecuteEx(&si); - } -} - WCHAR* GetString(UINT id) { LPWSTR pData; diff --git a/Library/Litestep.h b/Library/Litestep.h index c4b42879..c0aa2466 100644 --- a/Library/Litestep.h +++ b/Library/Litestep.h @@ -30,9 +30,6 @@ UINT GetUniqueID(); template UINT TypeID() { static UINT id = GetUniqueID(); return id; } -void RunCommand(std::wstring command); -void RunFile(const WCHAR* file, const WCHAR* args = NULL); - WCHAR* GetString(UINT id); std::wstring GetFormattedString(UINT id, ...); diff --git a/Library/MeterWindow.cpp b/Library/MeterWindow.cpp index 68dfa9d4..95af5351 100644 --- a/Library/MeterWindow.cpp +++ b/Library/MeterWindow.cpp @@ -706,20 +706,20 @@ void CMeterWindow::ChangeSingleZPos(ZPOSITION zPos, bool all) ** Runs the bang command with the given arguments. ** Correct number of arguments must be passed (or use CRainmeter::ExecuteBang). */ -void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& args) +void CMeterWindow::DoBang(Bang bang, const std::vector& args) { switch (bang) { - case BANG_REFRESH: + case Bang::Refresh: // Refresh needs to be delayed since it crashes if done during Update() PostMessage(m_Window, WM_METERWINDOW_DELAYED_REFRESH, (WPARAM)NULL, (LPARAM)NULL); break; - case BANG_REDRAW: + case Bang::Redraw: Redraw(); break; - case BANG_UPDATE: + case Bang::Update: KillTimer(m_Window, TIMER_METER); // Kill timer temporarily Update(false); if (m_WindowUpdate >= 0) @@ -728,122 +728,122 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_SHOWBLUR: + case Bang::ShowBlur: ShowBlur(); break; - case BANG_HIDEBLUR: + case Bang::HideBlur: HideBlur(); break; - case BANG_TOGGLEBLUR: - RunBang(IsBlur() ? BANG_HIDEBLUR : BANG_SHOWBLUR, args); + case Bang::ToggleBlur: + DoBang(IsBlur() ? Bang::HideBlur : Bang::ShowBlur, args); break; - case BANG_ADDBLUR: + case Bang::AddBlur: ResizeBlur(args[0], RGN_OR); if (IsBlur()) ShowBlur(); break; - case BANG_REMOVEBLUR: + case Bang::RemoveBlur: ResizeBlur(args[0], RGN_DIFF); if (IsBlur()) ShowBlur(); break; - case BANG_TOGGLEMETER: + case Bang::ToggleMeter: ToggleMeter(args[0]); break; - case BANG_SHOWMETER: + case Bang::ShowMeter: ShowMeter(args[0]); break; - case BANG_HIDEMETER: + case Bang::HideMeter: HideMeter(args[0]); break; - case BANG_UPDATEMETER: + case Bang::UpdateMeter: UpdateMeter(args[0]); break; - case BANG_TOGGLEMETERGROUP: + case Bang::ToggleMeterGroup: ToggleMeter(args[0], true); break; - case BANG_SHOWMETERGROUP: + case Bang::ShowMeterGroup: ShowMeter(args[0], true); break; - case BANG_HIDEMETERGROUP: + case Bang::HideMeterGroup: HideMeter(args[0], true); break; - case BANG_UPDATEMETERGROUP: + case Bang::UpdateMeterGroup: UpdateMeter(args[0], true); break; - case BANG_TOGGLEMEASURE: + case Bang::ToggleMeasure: ToggleMeasure(args[0]); break; - case BANG_ENABLEMEASURE: + case Bang::EnableMeasure: EnableMeasure(args[0]); break; - case BANG_DISABLEMEASURE: + case Bang::DisableMeasure: DisableMeasure(args[0]); break; - case BANG_UPDATEMEASURE: + case Bang::UpdateMeasure: UpdateMeasure(args[0]); CDialogAbout::UpdateMeasures(this); break; - case BANG_DISABLEMEASUREGROUP: + case Bang::DisableMeasureGroup: DisableMeasure(args[0], true); break; - case BANG_TOGGLEMEASUREGROUP: + case Bang::ToggleMeasureGroup: ToggleMeasure(args[0], true); break; - case BANG_ENABLEMEASUREGROUP: + case Bang::EnableMeasureGroup: EnableMeasure(args[0], true); break; - case BANG_UPDATEMEASUREGROUP: + case Bang::UpdateMeasureGroup: UpdateMeasure(args[0], true); CDialogAbout::UpdateMeasures(this); break; - case BANG_SHOW: + case Bang::Show: m_Hidden = false; ShowWindow(m_Window, SW_SHOWNOACTIVATE); UpdateWindowTransparency((m_WindowHide == HIDEMODE_FADEOUT) ? 255 : m_AlphaValue); break; - case BANG_HIDE: + case Bang::Hide: m_Hidden = true; ShowWindow(m_Window, SW_HIDE); break; - case BANG_TOGGLE: - RunBang(m_Hidden ? BANG_SHOW : BANG_HIDE, args); + case Bang::Toggle: + DoBang(m_Hidden ? Bang::Show : Bang::Toggle, args); break; - case BANG_SHOWFADE: + case Bang::ShowFade: ShowFade(); break; - case BANG_HIDEFADE: + case Bang::HideFade: HideFade(); break; - case BANG_TOGGLEFADE: - RunBang(m_Hidden ? BANG_SHOWFADE : BANG_HIDEFADE, args); + case Bang::ToggleFade: + DoBang(m_Hidden ? Bang::ShowFade : Bang::HideFade, args); break; - case BANG_MOVE: + case Bang::Move: { int x = m_Parser.ParseInt(args[0].c_str(), 0); int y = m_Parser.ParseInt(args[1].c_str(), 0); @@ -851,39 +851,39 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_ZPOS: + case Bang::ZPos: SetWindowZPosition((ZPOSITION)m_Parser.ParseInt(args[0].c_str(), 0)); break; - case BANG_CLICKTHROUGH: + case Bang::ClickThrough: { int f = m_Parser.ParseInt(args[0].c_str(), 0); SetClickThrough((f == -1) ? !m_ClickThrough : f); } break; - case BANG_DRAGGABLE: + case Bang::Draggable: { int f = m_Parser.ParseInt(args[0].c_str(), 0); SetWindowDraggable((f == -1) ? !m_WindowDraggable : f); } break; - case BANG_SNAPEDGES: + case Bang::SnapEdges: { int f = m_Parser.ParseInt(args[0].c_str(), 0); SetSnapEdges((f == -1) ? !m_SnapEdges : f); } break; - case BANG_KEEPONSCREEN: + case Bang::KeepOnScreen: { int f = m_Parser.ParseInt(args[0].c_str(), 0); SetKeepOnScreen((f == -1) ? !m_KeepOnScreen : f); } break; - case BANG_SETTRANSPARENCY: + case Bang::SetTransparency: { const std::wstring& arg = args[0]; m_AlphaValue = CConfigParser::ParseInt(arg.c_str(), 255); @@ -893,7 +893,7 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_MOVEMETER: + case Bang::MoveMeter: { int x = m_Parser.ParseInt(args[0].c_str(), 0); int y = m_Parser.ParseInt(args[1].c_str(), 0); @@ -901,7 +901,7 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_COMMANDMEASURE: + case Bang::CommandMeasure: { const std::wstring& measure = args[0]; CMeasure* m = GetMeasure(measure); @@ -916,7 +916,7 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_PLUGIN: + case Bang::PluginBang: { std::wstring arg = args[0]; std::wstring::size_type pos; @@ -956,15 +956,15 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const std::vector& ar } break; - case BANG_SETVARIABLE: + case Bang::SetVariable: SetVariable(args[0], args[1]); break; - case BANG_SETOPTION: + case Bang::SetOption: SetOption(args[0], args[1], args[2], false); break; - case BANG_SETOPTIONGROUP: + case Bang::SetOptionGroup: SetOption(args[0], args[1], args[2], true); break; } diff --git a/Library/MeterWindow.h b/Library/MeterWindow.h index 93d2fd0b..d1ae8b75 100644 --- a/Library/MeterWindow.h +++ b/Library/MeterWindow.h @@ -23,6 +23,7 @@ #include #include #include +#include "CommandHandler.h" #include "ConfigParser.h" #include "Group.h" #include "Mouse.h" @@ -91,55 +92,6 @@ enum BEVELTYPE BEVELTYPE_DOWN }; -enum BANGCOMMAND -{ - BANG_REFRESH, - BANG_REDRAW, - BANG_UPDATE, - BANG_TOGGLEMETER, - BANG_SHOWMETER, - BANG_HIDEMETER, - BANG_MOVEMETER, - BANG_UPDATEMETER, - BANG_TOGGLEMEASURE, - BANG_ENABLEMEASURE, - BANG_DISABLEMEASURE, - BANG_UPDATEMEASURE, - BANG_COMMANDMEASURE, - BANG_SHOWBLUR, - BANG_HIDEBLUR, - BANG_TOGGLEBLUR, - BANG_ADDBLUR, - BANG_REMOVEBLUR, - BANG_SHOW, - BANG_HIDE, - BANG_TOGGLE, - BANG_SHOWFADE, - BANG_HIDEFADE, - BANG_TOGGLEFADE, - BANG_MOVE, - BANG_ZPOS, - BANG_SETTRANSPARENCY, - BANG_CLICKTHROUGH, - BANG_DRAGGABLE, - BANG_SNAPEDGES, - BANG_KEEPONSCREEN, - - BANG_TOGGLEMETERGROUP, - BANG_SHOWMETERGROUP, - BANG_HIDEMETERGROUP, - BANG_UPDATEMETERGROUP, - BANG_TOGGLEMEASUREGROUP, - BANG_ENABLEMEASUREGROUP, - BANG_DISABLEMEASUREGROUP, - BANG_UPDATEMEASUREGROUP, - - BANG_PLUGIN, - BANG_SETVARIABLE, - BANG_SETOPTION, - BANG_SETOPTIONGROUP -}; - enum RESIZEMODE { RESIZEMODE_NONE = 0, @@ -165,7 +117,7 @@ public: void Initialize(); - void RunBang(BANGCOMMAND bang, const std::vector& args); + void DoBang(Bang bang, const std::vector& args); void HideMeter(const std::wstring& name, bool group = false); void ShowMeter(const std::wstring& name, bool group = false); diff --git a/Library/Rainmeter.cpp b/Library/Rainmeter.cpp index 43486155..1a5925ce 100644 --- a/Library/Rainmeter.cpp +++ b/Library/Rainmeter.cpp @@ -107,580 +107,6 @@ int RainmeterMain(LPWSTR cmdLine) return ret; } -/* -** Splits the given string into substrings -** -*/ -std::vector CRainmeter::ParseString(LPCTSTR str, CConfigParser* parser) -{ - std::vector result; - - if (str) - { - std::wstring arg = str; - - // Split the argument between first space. - // Or if string is in quotes, the after the second quote. - - auto addResult = [&](std::wstring& string, bool stripQuotes) - { - if (stripQuotes) - { - size_t pos = 0; - do - { - pos = string.find(L'"', pos); - if (pos != std::wstring::npos) - { - string.erase(pos, 1); - } - } - while (pos != std::wstring::npos); - } - - if (parser) - { - parser->ReplaceMeasures(string); - } - - result.push_back(string); - }; - - size_t pos; - std::wstring newStr; - while ((pos = arg.find_first_not_of(L' ')) != std::wstring::npos) - { - size_t extra = 1; - 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); - - extra = 4; - if ((pos = arg.find(L"\"\"\" ")) == std::wstring::npos) - { - extra = 3; - pos = arg.rfind(L"\"\"\""); // search backward - } - } - 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 + extra); - - addResult(newStr, extra == 1); - } - else // quote or space not found - { - addResult(arg, extra == 1); - arg.clear(); - break; - } - } - - if (!arg.empty() && result.empty()) - { - addResult(arg, true); - } - } - - return result; -} - -/* -** Parses Bang args -** -*/ -void CRainmeter::BangWithArgs(BANGCOMMAND bang, std::vector& args, size_t numOfArgs, CMeterWindow* meterWindow) -{ - const size_t argsCount = args.size(); - - if (argsCount >= numOfArgs) - { - if (argsCount == numOfArgs && meterWindow) - { - meterWindow->RunBang(bang, args); - } - else - { - // Use the specified window instead of meterWindow parameter - if (argsCount > numOfArgs) - { - const std::wstring& folderPath = args[numOfArgs]; - if (!folderPath.empty() && (folderPath.length() != 1 || folderPath[0] != L'*')) - { - CMeterWindow* meterWindow = GetMeterWindow(folderPath); - if (meterWindow) - { - meterWindow->RunBang(bang, args); - } - else - { - LogErrorF( L"Bang: Skin \"%s\" not found", folderPath.c_str()); - } - return; - } - } - - // No skin defined -> apply to all. - std::map::const_iterator iter = m_MeterWindows.begin(); - for (; iter != m_MeterWindows.end(); ++iter) - { - ((*iter).second)->RunBang(bang, args); - } - } - } - else - { - // For backwards compatibility - if (bang == BANG_COMMANDMEASURE && argsCount >= 1) - { - std::wstring& firstArg = args[0]; - std::wstring::size_type pos = firstArg.find_first_of(L' '); - if (pos != std::wstring::npos) - { - std::wstring newArg = firstArg.substr(0, pos); - firstArg.erase(0, pos + 1); - args.insert(args.begin(), newArg); - - LogWarning(L"!CommandMeasure: Two parameters required, only one given"); - BangWithArgs(bang, args, numOfArgs, meterWindow); - return; - } - } - - LogError(L"Bang: Incorrect number of arguments"); - } -} - -/* -** Parses Bang args for Group -** -*/ -void CRainmeter::BangGroupWithArgs(BANGCOMMAND bang, std::vector& args, size_t numOfArgs, CMeterWindow* meterWindow) -{ - if (args.size() > numOfArgs) - { - std::multimap windows; - GetMeterWindowsByLoadOrder(windows, args[numOfArgs]); - - args.resize(numOfArgs); // Remove extra parameters (including group) - - std::multimap::const_iterator iter = windows.begin(); - for (; iter != windows.end(); ++iter) - { - BangWithArgs(bang, args, numOfArgs, (*iter).second); - } - } - else - { - LogError(L"BangGroup: Incorrect number of arguments"); - } -} - -/* -** !ActivateConfig bang -** -*/ -void CRainmeter::Bang_ActivateSkin(std::vector& args) -{ - if (args.size() == 1) - { - int index = FindSkinFolderIndex(args[0]); - if (index != -1) - { - const SkinFolder& skinFolder = m_SkinFolders[index]; - if (!(skinFolder.active == 1 && skinFolder.files.size() == 1)) - { - // Activate the next index. - ActivateSkin(index, (skinFolder.active < skinFolder.files.size()) ? skinFolder.active : 0); - } - return; - } - } - else if (args.size() > 1) - { - std::pair indexes = GetMeterWindowIndex(args[0], args[1]); - if (indexes.first != -1 && indexes.second != -1) - { - ActivateSkin(indexes.first, indexes.second); - return; - } - } - - LogError(L"!ActivateConfig: Invalid parameters"); -} - -/* -** !DeactivateConfig bang -** -*/ -void CRainmeter::Bang_DeactivateSkin(std::vector& args, CMeterWindow* meterWindow) -{ - if (!args.empty()) - { - meterWindow = GetMeterWindow(args[0]); - if (!meterWindow) - { - LogWarningF(L"!DeactivateConfig: \"%s\" not active", args[0].c_str()); - return; - } - } - - if (meterWindow) - { - DeactivateSkin(meterWindow, -1); - } - else - { - LogError(L"!DeactivateConfig: Invalid parameters"); - } -} - -/* -** !ToggleConfig bang -** -*/ -void CRainmeter::Bang_ToggleSkin(std::vector& args) -{ - if (args.size() >= 2) - { - CMeterWindow* mw = GetMeterWindow(args[0]); - if (mw) - { - DeactivateSkin(mw, -1); - return; - } - - // If the skin wasn't active, activate it - Bang_ActivateSkin(args); - } - else - { - LogError(L"!ToggleConfig: Invalid parameters"); - } -} - -/* -** !DeactivateConfigGroup bang -** -*/ -void CRainmeter::Bang_DeactivateSkinGroup(std::vector& args) -{ - if (!args.empty()) - { - std::multimap windows; - GetMeterWindowsByLoadOrder(windows, args[0]); - - std::multimap::const_iterator iter = windows.begin(); - for (; iter != windows.end(); ++iter) - { - DeactivateSkin((*iter).second, -1); - } - } - else - { - LogError(L"!DeactivateConfigGroup: Invalid parameters"); - } -} - -/* -** !LoadLayout bang -** -*/ -void CRainmeter::Bang_LoadLayout(std::vector& args, CMeterWindow* meterWindow) -{ - if (args.size() == 1) - { - if (meterWindow) - { - // Delay to avoid loading theme in the middle of an update. - std::wstring command = L"!LoadLayout \""; - command += args[0]; - command += L'"'; - Rainmeter->DelayedExecuteCommand(command.c_str()); - } - else - { - // Not called from a skin (or called with delay). - LoadLayout(args[0]); - } - } -} - -/* -** !SetClip bang -** -*/ -void CRainmeter::Bang_SetClip(std::vector& args) -{ - if (!args.empty()) - { - CSystem::SetClipboardText(args[0]); - } - else - { - LogError(L"!SetClip: Invalid parameter"); - } -} - -/* -** !SetWallpaper bang -** -*/ -void CRainmeter::Bang_SetWallpaper(std::vector& args, CMeterWindow* meterWindow) -{ - const size_t argsSize = args.size(); - if (argsSize >= 1 && argsSize <= 2) - { - std::wstring& file = args[0]; - const std::wstring& style = (argsSize == 2) ? args[1] : L""; - - if (meterWindow) - { - meterWindow->MakePathAbsolute(file); - } - - CSystem::SetWallpaper(file, style); - } - else - { - LogError(L"!SetWallpaper: Invalid parameters"); - } -} - -/* -** !SkinMenu bang -** -*/ -void CRainmeter::Bang_SkinMenu(std::vector& args, CMeterWindow* meterWindow) -{ - if (!args.empty()) - { - meterWindow = GetMeterWindow(args[0]); - if (!meterWindow) - { - LogWarningF(L"!SkinMenu: \"%s\" not active", args[0].c_str()); - return; - } - } - - if (meterWindow) - { - POINT pos = CSystem::GetCursorPosition(); - ShowContextMenu(pos, meterWindow); - } - else - { - LogError(L"!SkinMenu: Invalid parameter"); - } -} - -/* -** !TrayMenu bang -** -*/ -void CRainmeter::Bang_TrayMenu() -{ - POINT pos = CSystem::GetCursorPosition(); - ShowContextMenu(pos, NULL); -} - -/* -** !WriteKeyValue bang -** -*/ -void CRainmeter::Bang_WriteKeyValue(std::vector& args, CMeterWindow* meterWindow) -{ - if (args.size() == 3 && meterWindow) - { - // Add the skin file path to the args - args.push_back(meterWindow->GetFilePath()); - } - else if (args.size() < 4) - { - LogError(L"!WriteKeyValue: Invalid parameters"); - return; - } - - std::wstring& strIniFile = args[3]; - if (meterWindow) - { - meterWindow->MakePathAbsolute(strIniFile); - } - - const WCHAR* iniFile = strIniFile.c_str(); - - if (strIniFile.find(L"..\\") != std::wstring::npos || strIniFile.find(L"../") != std::wstring::npos) - { - LogErrorF(L"!WriteKeyValue: Illegal path: %s", iniFile); - return; - } - - if (_wcsnicmp(iniFile, m_SkinPath.c_str(), m_SkinPath.size()) != 0 && - _wcsnicmp(iniFile, m_SettingsPath.c_str(), m_SettingsPath.size()) != 0) - { - LogErrorF(L"!WriteKeyValue: Illegal path: %s", iniFile); - return; - } - - // Verify whether the file exists - if (_waccess(iniFile, 0) == -1) - { - LogErrorF(L"!WriteKeyValue: File not found: %s", iniFile); - return; - } - - // Verify whether the file is read-only - DWORD attr = GetFileAttributes(iniFile); - if (attr == -1 || (attr & FILE_ATTRIBUTE_READONLY)) - { - LogWarningF(L"!WriteKeyValue: File is read-only: %s", iniFile); - return; - } - - // Avoid "IniFileMapping" - CSystem::UpdateIniFileMappingList(); - std::wstring strIniWrite = CSystem::GetTemporaryFile(strIniFile); - if (strIniWrite.size() == 1 && strIniWrite[0] == L'?') // error occurred - { - return; - } - - bool temporary = !strIniWrite.empty(); - - if (temporary) - { - if (GetDebug()) LogDebugF(L"!WriteKeyValue: Writing to: %s (Temp: %s)", iniFile, strIniWrite.c_str()); - } - else - { - if (GetDebug()) LogDebugF(L"!WriteKeyValue: Writing to: %s", iniFile); - strIniWrite = strIniFile; - } - - const WCHAR* iniWrite = strIniWrite.c_str(); - const WCHAR* section = args[0].c_str(); - const WCHAR* key = args[1].c_str(); - const std::wstring& strValue = args[2]; - - bool formula = false; - BOOL write = 0; - - if (meterWindow) - { - double value; - formula = meterWindow->GetParser().ParseFormula(strValue, &value); - - // Formula read fine - if (formula) - { - WCHAR buffer[256]; - int len = _snwprintf_s(buffer, _TRUNCATE, L"%.5f", value); - CMeasure::RemoveTrailingZero(buffer, len); - - write = WritePrivateProfileString(section, key, buffer, iniWrite); - } - } - - if (!formula) - { - write = WritePrivateProfileString(section, key, strValue.c_str(), iniWrite); - } - - if (temporary) - { - if (write != 0) - { - WritePrivateProfileString(NULL, NULL, NULL, iniWrite); // FLUSH - - // Copy the file back - if (!CSystem::CopyFiles(strIniWrite, strIniFile)) - { - LogErrorF(L"!WriteKeyValue: Failed to copy temporary file to original filepath: %s (Temp: %s)", iniFile, iniWrite); - } - } - else // failed - { - LogErrorF(L"!WriteKeyValue: Failed to write to: %s (Temp: %s)", iniFile, iniWrite); - } - - // Remove a temporary file - CSystem::RemoveFile(strIniWrite); - } - else - { - if (write == 0) // failed - { - LogErrorF(L"!WriteKeyValue: Failed to write to: %s", iniFile); - } - } -} - -/* -** !Log bang -** -*/ -void CRainmeter::Bang_Log(std::vector& args) -{ - if (!args.empty()) - { - CLogger::Level level = CLogger::Level::Notice; - if (args.size() > 1) - { - const WCHAR* type = args[1].c_str(); - if (_wcsicmp(type, L"ERROR") == 0) - { - level = CLogger::Level::Error; - } - else if (_wcsicmp(type, L"WARNING") == 0) - { - level = CLogger::Level::Warning; - } - else if (_wcsicmp(type, L"DEBUG") == 0) - { - level = CLogger::Level::Debug; - } - else if (_wcsicmp(type, L"NOTICE") != 0) - { - LogError(L"!Log: Invalid type"); - return; - } - } - - CLogger::GetInstance().Log(level, args[0].c_str()); - } -} - - -// ----------------------------------------------------------------------------------------------- -// -// The class starts here -// -// ----------------------------------------------------------------------------------------------- - /* ** Constructor ** @@ -1018,7 +444,7 @@ int CRainmeter::Initialize(LPCWSTR iniPath, LPCWSTR layout) bool layoutLoaded = false; if (layout) { - std::vector args = ParseString(layout); + std::vector args = CCommandHandler::ParseString(layout); layoutLoaded = (args.size() == 1 && LoadLayout(args[0])); } @@ -1367,7 +793,7 @@ void CRainmeter::EditSettings() { std::wstring file = L'"' + m_IniFile; file += L'"'; - RunFile(m_SkinEditor.c_str(), file.c_str()); + CCommandHandler::RunFile(m_SkinEditor.c_str(), file.c_str()); } void CRainmeter::EditSkinFile(const std::wstring& name, const std::wstring& iniFile) @@ -1377,13 +803,13 @@ void CRainmeter::EditSkinFile(const std::wstring& name, const std::wstring& iniF args += L'\\'; args += iniFile; args += L'"'; - RunFile(m_SkinEditor.c_str(), args.c_str()); + CCommandHandler::RunFile(m_SkinEditor.c_str(), args.c_str()); } void CRainmeter::OpenSkinFolder(const std::wstring& name) { std::wstring folderPath = m_SkinPath + name; - RunFile(folderPath.c_str()); + CCommandHandler::RunFile(folderPath.c_str()); } void CRainmeter::ActivateActiveSkins() @@ -1971,316 +1397,7 @@ void CRainmeter::ScanForLayouts() void CRainmeter::ExecuteBang(const WCHAR* bang, std::vector& args, CMeterWindow* meterWindow) { - if (_wcsicmp(bang, L"Refresh") == 0) - { - BangWithArgs(BANG_REFRESH, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"RefreshApp") == 0) - { - // Refresh needs to be delayed since it crashes if done during Update() - PostMessage(m_Window, WM_RAINMETER_DELAYED_REFRESH_ALL, (WPARAM)NULL, (LPARAM)NULL); - } - else if (_wcsicmp(bang, L"Redraw") == 0) - { - BangWithArgs(BANG_REDRAW, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"Update") == 0) - { - BangWithArgs(BANG_UPDATE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"Hide") == 0) - { - BangWithArgs(BANG_HIDE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"Show") == 0) - { - BangWithArgs(BANG_SHOW, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"Toggle") == 0) - { - BangWithArgs(BANG_TOGGLE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideFade") == 0) - { - BangWithArgs(BANG_HIDEFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ShowFade") == 0) - { - BangWithArgs(BANG_SHOWFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleFade") == 0) - { - BangWithArgs(BANG_TOGGLEFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideMeter") == 0) - { - BangWithArgs(BANG_HIDEMETER, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ShowMeter") == 0) - { - BangWithArgs(BANG_SHOWMETER, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleMeter") == 0) - { - BangWithArgs(BANG_TOGGLEMETER, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"MoveMeter") == 0) - { - BangWithArgs(BANG_MOVEMETER, args, 3, meterWindow); - } - else if (_wcsicmp(bang, L"UpdateMeter") == 0) - { - BangWithArgs(BANG_UPDATEMETER, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"DisableMeasure") == 0) - { - BangWithArgs(BANG_DISABLEMEASURE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"EnableMeasure") == 0) - { - BangWithArgs(BANG_ENABLEMEASURE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleMeasure") == 0) - { - BangWithArgs(BANG_TOGGLEMEASURE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"UpdateMeasure") == 0) - { - BangWithArgs(BANG_UPDATEMEASURE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"CommandMeasure") == 0) - { - BangWithArgs(BANG_COMMANDMEASURE, args, 2, meterWindow); - } - else if (_wcsicmp(bang, L"ShowBlur") == 0) - { - BangWithArgs(BANG_SHOWBLUR, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideBlur") == 0) - { - BangWithArgs(BANG_HIDEBLUR, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleBlur") == 0) - { - BangWithArgs(BANG_TOGGLEBLUR, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"AddBlur") == 0) - { - BangWithArgs(BANG_ADDBLUR, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"RemoveBlur") == 0) - { - BangWithArgs(BANG_REMOVEBLUR, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ActivateConfig") == 0) - { - Bang_ActivateSkin(args); - } - else if (_wcsicmp(bang, L"DeactivateConfig") == 0) - { - Bang_DeactivateSkin(args, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleConfig") == 0) - { - Bang_ToggleSkin(args); - } - else if (_wcsicmp(bang, L"Move") == 0) - { - BangWithArgs(BANG_MOVE, args, 2, meterWindow); - } - else if (_wcsicmp(bang, L"ZPos") == 0 || _wcsicmp(bang, L"ChangeZPos") == 0) // For backwards compatibility - { - BangWithArgs(BANG_ZPOS, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ClickThrough") == 0) - { - BangWithArgs(BANG_CLICKTHROUGH, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"Draggable") == 0) - { - BangWithArgs(BANG_DRAGGABLE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SnapEdges") == 0) - { - BangWithArgs(BANG_SNAPEDGES, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"KeepOnScreen") == 0) - { - BangWithArgs(BANG_KEEPONSCREEN, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SetTransparency") == 0) - { - BangWithArgs(BANG_SETTRANSPARENCY, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SetVariable") == 0) - { - BangWithArgs(BANG_SETVARIABLE, args, 2, meterWindow); - } - else if (_wcsicmp(bang, L"SetOption") == 0) - { - BangWithArgs(BANG_SETOPTION, args, 3, meterWindow); - } - else if (_wcsicmp(bang, L"RefreshGroup") == 0) - { - BangGroupWithArgs(BANG_REFRESH, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"UpdateGroup") == 0) - { - BangGroupWithArgs(BANG_UPDATE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"RedrawGroup") == 0) - { - BangGroupWithArgs(BANG_REDRAW, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideGroup") == 0) - { - BangGroupWithArgs(BANG_HIDE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ShowGroup") == 0) - { - BangGroupWithArgs(BANG_SHOW, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleGroup") == 0) - { - BangGroupWithArgs(BANG_TOGGLE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideFadeGroup") == 0) - { - BangGroupWithArgs(BANG_HIDEFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ShowFadeGroup") == 0) - { - BangGroupWithArgs(BANG_SHOWFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleFadeGroup") == 0) - { - BangGroupWithArgs(BANG_TOGGLEFADE, args, 0, meterWindow); - } - else if (_wcsicmp(bang, L"HideMeterGroup") == 0) - { - BangWithArgs(BANG_HIDEMETERGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ShowMeterGroup") == 0) - { - BangWithArgs(BANG_SHOWMETERGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleMeterGroup") == 0) - { - BangWithArgs(BANG_TOGGLEMETERGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"UpdateMeterGroup") == 0) - { - BangWithArgs(BANG_UPDATEMETERGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"DisableMeasureGroup") == 0) - { - BangWithArgs(BANG_DISABLEMEASUREGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"EnableMeasureGroup") == 0) - { - BangWithArgs(BANG_ENABLEMEASUREGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ToggleMeasureGroup") == 0) - { - BangWithArgs(BANG_TOGGLEMEASUREGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"UpdateMeasureGroup") == 0) - { - BangWithArgs(BANG_UPDATEMEASUREGROUP, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"DeactivateConfigGroup") == 0) - { - Bang_DeactivateSkinGroup(args); - } - else if (_wcsicmp(bang, L"ZPosGroup") == 0) - { - BangGroupWithArgs(BANG_ZPOS, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"ClickThroughGroup") == 0) - { - BangGroupWithArgs(BANG_CLICKTHROUGH, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"DraggableGroup") == 0) - { - BangGroupWithArgs(BANG_DRAGGABLE, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SnapEdgesGroup") == 0) - { - BangGroupWithArgs(BANG_SNAPEDGES, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"KeepOnScreenGroup") == 0) - { - BangGroupWithArgs(BANG_KEEPONSCREEN, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SetTransparencyGroup") == 0) - { - BangGroupWithArgs(BANG_SETTRANSPARENCY, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"SetVariableGroup") == 0) - { - BangGroupWithArgs(BANG_SETVARIABLE, args, 2, meterWindow); - } - else if (_wcsicmp(bang, L"SetOptionGroup") == 0) - { - BangWithArgs(BANG_SETOPTIONGROUP, args, 3, meterWindow); - } - else if (_wcsicmp(bang, L"WriteKeyValue") == 0) - { - Bang_WriteKeyValue(args, meterWindow); - } - else if (_wcsicmp(bang, L"PluginBang") == 0) - { - BangWithArgs(BANG_PLUGIN, args, 1, meterWindow); - } - else if (_wcsicmp(bang, L"LoadLayout") == 0) - { - Bang_LoadLayout(args, meterWindow); - } - else if (_wcsicmp(bang, L"SetClip") == 0) - { - Bang_SetClip(args); - } - else if (_wcsicmp(bang, L"SetWallpaper") == 0) - { - Bang_SetWallpaper(args, meterWindow); - } - else if (_wcsicmp(bang, L"About") == 0) - { - CDialogAbout::Open(args.empty() ? L"" : args[0].c_str()); - } - else if (_wcsicmp(bang, L"Manage") == 0) - { - CDialogManage::Open(args.empty() ? L"" : args[0].c_str()); - } - else if (_wcsicmp(bang, L"SkinMenu") == 0) - { - Bang_SkinMenu(args, meterWindow); - } - else if (_wcsicmp(bang, L"TrayMenu") == 0) - { - Bang_TrayMenu(); - } - else if (_wcsicmp(bang, L"ResetStats") == 0) - { - ResetStats(); - } - else if (_wcsicmp(bang, L"Log") == 0) - { - Bang_Log(args); - } - else if (_wcsicmp(bang, L"Quit") == 0) - { - // Quit needs to be delayed since it crashes if done during Update() - PostMessage(GetTrayWindow()->GetWindow(), WM_COMMAND, MAKEWPARAM(IDM_QUIT, 0), (LPARAM)NULL); - } - else if (_wcsicmp(bang, L"LsBoxHook") == 0) - { - // Deprecated. - } - else - { - LogErrorF(L"Invalid bang: !%s", bang); - } + m_CommandHandler.ExecuteBang(bang, args, meterWindow); } /* @@ -2289,142 +1406,7 @@ void CRainmeter::ExecuteBang(const WCHAR* bang, std::vector& args, */ void CRainmeter::ExecuteCommand(const WCHAR* command, CMeterWindow* meterWindow, bool multi) { - if (command[0] == L'!') // Bang - { - ++command; // Skip "!" - - if (_wcsnicmp(L"Execute", command, 7) == 0) - { - command += 7; - command = wcschr(command, L'['); - if (!command) return; - } - else - { - if (_wcsnicmp(command, L"Rainmeter", 9) == 0) - { - // Skip "Rainmeter" for backwards compatibility - command += 9; - } - - std::wstring bang; - std::vector args; - - // Find the first space - const WCHAR* pos = wcschr(command, L' '); - if (pos) - { - bang.assign(command, 0, pos - command); - args = ParseString(pos + 1, meterWindow ? &meterWindow->GetParser() : NULL); - } - else - { - bang = command; - } - - ExecuteBang(bang.c_str(), args, meterWindow); - return; - } - } - - if (multi && command[0] == L'[') // Multi-bang - { - std::wstring bangs = command; - std::wstring::size_type start = std::wstring::npos; - int count = 0; - for (size_t i = 0, isize = bangs.size(); i < isize; ++i) - { - if (bangs[i] == L'[') - { - if (count == 0) - { - start = i; - } - ++count; - } - else if (bangs[i] == L']') - { - --count; - - if (count == 0 && start != std::wstring::npos) - { - // Change ] to NULL - bangs[i] = L'\0'; - - // Skip whitespace - start = bangs.find_first_not_of(L" \t\r\n", start + 1, 4); - - ExecuteCommand(bangs.c_str() + start, meterWindow, false); - } - } - else if (bangs[i] == L'"' && isize > (i + 2) && bangs[i + 1] == L'"' && bangs[i + 2] == L'"') - { - i += 3; - - std::wstring::size_type pos = bangs.find(L"\"\"\"", i); - if (pos != std::wstring::npos) - { - i = pos + 2; // Skip "", loop will skip last " - } - } - } - } - else - { - // Check for built-ins - if (_wcsnicmp(L"PLAY", command, 4) == 0) - { - if (command[4] == L' ' || // PLAY - _wcsnicmp(L"LOOP ", &command[4], 5) == 0) // PLAYLOOP - { - command += 4; // Skip PLAY - - DWORD flags = SND_FILENAME | SND_ASYNC; - - if (command[0] != L' ') - { - flags |= SND_LOOP | SND_NODEFAULT; - command += 4; // Skip LOOP - } - - ++command; // Skip the space - if (command[0] != L'\0') - { - std::wstring sound = command; - - // Strip the quotes - std::wstring::size_type len = sound.length(); - if (len >= 2 && sound[0] == L'"' && sound[len - 1] == L'"') - { - len -= 2; - sound.assign(sound, 1, len); - } - - if (meterWindow) - { - meterWindow->GetParser().ReplaceMeasures(sound); - meterWindow->MakePathAbsolute(sound); - } - - PlaySound(sound.c_str(), NULL, flags); - } - return; - } - else if (_wcsnicmp(L"STOP", &command[4], 4) == 0) // PLAYSTOP - { - PlaySound(NULL, NULL, SND_PURGE); - return; - } - } - - // Run command - std::wstring tmpSz = command; - if (meterWindow) - { - meterWindow->GetParser().ReplaceMeasures(tmpSz); - } - RunCommand(tmpSz); - } + m_CommandHandler.ExecuteCommand(command, meterWindow, multi); } /* @@ -3520,7 +2502,7 @@ void CRainmeter::ShowLogFile() std::wstring logFile = L'"' + CLogger::GetInstance().GetLogFilePath(); logFile += L'"'; - RunFile(m_SkinEditor.c_str(), logFile.c_str()); + CCommandHandler::RunFile(m_SkinEditor.c_str(), logFile.c_str()); } void CRainmeter::SetDebug(bool debug) diff --git a/Library/Rainmeter.h b/Library/Rainmeter.h index e041ebef..1d77f583 100644 --- a/Library/Rainmeter.h +++ b/Library/Rainmeter.h @@ -24,7 +24,7 @@ #include #include #include -#include "Litestep.h" +#include "CommandHandler.h" #include "Logger.h" #include "MeterWindow.h" @@ -212,29 +212,15 @@ public: bool LoadLayout(const std::wstring& name); void PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace = true); - static std::vector ParseString(LPCTSTR str, CConfigParser* parser = NULL); static std::wstring ExtractPath(const std::wstring& strFilePath); static void ExpandEnvironmentVariables(std::wstring& strPath); + friend class CCommandHandler; friend class CDialogManage; private: static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - void BangWithArgs(BANGCOMMAND bang, std::vector& args, size_t numOfArgs, CMeterWindow* meterWindow); - void BangGroupWithArgs(BANGCOMMAND bang, std::vector& args, size_t numOfArgs, CMeterWindow* meterWindow); - void Bang_ActivateSkin(std::vector& args); - void Bang_DeactivateSkin(std::vector& args, CMeterWindow* meterWindow); - void Bang_ToggleSkin(std::vector& args); - void Bang_DeactivateSkinGroup(std::vector& args); - void Bang_LoadLayout(std::vector& args, CMeterWindow* meterWindow); - void Bang_SetClip(std::vector& args); - void Bang_SetWallpaper(std::vector& args, CMeterWindow* meterWindow); - void Bang_SkinMenu(std::vector& args, CMeterWindow* meterWindow); - void Bang_TrayMenu(); - void Bang_WriteKeyValue(std::vector& args, CMeterWindow* meterWindow); - void Bang_Log(std::vector& args); - void ActivateActiveSkins(); void CreateMeterWindow(const std::wstring& folderPath, const std::wstring& file); void DeleteAllMeterWindows(); @@ -306,6 +292,8 @@ private: std::wstring m_SkinEditor; + CCommandHandler m_CommandHandler; + CConfigParser* m_CurrentParser; HWND m_Window; diff --git a/Library/TrayWindow.cpp b/Library/TrayWindow.cpp index 77c48dbc..2c9f830f 100644 --- a/Library/TrayWindow.cpp +++ b/Library/TrayWindow.cpp @@ -475,11 +475,11 @@ LRESULT CALLBACK CTrayWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; case IDM_SHOW_HELP: - RunFile(RAINMETER_HELP); + CCommandHandler::RunFile(RAINMETER_HELP); break; case IDM_NEW_VERSION: - RunFile(RAINMETER_OFFICIAL); + CCommandHandler::RunFile(RAINMETER_OFFICIAL); break; case IDM_REFRESH: @@ -634,7 +634,7 @@ LRESULT CALLBACK CTrayWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else if (tray->m_Notification == TRAY_NOTIFICATION_UPDATE) { - RunFile(RAINMETER_OFFICIAL); + CCommandHandler::RunFile(RAINMETER_OFFICIAL); } tray->m_Notification = TRAY_NOTIFICATION_NONE; break; diff --git a/Library/lua/LuaManager.cpp b/Library/lua/LuaManager.cpp index d754b9e5..9d2f70c2 100644 --- a/Library/lua/LuaManager.cpp +++ b/Library/lua/LuaManager.cpp @@ -17,8 +17,9 @@ */ #include "../StdAfx.h" +#include "../../Common/StringUtil.h" #include "LuaManager.h" -#include "../Rainmeter.h" +#include "../Logger.h" int LuaManager::c_RefCount = 0; lua_State* LuaManager::c_State = 0; diff --git a/Library/lua/LuaScript.cpp b/Library/lua/LuaScript.cpp index 96ede74b..db032a96 100644 --- a/Library/lua/LuaScript.cpp +++ b/Library/lua/LuaScript.cpp @@ -17,9 +17,9 @@ */ #include "../StdAfx.h" +#include "../../Common/StringUtil.h" #include "LuaScript.h" #include "LuaManager.h" -#include "../Rainmeter.h" /* ** The constructor