diff --git a/Library/ConfigParser.cpp b/Library/ConfigParser.cpp index e39482a6..18a020bc 100644 --- a/Library/ConfigParser.cpp +++ b/Library/ConfigParser.cpp @@ -51,10 +51,8 @@ CConfigParser::~CConfigParser() { } -void CConfigParser::Initialize(LPCTSTR filename, CRainmeter* pRainmeter, CMeterWindow* meterWindow, LPCTSTR config) +void CConfigParser::Initialize(const std::wstring& filename, CMeterWindow* meterWindow, LPCTSTR config) { - m_Filename = filename; - m_Measures.clear(); m_Sections.clear(); m_Values.clear(); @@ -70,12 +68,19 @@ void CConfigParser::Initialize(LPCTSTR filename, CRainmeter* pRainmeter, CMeterW m_CurrentSection = NULL; // Set the built-in variables. Do this before the ini file is read so that the paths can be used with @include - SetBuiltInVariables(pRainmeter, meterWindow); + SetBuiltInVariables(filename, meterWindow); ResetMonitorVariables(meterWindow); CSystem::UpdateIniFileMappingList(); - ReadIniFile(m_Filename, config); + std::wstring resourcePath; + if (meterWindow) + { + resourcePath = meterWindow->GetSkinRootPath(); + resourcePath += L"@Resources\\"; + } + + ReadIniFile(filename, resourcePath, config); ReadVariables(); // Clear and minimize @@ -83,18 +88,16 @@ void CConfigParser::Initialize(LPCTSTR filename, CRainmeter* pRainmeter, CMeterW m_ListVariables.clear(); } -void CConfigParser::SetBuiltInVariables(CRainmeter* pRainmeter, CMeterWindow* meterWindow) +void CConfigParser::SetBuiltInVariables(const std::wstring& filename, CMeterWindow* meterWindow) { - if (pRainmeter) - { - SetBuiltInVariable(L"PROGRAMPATH", pRainmeter->GetPath()); - SetBuiltInVariable(L"PROGRAMDRIVE", pRainmeter->GetDrive()); - SetBuiltInVariable(L"SETTINGSPATH", pRainmeter->GetSettingsPath()); - SetBuiltInVariable(L"SKINSPATH", pRainmeter->GetSkinPath()); - SetBuiltInVariable(L"PLUGINSPATH", pRainmeter->GetPluginPath()); - SetBuiltInVariable(L"CURRENTPATH", CRainmeter::ExtractPath(m_Filename)); - SetBuiltInVariable(L"ADDONSPATH", pRainmeter->GetAddonPath()); - } + SetBuiltInVariable(L"PROGRAMPATH", Rainmeter->GetPath()); + SetBuiltInVariable(L"PROGRAMDRIVE", Rainmeter->GetDrive()); + SetBuiltInVariable(L"SETTINGSPATH", Rainmeter->GetSettingsPath()); + SetBuiltInVariable(L"SKINSPATH", Rainmeter->GetSkinPath()); + SetBuiltInVariable(L"PLUGINSPATH", Rainmeter->GetPluginPath()); + SetBuiltInVariable(L"CURRENTPATH", CRainmeter::ExtractPath(filename)); + SetBuiltInVariable(L"ADDONSPATH", Rainmeter->GetAddonPath()); + if (meterWindow) { SetBuiltInVariable(L"CURRENTFILE", meterWindow->GetSkinIniFile()); @@ -1152,7 +1155,7 @@ RECT CConfigParser::ParseRECT(LPCTSTR string) ** Reads the given ini file and fills the m_Values and m_Keys maps. ** */ -void CConfigParser::ReadIniFile(const std::wstring& iniFile, LPCTSTR config, int depth) +void CConfigParser::ReadIniFile(const std::wstring& iniFile, const std::wstring& resourcePath, LPCTSTR config, int depth) { if (depth > 100) // Is 100 enough to assume the include loop never ends? { @@ -1316,10 +1319,18 @@ void CConfigParser::ReadIniFile(const std::wstring& iniFile, LPCTSTR config, int ReplaceVariables(value); if (!CSystem::IsAbsolutePath(value)) { - // It's a relative path so add the current path as a prefix - value.insert(0, CRainmeter::ExtractPath(iniFile)); + if (!resourcePath.empty() && + value[0] == L'@' && value[1] == L'\\') // value[1] == L'\0' if value.size() == 1 + { + value.replace(0, 2, resourcePath); + } + else + { + // Relative to the ini folder + value.insert(0, CRainmeter::ExtractPath(iniFile)); + } } - ReadIniFile(value, config, depth + 1); + ReadIniFile(value, resourcePath, config, depth + 1); } } else diff --git a/Library/ConfigParser.h b/Library/ConfigParser.h index c8872da2..7c96caaa 100644 --- a/Library/ConfigParser.h +++ b/Library/ConfigParser.h @@ -40,7 +40,7 @@ public: CConfigParser(); ~CConfigParser(); - void Initialize(LPCTSTR filename, CRainmeter* pRainmeter, CMeterWindow* meterWindow = NULL, LPCTSTR config = NULL); + void Initialize(const std::wstring& filename, CMeterWindow* meterWindow = NULL, LPCTSTR config = NULL); void AddMeasure(CMeasure* pMeasure); bool GetVariable(const std::wstring& strVariable, std::wstring& strValue); @@ -81,7 +81,6 @@ public: bool ParseFormula(const std::wstring& formula, double* resultValue); - const std::wstring& GetFilename() { return m_Filename; } const std::list& GetSections() { return m_Sections; } bool ReplaceVariables(std::wstring& result); @@ -101,13 +100,13 @@ public: static void UpdateWorkareaVariables() { SetMultiMonitorVariables(false); } private: - void SetBuiltInVariables(CRainmeter* pRainmeter, CMeterWindow* meterWindow); + void SetBuiltInVariables(const std::wstring& filename, CMeterWindow* meterWindow); void ReadVariables(); CMeasure* GetMeasure(const std::wstring& name); - void ReadIniFile(const std::wstring& strFileName, LPCTSTR config = NULL, int depth = 0); + void ReadIniFile(const std::wstring& iniFile, const std::wstring& resourcePath, LPCTSTR config = NULL, int depth = 0); void SetAutoSelectedMonitorVariables(CMeterWindow* meterWindow); @@ -122,8 +121,6 @@ private: static std::wstring StrToUpper(const WCHAR* str) { std::wstring strTmp(str); StrToUpperC(strTmp); return strTmp; } static std::wstring& StrToUpperC(std::wstring& str) { _wcsupr(&str[0]); return str; } - std::wstring m_Filename; - std::unordered_map m_Measures; std::vector m_StyleTemplate; diff --git a/Library/DialogManage.cpp b/Library/DialogManage.cpp index 5cab538b..0f26b630 100644 --- a/Library/DialogManage.cpp +++ b/Library/DialogManage.cpp @@ -1429,7 +1429,7 @@ INT_PTR CDialogManage::CTabThemes::OnCommand(WPARAM wParam, LPARAM lParam) if (Button_GetCheck(item) == BST_CHECKED) { CConfigParser parser; - parser.Initialize(path.c_str(), Rainmeter); + parser.Initialize(path); // Remove sections with Active=0 std::list::const_iterator iter = parser.GetSections().begin(); diff --git a/Library/MeasureNet.cpp b/Library/MeasureNet.cpp index a251c9d7..1bbe4a28 100644 --- a/Library/MeasureNet.cpp +++ b/Library/MeasureNet.cpp @@ -569,12 +569,12 @@ void CMeasureNet::ResetStats() ** Reads statistics. ** */ -void CMeasureNet::ReadStats(const WCHAR* iniFile, std::wstring& statsDate) +void CMeasureNet::ReadStats(const std::wstring& iniFile, std::wstring& statsDate) { WCHAR buffer[48]; CConfigParser parser; - parser.Initialize(iniFile, NULL, NULL, L"Statistics"); + parser.Initialize(iniFile, NULL, L"Statistics"); const std::wstring& date = parser.ReadString(L"Statistics", L"Since", L"", false); if (!date.empty()) diff --git a/Library/MeasureNet.h b/Library/MeasureNet.h index 8be4fd56..1ec2d518 100644 --- a/Library/MeasureNet.h +++ b/Library/MeasureNet.h @@ -48,7 +48,7 @@ public: static void UpdateStats(); static void ResetStats(); - static void ReadStats(const WCHAR* iniFile, std::wstring& statsDate); + static void ReadStats(const std::wstring& iniFile, std::wstring& statsDate); static void WriteStats(const WCHAR* iniFile, const std::wstring& statsDate); static void InitializeNewApi(); diff --git a/Library/MeasurePlugin.cpp b/Library/MeasurePlugin.cpp index 457dcf09..fbb94b17 100644 --- a/Library/MeasurePlugin.cpp +++ b/Library/MeasurePlugin.cpp @@ -208,7 +208,7 @@ void CMeasurePlugin::ReadConfig(CConfigParser& parser, const WCHAR* section) if (initializeFunc) { - maxValue = ((INITIALIZE)initializeFunc)(m_Plugin, parser.GetFilename().c_str(), section, m_ID); + maxValue = ((INITIALIZE)initializeFunc)(m_Plugin, m_MeterWindow->GetSkinFilePath().c_str(), section, m_ID); } } diff --git a/Library/MeterWindow.cpp b/Library/MeterWindow.cpp index 3a402e76..667ca73a 100644 --- a/Library/MeterWindow.cpp +++ b/Library/MeterWindow.cpp @@ -137,6 +137,7 @@ CMeterWindow::CMeterWindow(const std::wstring& config, const std::wstring& iniFi m_Refreshing(false), m_Hidden(false), m_ResizeWindow(RESIZEMODE_NONE), + m_ResourcesFolder(false), m_UpdateCounter(), m_MouseMoveCounter(), m_FontCollection(), @@ -1801,7 +1802,7 @@ void CMeterWindow::ReadConfig() m_ConfigGroup.clear(); CConfigParser parser; - parser.Initialize(iniFile.c_str(), Rainmeter, NULL, m_SkinName.c_str()); + parser.Initialize(iniFile, NULL, m_SkinName.c_str()); for (int i = 0; i < 2; ++i) { @@ -1958,7 +1959,18 @@ bool CMeterWindow::ReadSkin() return false; } - m_Parser.Initialize(iniFile.c_str(), Rainmeter, this); + std::wstring::size_type suiteLen; + if ((suiteLen = m_SkinName.find_first_of(L'\\')) == std::wstring::npos) + { + suiteLen = m_SkinName.size(); + } + + std::wstring resourcePath = Rainmeter->GetSkinPath(); + resourcePath.append(m_SkinName, 0, suiteLen); + resourcePath += L"\\@Resources\\"; + m_ResourcesFolder = (_waccess(resourcePath.c_str(), 0) == 0); + + m_Parser.Initialize(iniFile, this); // Check the version UINT appVersion = m_Parser.ReadUInt(L"Rainmeter", L"AppVersion", 0); @@ -2052,8 +2064,7 @@ bool CMeterWindow::ReadSkin() { ResizeBlur(blurRegion, RGN_OR); - // Here we are checking to see if there are more than one blur region - // to be loaded. They will be named BlurRegion2, BlurRegion3, etc. + // Check for BlurRegion2, BlurRegion3, etc. _snwprintf_s(buffer, _TRUNCATE, L"BlurRegion%i", ++i); blurRegion = m_Parser.ReadString(L"Rainmeter", buffer, L"").c_str(); } @@ -2070,36 +2081,73 @@ bool CMeterWindow::ReadSkin() } } + // Load fonts in Resources folder + if (m_ResourcesFolder) + { + WIN32_FIND_DATA fd; + resourcePath += L"Fonts\\*"; + + HANDLE find = FindFirstFileEx( + resourcePath.c_str(), + (CSystem::GetOSPlatform() >= OSPLATFORM_7) ? FindExInfoBasic : FindExInfoStandard, + &fd, + FindExSearchNameMatch, + NULL, + 0); + + if (find != INVALID_HANDLE_VALUE) + { + m_FontCollection = new PrivateFontCollection(); + + do + { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + std::wstring file(resourcePath, 0, resourcePath.length() - 1); + file += fd.cFileName; + Status status = m_FontCollection->AddFontFile(file.c_str()); + if (status != Ok) + { + std::wstring error = L"Unable to load font: "; + error += file.c_str(); + Log(LOG_ERROR, error.c_str()); + } + } + } + while (FindNextFile(find, &fd)); + } + } + // Load local fonts const WCHAR* localFont = m_Parser.ReadString(L"Rainmeter", L"LocalFont", L"").c_str(); if (*localFont) { - m_FontCollection = new PrivateFontCollection(); - int i = 1; + if (!m_FontCollection) + { + m_FontCollection = new PrivateFontCollection(); + } + int i = 1; do { // Try program folder first std::wstring szFontFile = Rainmeter->GetPath() + L"Fonts\\"; szFontFile += localFont; - Status nResults = m_FontCollection->AddFontFile(szFontFile.c_str()); - - if (nResults != Ok) + Status status = m_FontCollection->AddFontFile(szFontFile.c_str()); + if (status != Ok) { szFontFile = localFont; MakePathAbsolute(szFontFile); - nResults = m_FontCollection->AddFontFile(szFontFile.c_str()); - - if (nResults != Ok) + status = m_FontCollection->AddFontFile(szFontFile.c_str()); + if (status != Ok) { - std::wstring error = L"Unable to load font file: "; + std::wstring error = L"Unable to load font: "; error += localFont; Log(LOG_ERROR, error.c_str()); } } - // Here we are checking to see if there are more than one local font - // to be loaded. They will be named LocalFont2, LocalFont3, etc. + // Check for LocalFont2, LocalFont3, etc. _snwprintf_s(buffer, _TRUNCATE, L"LocalFont%i", ++i); localFont = m_Parser.ReadString(L"Rainmeter", buffer, L"").c_str(); } @@ -4640,15 +4688,44 @@ void CMeterWindow::MakePathAbsolute(std::wstring& path) else { std::wstring absolute; - absolute.reserve(Rainmeter->GetSkinPath().size() + m_SkinName.size() + 1 + path.size()); - absolute = Rainmeter->GetSkinPath(); - absolute += m_SkinName; - absolute += L'\\'; - absolute += path; + + if (m_ResourcesFolder && (path[0] == L'@' && path[1] == L'\\')) // path[1] == L'\0' if path.size() == 1 + { + const std::wstring::size_type resourcesLen = 13; // Count of "\\@Resources\\" + + std::wstring::size_type suiteLen; + if ((suiteLen = m_SkinName.find_first_of(L'\\')) == std::wstring::npos) + { + suiteLen = m_SkinName.size(); + } + + absolute.reserve(Rainmeter->GetSkinPath().size() + suiteLen + resourcesLen + (path.size() - 2)); + absolute = Rainmeter->GetSkinPath(); + absolute.append(m_SkinName, 0, suiteLen); + absolute += L"\\@Resources\\"; + absolute.append(path, 2, path.length() - 1); + } + else + { + absolute.reserve(Rainmeter->GetSkinPath().size() + m_SkinName.size() + 1 + path.size()); + absolute = Rainmeter->GetSkinPath(); + absolute += m_SkinName; + absolute += L'\\'; + absolute += path; + } + absolute.swap(path); } } +std::wstring CMeterWindow::GetSkinFilePath() +{ + std::wstring file = Rainmeter->GetSkinPath() + m_SkinName; + file += L'\\'; + file += m_SkinIniFile; + return file; +} + std::wstring CMeterWindow::GetSkinRootPath() { std::wstring path = Rainmeter->GetSkinPath(); diff --git a/Library/MeterWindow.h b/Library/MeterWindow.h index ca3b638d..9a0ad131 100644 --- a/Library/MeterWindow.h +++ b/Library/MeterWindow.h @@ -203,6 +203,7 @@ public: const std::wstring& GetSkinName() { return m_SkinName; } const std::wstring& GetSkinIniFile() { return m_SkinIniFile; } + std::wstring GetSkinFilePath(); std::wstring GetSkinRootPath(); std::list& GetMeasures() { return m_Measures; } @@ -450,6 +451,8 @@ private: const std::wstring m_SkinName; // Name of the current skin folder const std::wstring m_SkinIniFile; // Name of the current skin iniFile + bool m_ResourcesFolder; + int m_UpdateCounter; UINT m_MouseMoveCounter; diff --git a/Library/Rainmeter.cpp b/Library/Rainmeter.cpp index 98904d85..fa740ee3 100644 --- a/Library/Rainmeter.cpp +++ b/Library/Rainmeter.cpp @@ -1552,10 +1552,10 @@ void CRainmeter::ScanForConfigs(const std::wstring& path) m_ConfigMenu.clear(); m_ConfigOrders.clear(); - ScanForConfigsRecursive(path, L"", 0, m_ConfigMenu, false); + ScanForConfigsRecursive(path, L"", 0, m_ConfigMenu); } -int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector& menu, bool DontRecurse) +int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector& menu, bool rootSkinFolder) { WIN32_FIND_DATA fileData; // Data structure describes the file found HANDLE hSearch; // Search handle returned by FindFirstFile @@ -1589,7 +1589,8 @@ int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring b { if (wcscmp(L".", fileData.cFileName) != 0 && wcscmp(L"..", fileData.cFileName) != 0 && - !(first && wcscmp(L"Backup", fileData.cFileName) == 0)) // Skip the backup folder + !(first && wcscmp(L"Backup", fileData.cFileName) == 0) && + !(rootSkinFolder && wcscmp(L"@Resources", fileData.cFileName) == 0)) { folders.push_back(filename); } @@ -1635,16 +1636,13 @@ int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring b menuItem.index = -1; menu.push_back(std::move(menuItem)); - if (!DontRecurse) - { - std::vector::iterator iter2 = menu.end() - 1; - index = ScanForConfigsRecursive(path, base + (*iter), index, (*iter2).children, false); + std::vector::iterator iter2 = menu.end() - 1; + index = ScanForConfigsRecursive(path, base + (*iter), index, (*iter2).children, base.empty()); - // Remove menu item if it has no child - if ((*iter2).children.empty()) - { - menu.erase(iter2); - } + // Remove menu item if it has no child + if ((*iter2).children.empty()) + { + menu.erase(iter2); } } @@ -2169,7 +2167,7 @@ void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile) m_DesktopWorkAreas.clear(); CConfigParser parser; - parser.Initialize(iniFile.c_str(), this); + parser.Initialize(iniFile, NULL, NULL); // Read Logging settings m_Logging = 0!=parser.ReadInt(L"Rainmeter", L"Logging", 0); @@ -2567,7 +2565,7 @@ void CRainmeter::ReadStats() } // Only Net measure has stats at the moment - CMeasureNet::ReadStats(statsFile, m_StatsDate); + CMeasureNet::ReadStats(m_StatsFile, m_StatsDate); } /* diff --git a/Library/Rainmeter.h b/Library/Rainmeter.h index 4dde033b..53ef769e 100644 --- a/Library/Rainmeter.h +++ b/Library/Rainmeter.h @@ -258,7 +258,7 @@ private: void UpdateDesktopWorkArea(bool reset); HMENU CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu); void ChangeSkinIndex(HMENU subMenu, int index); - int ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector& menu, bool DontRecurse); + int ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector& menu, bool rootSkinFolder = false); HMENU CreateConfigMenu(HMENU configMenu, const std::vector& configMenuData); void CreateThemeMenu(HMENU themeMenu); void CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow);