2014-08-01 19:54:35 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2001 Kimmo Pekkola
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2014-08-12 13:38:37 +00:00
|
|
|
*/
|
2014-08-01 19:54:35 +00:00
|
|
|
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../Common/PathUtil.h"
|
|
|
|
#include "Rainmeter.h"
|
|
|
|
#include "System.h"
|
|
|
|
#include "Error.h"
|
|
|
|
#include "MeasureNet.h"
|
|
|
|
#include "MeasureCPU.h"
|
|
|
|
#include "MeterString.h"
|
|
|
|
#include "../Version.h"
|
|
|
|
|
|
|
|
using namespace Gdiplus;
|
|
|
|
|
|
|
|
enum TIMER
|
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
TIMER_NETSTATS = 1
|
2014-08-01 19:54:35 +00:00
|
|
|
};
|
|
|
|
enum INTERVAL
|
|
|
|
{
|
|
|
|
INTERVAL_NETSTATS = 120000
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Constructor
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
Rainmeter::Rainmeter() :
|
2014-08-12 13:38:37 +00:00
|
|
|
m_UseD2D(true),
|
|
|
|
m_Debug(false),
|
|
|
|
m_DesktopWorkAreaChanged(false),
|
|
|
|
m_DesktopWorkAreaType(false),
|
|
|
|
m_NormalStayDesktop(true),
|
|
|
|
m_DisableDragging(false),
|
|
|
|
m_CurrentParser(),
|
|
|
|
m_Window(),
|
|
|
|
m_Mutex(),
|
|
|
|
m_Instance(),
|
|
|
|
m_GDIplusToken(),
|
|
|
|
m_GlobalOptions()
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
|
|
|
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
|
|
|
|
|
|
|
InitCommonControls();
|
|
|
|
|
|
|
|
// Initialize GDI+.
|
|
|
|
GdiplusStartupInput gdiplusStartupInput;
|
|
|
|
GdiplusStartup(&m_GDIplusToken, &gdiplusStartupInput, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Destructor
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
Rainmeter::~Rainmeter()
|
|
|
|
{
|
|
|
|
CoUninitialize();
|
|
|
|
|
|
|
|
GdiplusShutdown(m_GDIplusToken);
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
Rainmeter& Rainmeter::GetInstance()
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
|
|
|
static Rainmeter s_Rainmeter;
|
|
|
|
return s_Rainmeter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** The main initialization function for the module.
|
|
|
|
**
|
|
|
|
*/
|
2014-08-12 13:38:37 +00:00
|
|
|
int Rainmeter::Initialize()
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
|
|
|
m_Instance = GetModuleHandle(L"Rainmeter");
|
2014-08-12 13:38:37 +00:00
|
|
|
m_UseCurrentDirectory = true;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Create a window
|
2014-08-01 19:54:35 +00:00
|
|
|
WNDCLASS wc = {0};
|
2014-08-12 13:38:37 +00:00
|
|
|
wc.lpfnWndProc = (WNDPROC) MainWndProc;
|
2014-08-01 19:54:35 +00:00
|
|
|
wc.hInstance = m_Instance;
|
|
|
|
wc.lpszClassName = RAINMETER_CLASS_NAME;
|
|
|
|
ATOM className = RegisterClass(&wc);
|
|
|
|
|
|
|
|
m_Window = CreateWindowEx(
|
|
|
|
WS_EX_TOOLWINDOW,
|
|
|
|
MAKEINTATOM(className),
|
|
|
|
RAINMETER_WINDOW_NAME,
|
|
|
|
WS_POPUP | WS_DISABLED,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
m_Instance,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
if (!m_Window) return 1;
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Set up logger
|
2014-08-01 19:54:35 +00:00
|
|
|
Logger& logger = GetLogger();
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// TODO: figure if we need language library
|
2014-08-01 19:54:35 +00:00
|
|
|
|
|
|
|
// Create user skins, layouts, addons, and plugins folders if needed
|
2014-08-12 13:38:37 +00:00
|
|
|
LogNoticeF(L"Path: %s", GetWorkDirectory().c_str());
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Initialize static stuff
|
2014-08-01 19:54:35 +00:00
|
|
|
System::Initialize(m_Instance);
|
|
|
|
|
|
|
|
MeasureNet::InitializeStatic();
|
|
|
|
MeasureCPU::InitializeStatic();
|
|
|
|
MeterString::InitializeStatic();
|
|
|
|
|
|
|
|
ResetStats();
|
|
|
|
ReadStats();
|
|
|
|
|
|
|
|
// Change the work area if necessary
|
|
|
|
if (m_DesktopWorkAreaChanged)
|
|
|
|
{
|
|
|
|
UpdateDesktopWorkArea(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; // All is OK
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::Finalize()
|
|
|
|
{
|
|
|
|
KillTimer(m_Window, TIMER_NETSTATS);
|
|
|
|
|
|
|
|
DeleteAllUnmanagedMeterWindows();
|
|
|
|
DeleteAllMeterWindows();
|
|
|
|
DeleteAllUnmanagedMeterWindows(); // Redelete unmanaged windows caused by OnCloseAction
|
|
|
|
|
|
|
|
System::Finalize();
|
|
|
|
|
|
|
|
MeasureNet::UpdateIFTable();
|
|
|
|
MeasureNet::UpdateStats();
|
|
|
|
WriteStats(true);
|
|
|
|
|
|
|
|
MeasureNet::FinalizeStatic();
|
|
|
|
MeasureCPU::FinalizeStatic();
|
|
|
|
MeterString::FinalizeStatic();
|
|
|
|
|
|
|
|
// Change the work area back
|
|
|
|
if (m_DesktopWorkAreaChanged)
|
|
|
|
{
|
|
|
|
UpdateDesktopWorkArea(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Mutex) ReleaseMutex(m_Mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Rainmeter::MessagePump()
|
|
|
|
{
|
|
|
|
MSG msg;
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
// Run the standard window message loop
|
|
|
|
while ((ret = GetMessage(&msg, nullptr, 0, 0)) != 0)
|
|
|
|
{
|
|
|
|
if (ret == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
return (int) msg.wParam;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CALLBACK Rainmeter::MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (uMsg)
|
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_DESTROY:
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_COPYDATA:
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
COPYDATASTRUCT* cds = (COPYDATASTRUCT*) lParam;
|
2014-08-01 19:54:35 +00:00
|
|
|
if (cds)
|
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
const WCHAR* data = (const WCHAR*) cds->lpData;
|
2014-08-01 19:54:35 +00:00
|
|
|
if (cds->dwData == 1 && (cds->cbData > 0))
|
|
|
|
{
|
|
|
|
GetRainmeter().DelayedExecuteCommand(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_TIMER:
|
|
|
|
if (wParam == TIMER_NETSTATS)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
MeasureNet::UpdateIFTable();
|
|
|
|
MeasureNet::UpdateStats();
|
|
|
|
GetRainmeter().WriteStats(false);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_RAINMETER_DELAYED_REFRESH_ALL:
|
|
|
|
GetRainmeter().RefreshAll();
|
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_RAINMETER_DELAYED_EXECUTE:
|
|
|
|
if (lParam)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// Execute bang
|
|
|
|
WCHAR* bang = (WCHAR*) lParam;
|
|
|
|
GetRainmeter().ExecuteCommand(bang, nullptr);
|
|
|
|
free(bang); // _wcsdup()
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
case WM_RAINMETER_EXECUTE:
|
|
|
|
if (GetRainmeter().HasMeterWindow((MeterWindow*) wParam))
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
GetRainmeter().ExecuteCommand((const WCHAR*) lParam, (MeterWindow*) wParam);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
break;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
default:
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
return 0;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::SetNetworkStatisticsTimer()
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
static bool set = SetTimer(m_Window, TIMER_NETSTATS, INTERVAL_NETSTATS, nullptr) != 0;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::ActivateSkin(std::wstring file)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
file = NormalizePath(file);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Verify that the skin is not already active
|
|
|
|
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.find(file);
|
|
|
|
if (iter != m_MeterWindows.end())
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
if (wcscmp(((*iter).second)->GetFileName().c_str(), file.c_str()) == 0)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
LogWarningF((*iter).second, L"!ActivateConfig: \"%s\" already active", file.c_str());
|
|
|
|
return;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
else
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// Deactivate the existing skin
|
|
|
|
DeactivateSkin((*iter).second);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Verify whether the ini-file exists
|
|
|
|
if (_waccess(file.c_str(), 0) == -1)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
throw std::exception("Skin file not found");
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
CreateMeterWindow(file);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::DeactivateSkin(MeterWindow* meterWindow)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
|
|
|
if (meterWindow)
|
|
|
|
{
|
|
|
|
meterWindow->Deactivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::ToggleSkin(std::wstring file)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
file = GetAbsolutePath(file);
|
|
|
|
std::wstring folder = PathUtil::GetFolderFromFilePath(file);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
MeterWindow* meterWindow = GetMeterWindow(file);
|
|
|
|
|
|
|
|
if (meterWindow)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
DeactivateSkin(meterWindow);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
else
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
ActivateSkin(file);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::CreateMeterWindow(std::wstring file)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
file = NormalizePath(file);
|
|
|
|
std::wstring folder = PathUtil::GetFolderFromFilePath(file);
|
|
|
|
MeterWindow* mw = new MeterWindow(folder, file.substr(folder.size())); //TODO: temporary workaround
|
2014-08-01 19:54:35 +00:00
|
|
|
|
|
|
|
// Note: May modify existing key
|
2014-08-12 13:38:37 +00:00
|
|
|
m_MeterWindows[file] = mw;
|
2014-08-01 19:54:35 +00:00
|
|
|
|
|
|
|
mw->Initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::DeleteAllMeterWindows()
|
|
|
|
{
|
|
|
|
auto it = m_MeterWindows.cbegin();
|
|
|
|
while (it != m_MeterWindows.cend())
|
|
|
|
{
|
|
|
|
MeterWindow* mw = (*it).second;
|
|
|
|
m_MeterWindows.erase(it); // Remove before deleting MeterWindow
|
|
|
|
|
|
|
|
delete mw;
|
|
|
|
|
|
|
|
// Get next valid iterator (Fix for iterator invalidation caused by OnCloseAction)
|
|
|
|
it = m_MeterWindows.cbegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_MeterWindows.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::DeleteAllUnmanagedMeterWindows()
|
|
|
|
{
|
|
|
|
for (auto it = m_UnmanagedMeterWindows.cbegin(); it != m_UnmanagedMeterWindows.cend(); ++it)
|
|
|
|
{
|
|
|
|
delete (*it);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_UnmanagedMeterWindows.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Removes the skin from m_MeterWindows. The skin should delete itself.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::RemoveMeterWindow(MeterWindow* meterWindow)
|
|
|
|
{
|
|
|
|
for (auto it = m_MeterWindows.cbegin(); it != m_MeterWindows.cend(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it).second == meterWindow)
|
|
|
|
{
|
|
|
|
m_MeterWindows.erase(it);
|
2014-08-12 13:38:37 +00:00
|
|
|
return;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Adds the skin to m_UnmanagedMeterWindows. The skin should remove itself by calling RemoveUnmanagedMeterWindow().
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::AddUnmanagedMeterWindow(MeterWindow* meterWindow)
|
|
|
|
{
|
|
|
|
for (auto it = m_UnmanagedMeterWindows.cbegin(); it != m_UnmanagedMeterWindows.cend(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it) == meterWindow) // already added
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_UnmanagedMeterWindows.push_back(meterWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::RemoveUnmanagedMeterWindow(MeterWindow* meterWindow)
|
|
|
|
{
|
|
|
|
for (auto it = m_UnmanagedMeterWindows.cbegin(); it != m_UnmanagedMeterWindows.cend(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it) == meterWindow)
|
|
|
|
{
|
|
|
|
m_UnmanagedMeterWindows.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Rainmeter::HasMeterWindow(const MeterWindow* meterWindow) const
|
|
|
|
{
|
|
|
|
for (auto it = m_MeterWindows.begin(); it != m_MeterWindows.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it).second == meterWindow)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
MeterWindow* Rainmeter::GetMeterWindow(const std::wstring& filePath)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
std::wstring filePathLower;
|
|
|
|
std::transform(filePath.begin(), filePath.end(), filePathLower.begin(), ::tolower);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
if (m_MeterWindows.count(filePathLower) > 0)
|
|
|
|
return m_MeterWindows.at(filePathLower);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MeterWindow* Rainmeter::GetMeterWindow(HWND hwnd)
|
|
|
|
{
|
|
|
|
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.begin();
|
|
|
|
for (; iter != m_MeterWindows.end(); ++iter)
|
|
|
|
{
|
|
|
|
if ((*iter).second->GetWindow() == hwnd)
|
|
|
|
{
|
|
|
|
return (*iter).second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::GetMeterWindowsByLoadOrder(std::multimap<int, MeterWindow*>& windows, const std::wstring& group)
|
|
|
|
{
|
|
|
|
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.begin();
|
|
|
|
for (; iter != m_MeterWindows.end(); ++iter)
|
|
|
|
{
|
|
|
|
MeterWindow* mw = (*iter).second;
|
|
|
|
if (mw && (group.empty() || mw->BelongsToGroup(group)))
|
|
|
|
{
|
|
|
|
windows.insert(std::pair<int, MeterWindow*>(GetLoadOrder((*iter).first), mw));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::SetLoadOrder(const std::wstring& file, int order)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
for (auto iter = m_SkinOrders.begin(); iter != m_SkinOrders.end(); ++iter)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
if ((*iter).second == file) // already exists
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
|
|
|
if ((*iter).first != order)
|
|
|
|
{
|
|
|
|
m_SkinOrders.erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
m_SkinOrders.insert(std::make_pair(order, file));
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
int Rainmeter::GetLoadOrder(const std::wstring& filePath)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
for (auto pair : m_SkinOrders)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
if (pair.second == filePath)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
return pair.first;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
|
2014-08-01 19:54:35 +00:00
|
|
|
// LoadOrder not specified
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::ExecuteBang(const WCHAR* bang, std::vector<std::wstring>& args, MeterWindow* meterWindow)
|
|
|
|
{
|
|
|
|
m_CommandHandler.ExecuteBang(bang, args, meterWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Runs the given command or bang
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::ExecuteCommand(const WCHAR* command, MeterWindow* meterWindow, bool multi)
|
|
|
|
{
|
|
|
|
m_CommandHandler.ExecuteCommand(command, meterWindow, multi);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Executes command when current processing is done.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::DelayedExecuteCommand(const WCHAR* command)
|
|
|
|
{
|
|
|
|
WCHAR* bang = _wcsdup(command);
|
2014-08-12 13:38:37 +00:00
|
|
|
PostMessage(m_Window, WM_RAINMETER_DELAYED_EXECUTE, (WPARAM)nullptr, (LPARAM) bang);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-08-12 13:38:37 +00:00
|
|
|
** Refreshes all active meter windows.
|
|
|
|
** Note: This function calls MeterWindow::Refresh() directly for synchronization. Be careful about crash.
|
2014-08-01 19:54:35 +00:00
|
|
|
**
|
|
|
|
*/
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::RefreshAll()
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// Read skins and settings
|
|
|
|
LoadLayout();
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Change the work area if necessary
|
|
|
|
if (m_DesktopWorkAreaChanged)
|
|
|
|
{
|
|
|
|
UpdateDesktopWorkArea(false);
|
|
|
|
}
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Make the sending order by using LoadOrder
|
|
|
|
std::multimap<int, MeterWindow*> windows;
|
|
|
|
GetMeterWindowsByLoadOrder(windows);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Prepare the helper window
|
|
|
|
System::PrepareHelperWindow();
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Refresh all
|
|
|
|
std::multimap<int, MeterWindow*>::const_iterator iter = windows.begin();
|
|
|
|
for (; iter != windows.end(); ++iter)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
MeterWindow* mw = (*iter).second;
|
|
|
|
if (mw)
|
|
|
|
{
|
|
|
|
mw->Refresh(false, true);
|
|
|
|
}
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
}
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
bool Rainmeter::LoadLayout(std::wstring filename)
|
|
|
|
{
|
|
|
|
if (filename.empty())
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
filename = m_LayoutFile;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
if (_waccess(filename.c_str(), 0) == -1)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
return false;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Unload current meters
|
|
|
|
DeleteAllUnmanagedMeterWindows();
|
|
|
|
DeleteAllMeterWindows();
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Load layout file
|
|
|
|
WCHAR buffer[MAX_PATH];
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Clear old settings
|
|
|
|
m_DesktopWorkAreas.clear();
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
ConfigParser parser;
|
|
|
|
parser.Initialize(filename, nullptr, nullptr);
|
|
|
|
|
|
|
|
// Read desktop work area settings
|
2014-08-01 19:54:35 +00:00
|
|
|
const std::wstring& area = parser.ReadString(L"Rainmeter", L"DesktopWorkArea", L"");
|
|
|
|
if (!area.empty())
|
|
|
|
{
|
|
|
|
m_DesktopWorkAreas[0] = parser.ParseRECT(area.c_str());
|
|
|
|
m_DesktopWorkAreaChanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const size_t monitorCount = System::GetMonitorCount();
|
|
|
|
for (UINT i = 1; i <= monitorCount; ++i)
|
|
|
|
{
|
|
|
|
_snwprintf_s(buffer, _TRUNCATE, L"DesktopWorkArea@%i", (int)i);
|
|
|
|
const std::wstring& area = parser.ReadString(L"Rainmeter", buffer, L"");
|
|
|
|
if (!area.empty())
|
|
|
|
{
|
|
|
|
m_DesktopWorkAreas[i] = parser.ParseRECT(area.c_str());
|
|
|
|
m_DesktopWorkAreaChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_DesktopWorkAreaType = parser.ReadBool(L"Rainmeter", L"DesktopWorkAreaType", false);
|
|
|
|
|
|
|
|
for (auto iter = parser.GetSections().cbegin(); iter != parser.GetSections().end(); ++iter)
|
|
|
|
{
|
|
|
|
const WCHAR* section = (*iter).c_str();
|
|
|
|
|
|
|
|
if (wcscmp(section, L"Rainmeter") == 0 ||
|
|
|
|
wcscmp(section, L"TrayMeasure") == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
|
2014-08-01 19:54:35 +00:00
|
|
|
// Make sure there is a ini file available
|
|
|
|
int active = parser.ReadInt(section, L"Active", 0);
|
2014-08-12 13:38:37 +00:00
|
|
|
if (active > 0)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// TODO: fix, get 'active'th file from *iter folder
|
|
|
|
ActivateSkin(*iter);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// TODO: activate using 'order'
|
|
|
|
int order = parser.ReadInt(section, L"LoadOrder", 0);
|
|
|
|
SetLoadOrder(*iter, order);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Applies given DesktopWorkArea and DesktopWorkArea@n.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::UpdateDesktopWorkArea(bool reset)
|
|
|
|
{
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
if (reset)
|
|
|
|
{
|
|
|
|
if (!m_OldDesktopWorkAreas.empty())
|
|
|
|
{
|
|
|
|
int i = 1;
|
|
|
|
for (auto iter = m_OldDesktopWorkAreas.cbegin(); iter != m_OldDesktopWorkAreas.cend(); ++iter, ++i)
|
|
|
|
{
|
|
|
|
RECT r = (*iter);
|
|
|
|
|
|
|
|
BOOL result = SystemParametersInfo(SPI_SETWORKAREA, 0, &r, 0);
|
|
|
|
|
|
|
|
if (m_Debug)
|
|
|
|
{
|
|
|
|
std::wstring format = L"Resetting WorkArea@%i: L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)";
|
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
format += L" => FAIL";
|
|
|
|
}
|
|
|
|
LogDebugF(format.c_str(), i, r.left, r.top, r.right, r.bottom, r.right - r.left, r.bottom - r.top);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const size_t numOfMonitors = System::GetMonitorCount();
|
|
|
|
const MultiMonitorInfo& monitorsInfo = System::GetMultiMonitorInfo();
|
|
|
|
const std::vector<MonitorInfo>& monitors = monitorsInfo.monitors;
|
|
|
|
|
|
|
|
if (m_OldDesktopWorkAreas.empty())
|
|
|
|
{
|
|
|
|
// Store old work areas for changing them back
|
|
|
|
for (size_t i = 0; i < numOfMonitors; ++i)
|
|
|
|
{
|
|
|
|
m_OldDesktopWorkAreas.push_back(monitors[i].work);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Debug)
|
|
|
|
{
|
|
|
|
LogDebugF(L"DesktopWorkAreaType: %s", m_DesktopWorkAreaType ? L"Margin" : L"Default");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (UINT i = 0; i <= numOfMonitors; ++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[monitorsInfo.primary - 1].screen : monitors[i - 1].screen;
|
|
|
|
r.left += margin.left;
|
|
|
|
r.top += margin.top;
|
|
|
|
r.right -= margin.right;
|
|
|
|
r.bottom -= margin.bottom;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
const RECT screenRect = monitors[i - 1].screen;
|
|
|
|
r.left += screenRect.left;
|
|
|
|
r.top += screenRect.top;
|
|
|
|
r.right += screenRect.left;
|
|
|
|
r.bottom += screenRect.top;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL result = SystemParametersInfo(SPI_SETWORKAREA, 0, &r, 0);
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Debug)
|
|
|
|
{
|
|
|
|
std::wstring format = L"Applying DesktopWorkArea";
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
WCHAR buffer[64];
|
|
|
|
size_t len = _snwprintf_s(buffer, _TRUNCATE, L"@%i", i);
|
|
|
|
format.append(buffer, len);
|
|
|
|
}
|
|
|
|
format += L": L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)";
|
|
|
|
if (!result)
|
|
|
|
{
|
|
|
|
format += L" => FAIL";
|
|
|
|
}
|
|
|
|
LogDebugF(format.c_str(), r.left, r.top, r.right, r.bottom, r.right - r.left, r.bottom - r.top);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed && System::GetWindow())
|
|
|
|
{
|
|
|
|
// Update System::MultiMonitorInfo for for work area variables
|
|
|
|
SendMessageTimeout(System::GetWindow(), WM_SETTINGCHANGE, SPI_SETWORKAREA, 0, SMTO_ABORTIFHUNG, 1000, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Reads the statistics from the ini-file
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::ReadStats()
|
|
|
|
{
|
|
|
|
const WCHAR* statsFile = m_StatsFile.c_str();
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// If m_StatsFile doesn't exist, create it
|
2014-08-01 19:54:35 +00:00
|
|
|
if (_waccess(statsFile, 0) == -1)
|
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
WritePrivateProfileSection(L"Statistics", L"", statsFile);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only Net measure has stats at the moment
|
|
|
|
MeasureNet::ReadStats(m_StatsFile, m_StatsDate);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Writes the statistics to the ini-file. If bForce is false the stats are written only once per an appropriate interval.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::WriteStats(bool bForce)
|
|
|
|
{
|
|
|
|
static ULONGLONG lastWrite = 0;
|
|
|
|
|
|
|
|
ULONGLONG ticks = System::GetTickCount64();
|
|
|
|
|
|
|
|
if (bForce || (lastWrite + INTERVAL_NETSTATS < ticks))
|
|
|
|
{
|
|
|
|
lastWrite = ticks;
|
|
|
|
|
|
|
|
// Only Net measure has stats at the moment
|
|
|
|
const WCHAR* statsFile = m_StatsFile.c_str();
|
|
|
|
MeasureNet::WriteStats(statsFile, m_StatsDate);
|
|
|
|
|
|
|
|
WritePrivateProfileString(nullptr, nullptr, nullptr, statsFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Clears the statistics
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
void Rainmeter::ResetStats()
|
|
|
|
{
|
|
|
|
// Set the stats-date string
|
|
|
|
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
|
|
|
|
MeasureNet::ResetStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rainmeter::SetDisableDragging(bool dragging)
|
|
|
|
{
|
|
|
|
m_DisableDragging = dragging;
|
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
void Rainmeter::SetUseD2D(bool enabled)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
m_UseD2D = enabled;
|
|
|
|
|
|
|
|
RefreshAll();
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
std::wstring Rainmeter::GetAbsolutePath(const std::wstring& path)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
if (!PathUtil::IsAbsolute(path))
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
WCHAR buffer[MAX_PATH];
|
|
|
|
std::wstring workdir = GetWorkDirectory();
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Work directory not absolute
|
|
|
|
if (!PathUtil::IsAbsolute(workdir))
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// Get current directory
|
|
|
|
WCHAR currentdir[MAX_PATH];
|
|
|
|
GetCurrentDirectory(MAX_PATH, currentdir);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Get absolute work directory
|
|
|
|
PathCombine(buffer, currentdir, workdir.c_str());
|
|
|
|
workdir.assign(buffer);
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Combine
|
|
|
|
PathCombine(buffer, workdir.c_str(), path.c_str());
|
|
|
|
|
|
|
|
return buffer;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
2014-08-12 13:38:37 +00:00
|
|
|
|
|
|
|
return path;
|
2014-08-01 19:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
std::wstring Rainmeter::NormalizePath(const std::wstring& path)
|
2014-08-01 19:54:35 +00:00
|
|
|
{
|
2014-08-12 13:38:37 +00:00
|
|
|
// Convert to absolute
|
|
|
|
std::wstring res = GetAbsolutePath(path);
|
|
|
|
|
|
|
|
// To lower
|
|
|
|
std::transform(res.begin(), res.end(), res.begin(), ::towlower);
|
2014-08-01 19:54:35 +00:00
|
|
|
|
2014-08-12 13:38:37 +00:00
|
|
|
// Return
|
|
|
|
return res;
|
|
|
|
}
|