mirror of
				https://github.com/chibicitiberiu/rainmeter-studio.git
				synced 2024-02-24 04:33:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2831 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2831 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|   Copyright (C) 2001 Kimmo Pekkola
 | |
| 
 | |
|   This program is free software; you can redistribute it and/or
 | |
|   modify it under the terms of the GNU General Public License
 | |
|   as published by the Free Software Foundation; either version 2
 | |
|   of the License, or (at your option) any later version.
 | |
| 
 | |
|   This program is distributed in the hope that it will be useful,
 | |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|   GNU General Public License for more details.
 | |
| 
 | |
|   You should have received a copy of the GNU General Public License
 | |
|   along with this program; if not, write to the Free Software
 | |
|   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | |
| */
 | |
| /*
 | |
|   $Header: /home/cvsroot/Rainmeter/Library/MeterWindow.cpp,v 1.1.1.1 2005/07/10 18:51:06 rainy Exp $
 | |
| 
 | |
|   $Log: MeterWindow.cpp,v $
 | |
|   Revision 1.1.1.1  2005/07/10 18:51:06  rainy
 | |
|   no message
 | |
| 
 | |
|   Revision 1.26  2004/08/13 15:47:45  rainy
 | |
|   Fixed z-position changing.
 | |
|   Mouse move events work for non-movable windows too.
 | |
| 
 | |
|   Revision 1.25  2004/07/11 17:19:29  rainy
 | |
|   Changed messageboxes to logs.
 | |
|   Mouse leave checks transparent pixels.
 | |
|   Added !RainmeterToggleConfig.
 | |
| 
 | |
|   Revision 1.24  2004/06/05 10:55:54  rainy
 | |
|   Too much changes to be listed in here...
 | |
| 
 | |
|   Revision 1.23  2004/03/13 16:19:17  rainy
 | |
|   Added support for multiple configs
 | |
| 
 | |
|   Revision 1.22  2003/12/05 15:50:10  Rainy
 | |
|   Multi-instance changes.
 | |
| 
 | |
|   Revision 1.21  2003/02/10 18:11:33  rainy
 | |
|   Too much changes to mention :-)
 | |
| 
 | |
|   Revision 1.20  2002/12/23 14:25:21  rainy
 | |
|   Separated skin and other settings.
 | |
|   Stats are now written in ini file.
 | |
| 
 | |
|   Revision 1.19  2002/07/01 15:27:36  rainy
 | |
|   AlwaysOnTop gets now three values.
 | |
|   Added Toggle().
 | |
|   Added RainmeterCurrentConfig and RainmeterCurrentConfigIni.
 | |
|   The ini file's timestamp is checked before it is overwritten.
 | |
|   AboutBox is now in separate source file.
 | |
|   Added SnapEdges.
 | |
| 
 | |
|   Revision 1.18  2002/05/05 10:48:56  rainy
 | |
|   Fixed few bugs.
 | |
| 
 | |
|   Revision 1.17  2002/05/04 08:16:35  rainy
 | |
|   There can be any number of ini files in the config folders.
 | |
|   WM_COPYDATA can be used to deliver the bangs.
 | |
|   Added support for per meter actions.
 | |
| 
 | |
|   Revision 1.16  2002/04/27 10:27:42  rainy
 | |
|   Added hide/show to meters and enable/disable to measures
 | |
| 
 | |
|   Revision 1.15  2002/04/01 15:36:10  rainy
 | |
|   Added PLAY, PLAYSTOP and PLAYLOOP build-in commands.
 | |
| 
 | |
|   Revision 1.14  2002/03/31 09:58:53  rainy
 | |
|   Added some comments
 | |
| 
 | |
|   Revision 1.13  2002/03/29 16:32:58  rainy
 | |
|   Fixed a typo
 | |
| 
 | |
|   Revision 1.12  2002/01/16 16:06:29  rainy
 | |
|   The file doesn't need to be named Rainmeter.ini anymore.
 | |
|   If the old config doesn't exist, we'll yse the first one instead.
 | |
| 
 | |
|   Revision 1.11  2001/12/23 10:14:09  rainy
 | |
|   Added support for different configs.
 | |
|   The position of the window is now remembered.
 | |
| 
 | |
|   Revision 1.10  2001/10/28 10:15:21  rainy
 | |
|   Added left and right mouse up actions.
 | |
|   IsNT() can now identify different OS more precisely.
 | |
| 
 | |
|   Revision 1.9  2001/10/14 07:27:58  rainy
 | |
|   Changed the errorhandling.
 | |
|   Stats now include the date when they were started to collect.
 | |
| 
 | |
|   Revision 1.8  2001/09/26 16:25:44  rainy
 | |
|   Added support for statistics.
 | |
|   Meters and Measures are now stored here.
 | |
| 
 | |
|   Revision 1.7  2001/09/01 12:57:13  rainy
 | |
|   Added support for Bar and Bitmap meters.
 | |
| 
 | |
|   Revision 1.6  2001/08/25 18:08:34  rainy
 | |
|   Added mousebutton actions.
 | |
|   The About dialog has now the build date.
 | |
| 
 | |
|   Revision 1.5  2001/08/25 17:15:52  rainy
 | |
|   Added context menu, which can show the about dialog, refresh the configuration or quit the program.
 | |
|   The ini-file can be defined in the step.rc also.
 | |
| 
 | |
|   Revision 1.4  2001/08/19 09:43:29  rainy
 | |
|   Mouse over hid the window even if it was not wanted.
 | |
| 
 | |
|   Revision 1.3  2001/08/19 09:12:12  rainy
 | |
|   Added support for GetRevID.
 | |
|   Added StartHidden.
 | |
| 
 | |
|   Revision 1.2  2001/08/12 15:36:55  Rainy
 | |
|   The ini-file's exsistance is checked.
 | |
|   Added String meter.
 | |
|   Improved mouse over hiding.
 | |
| 
 | |
|   Revision 1.1.1.1  2001/08/11 10:58:19  Rainy
 | |
|   Added to CVS.
 | |
| 
 | |
| */
 | |
| 
 | |
| #pragma warning(disable: 4786)
 | |
| #pragma warning(disable: 4996)
 | |
| 
 | |
| #include <windows.h>
 | |
| #include <gdiplus.h>
 | |
| #include "MeterWindow.h"
 | |
| #include "Rainmeter.h"
 | |
| #include "Error.h"
 | |
| #include <math.h>
 | |
| #include <time.h>
 | |
| #include "Meter.h"
 | |
| #include "Measure.h"
 | |
| #include "AboutDialog.h"
 | |
| #include "resource.h"
 | |
| #include "Litestep.h"
 | |
| #include <Mmsystem.h>
 | |
| #include <assert.h>
 | |
| #include <tchar.h>
 | |
| #include "MeasureCalc.h"
 | |
| #include "MeasureNet.h"
 | |
| #include "MeterButton.h"
 | |
| 
 | |
| using namespace Gdiplus;
 | |
| 
 | |
| #define ULW_ALPHA               0x00000002
 | |
| #define WS_EX_LAYERED           0x00080000
 | |
| 
 | |
| #define METERTIMER 1
 | |
| #define MOUSETIMER 2
 | |
| #define FADETIMER 3
 | |
| 
 | |
| #define SNAPDISTANCE 10
 | |
| 
 | |
| int CMeterWindow::m_InstanceCount = 0;
 | |
| 
 | |
| extern CRainmeter* Rainmeter;
 | |
| 
 | |
| /* 
 | |
| ** CMeterWindow
 | |
| **
 | |
| ** Constructor
 | |
| **
 | |
| */
 | |
| CMeterWindow::CMeterWindow(std::wstring& config, std::wstring& iniFile)
 | |
| {
 | |
| 	m_Background = NULL;
 | |
| 	m_Window = NULL;
 | |
| 	m_ChildWindow = false;
 | |
| 
 | |
| 	m_DoubleBuffer = NULL;
 | |
| 
 | |
| 	m_WindowX = 0;
 | |
| 	m_WindowY = 0;
 | |
| 	m_WindowW = 0;
 | |
| 	m_WindowH = 0;
 | |
| 	m_WindowZPosition = ZPOSITION_NORMAL;
 | |
| 	m_WindowDraggable = true;
 | |
| 	m_WindowUpdate = 1000;
 | |
| 	m_WindowHide = HIDEMODE_NONE;
 | |
| 	m_WindowStartHidden = false;
 | |
| 	m_SnapEdges = true;
 | |
| 	m_Rainmeter = NULL;
 | |
| 	m_ResetRegion = false;
 | |
| 	m_Refreshing = false;
 | |
| 	m_NativeTransparency = true;
 | |
| 	m_MeasuresToVariables = false;
 | |
| 	m_AllowNegativeCoordinates = true;
 | |
| 	m_SavePosition = false;			// Must be false
 | |
| 	m_AlphaValue = 255;
 | |
| 	m_FadeDuration = 250;
 | |
| 	m_ClickThrough = false;
 | |
| 	m_DynamicWindowSize = false;
 | |
| 	m_KeepOnScreen = true;
 | |
| 
 | |
| 	m_BackgroundSize.cx = 0;
 | |
| 	m_BackgroundSize.cy = 0;
 | |
| 
 | |
| 	m_FadeStartTime = 0;
 | |
| 	m_FadeStartValue = 0;
 | |
| 	m_FadeEndValue = 0;
 | |
| 	m_TransparencyValue = 0;
 | |
| 
 | |
| 	m_MouseOver = false;
 | |
| 
 | |
| 	m_BackgroundMode = BGMODE_IMAGE;
 | |
| 	m_SolidBevel = BEVELTYPE_NONE;
 | |
| 
 | |
| 	m_SkinName = config;
 | |
| 	m_SkinIniFile = iniFile;
 | |
| 
 | |
| 	m_User32Library = LoadLibrary(L"user32.dll");
 | |
| 
 | |
| 	m_UpdateCounter = 0;
 | |
| 
 | |
| 	m_InstanceCount++;
 | |
| }
 | |
| 
 | |
| /* 
 | |
| ** ~CMeterWindow
 | |
| **
 | |
| ** Destructor
 | |
| **
 | |
| */
 | |
| CMeterWindow::~CMeterWindow()
 | |
| {
 | |
| 	WriteConfig();
 | |
| 
 | |
| 	// Destroy the meters
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		delete (*j);
 | |
| 	}
 | |
| 
 | |
| 	// Destroy the measures
 | |
| 	std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 	for( ; i != m_Measures.end(); i++)
 | |
| 	{
 | |
| 		delete (*i);
 | |
| 	}
 | |
| 
 | |
| 	if(m_Background) delete m_Background;
 | |
| 	if(m_DoubleBuffer) delete (m_DoubleBuffer);
 | |
| 
 | |
| 	if(m_Window) DestroyWindow(m_Window);
 | |
| 
 | |
| 	FreeLibrary(m_User32Library);
 | |
| 
 | |
| 	m_InstanceCount--;
 | |
| 
 | |
| 	if (m_InstanceCount == 0)
 | |
| 	{
 | |
| 		BOOL Result;
 | |
| 		int counter = 0;
 | |
| 		do {
 | |
| 			// Wait for the window to die
 | |
| 			Result = UnregisterClass(L"RainmeterMeterWindow", m_Rainmeter->GetInstance());
 | |
| 			Sleep(100);
 | |
| 			counter += 1;
 | |
| 		} while(!Result && counter < 10);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* 
 | |
| ** Initialize
 | |
| **
 | |
| ** Initializes the window, creates the class and the window.
 | |
| **
 | |
| */
 | |
| int CMeterWindow::Initialize(CRainmeter& Rainmeter)
 | |
| {
 | |
| 	WNDCLASSEX wc;
 | |
| 
 | |
| 	m_Rainmeter = &Rainmeter;
 | |
| 
 | |
| 	// Register the windowclass
 | |
| 	memset(&wc, 0, sizeof(WNDCLASSEX));
 | |
| 	wc.style = CS_NOCLOSE;
 | |
| 	wc.cbSize = sizeof(WNDCLASSEX);
 | |
| 	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
 | |
| 	wc.lpfnWndProc = WndProc;
 | |
| 	wc.hInstance = m_Rainmeter->GetInstance();
 | |
| 	wc.lpszClassName = L"RainmeterMeterWindow";
 | |
| 	
 | |
| 	if(!RegisterClassEx(&wc))
 | |
| 	{
 | |
| 		DWORD err = GetLastError();
 | |
| 
 | |
| 		if (err != 0 && ERROR_CLASS_ALREADY_EXISTS != err)
 | |
| 		{
 | |
| 			throw CError(CError::ERROR_REGISTER_WINDOWCLASS, __LINE__, __FILE__);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	m_Window = CreateWindowEx(WS_EX_TOOLWINDOW,
 | |
| 							L"RainmeterMeterWindow", 
 | |
| 							NULL, 
 | |
| 							WS_POPUP,
 | |
| 							CW_USEDEFAULT,
 | |
| 							CW_USEDEFAULT,
 | |
| 							CW_USEDEFAULT,
 | |
| 							CW_USEDEFAULT,
 | |
| 							NULL,
 | |
| 							NULL,
 | |
| 							m_Rainmeter->GetInstance(),
 | |
| 							this);
 | |
| 
 | |
| 	if(m_Window == NULL) 
 | |
| 	{ 
 | |
| 		throw CError(CError::ERROR_CREATE_WINDOW, __LINE__, __FILE__);
 | |
| 	}
 | |
| 
 | |
| #ifndef _WIN64
 | |
| 	SetWindowLong(m_Window, GWL_USERDATA, magicDWord);
 | |
| #endif
 | |
| 
 | |
| 	setlocale(LC_NUMERIC, "C");
 | |
| 
 | |
| 	// Gotta have some kind of buffer during initialization
 | |
| 	m_DoubleBuffer = new Bitmap(1, 1, PixelFormat32bppARGB);
 | |
| 
 | |
| 	Refresh(true);
 | |
| 	if (!m_WindowStartHidden) 
 | |
| 	{
 | |
| 		if (m_WindowHide == HIDEMODE_FADEOUT) 
 | |
| 		{
 | |
| 			FadeWindow(0, 255);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			FadeWindow(0, m_AlphaValue);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	LSLog(LOG_DEBUG, L"Rainmeter", L"Initialization successful.");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Refresh
 | |
| **
 | |
| ** This deletes everything and rebuilds the config again.
 | |
| **
 | |
| */
 | |
| void CMeterWindow::Refresh(bool init)
 | |
| {
 | |
| 	assert(m_Rainmeter != NULL);
 | |
| 
 | |
| 	m_Rainmeter->SetCurrentParser(&m_Parser);
 | |
| 
 | |
| 	std::wstring dbg = L"Refreshing (Name: \"" + m_SkinName;
 | |
| 	dbg += L"\" Ini: \"" + m_SkinIniFile; 
 | |
| 	dbg += L"\")"; 
 | |
| 	LSLog(LOG_DEBUG, L"Rainmeter", dbg.c_str());
 | |
| 	
 | |
| 	m_Refreshing = true;
 | |
| 
 | |
| 	if(!init)
 | |
| 	{
 | |
| 		// First destroy everything
 | |
| 		WriteConfig();
 | |
| 
 | |
| 		KillTimer(m_Window, METERTIMER);	// Kill the timer
 | |
| 		KillTimer(m_Window, MOUSETIMER);	// Kill the timer
 | |
| 		KillTimer(m_Window, FADETIMER);	// Kill the timer
 | |
| 
 | |
| 		std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 		for( ; i != m_Measures.end(); i++)
 | |
| 		{
 | |
| 			delete (*i);
 | |
| 		}
 | |
| 		m_Measures.clear();
 | |
| 
 | |
| 		std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 		for( ; j != m_Meters.end(); j++)
 | |
| 		{
 | |
| 			delete (*j);
 | |
| 		}
 | |
| 		m_Meters.clear();
 | |
| 
 | |
| 		if(m_Background) delete m_Background;
 | |
| 		m_Background = NULL;
 | |
| 
 | |
| 		m_BackgroundSize.cx = m_BackgroundSize.cy = 0;
 | |
| 
 | |
| 		m_BackgroundName.erase();
 | |
| 	}
 | |
| 
 | |
| 	ReadConfig();	// Read the general settings
 | |
| 	ReadSkin();
 | |
| 
 | |
| 	InitializeMeters();
 | |
| 
 | |
| 	// Remove transparent flag
 | |
| 	LONG style = GetWindowLong(m_Window, GWL_EXSTYLE);
 | |
| 	if ((style & WS_EX_TRANSPARENT) != 0)
 | |
| 	{
 | |
| 		SetWindowLong(m_Window, GWL_EXSTYLE, style & ~WS_EX_TRANSPARENT);
 | |
| 	}
 | |
| 
 | |
| 	if (m_KeepOnScreen) 
 | |
| 	{
 | |
| 		MapCoordsToScreen(m_WindowX, m_WindowY, m_WindowW, m_WindowH);
 | |
| 	}
 | |
| 
 | |
| 	SetWindowPos(m_Window, NULL, m_WindowX, m_WindowY, m_WindowW, m_WindowH, SWP_NOZORDER | SWP_NOACTIVATE);
 | |
| 
 | |
| 	// Set the window region
 | |
| 	CreateRegion(true);	// Clear the region
 | |
| 	Update(false);
 | |
| 	CreateRegion(false);
 | |
| 
 | |
| 	// Start the timers
 | |
| 	if(0 == SetTimer(m_Window, METERTIMER, m_WindowUpdate, NULL))
 | |
| 	{
 | |
| 		throw CError(L"Unable to create a timer!", __LINE__, __FILE__);
 | |
| 	}
 | |
| 
 | |
| 	if(0 == SetTimer(m_Window, MOUSETIMER, 500, NULL))	// Mouse position is checked twice per sec
 | |
| 	{
 | |
| 		throw CError(L"Unable to create a timer!", __LINE__, __FILE__);
 | |
| 	}
 | |
| 
 | |
| 	UpdateTransparency(m_AlphaValue, true);
 | |
| 
 | |
| 	ChangeZPos(m_WindowZPosition);
 | |
| 
 | |
| 	m_Rainmeter->SetCurrentParser(NULL);
 | |
| 
 | |
| 	m_Refreshing = false;
 | |
| 
 | |
| 	if (!m_OnRefreshAction.empty())
 | |
| 	{
 | |
| 		m_Rainmeter->ExecuteCommand(m_OnRefreshAction.c_str(), this);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CMeterWindow::MapCoordsToScreen(int& x, int& y, int w, int h)
 | |
| {
 | |
| 	// Check that the window is inside the screen area
 | |
| 	HMONITOR hMonitor;
 | |
| 	MONITORINFO mi;
 | |
| 
 | |
| 	POINT pt = {x, y};
 | |
| 	for (int i = 0; i < 5; i++) 
 | |
| 	{
 | |
| 		switch(i) 
 | |
| 		{
 | |
| 		case 0:
 | |
| 			pt.x = x + w / 2;
 | |
| 			pt.y = y + h / 2;
 | |
| 			break;
 | |
| 
 | |
| 		case 1:
 | |
| 			pt.x = x;
 | |
| 			pt.y = y;
 | |
| 			break;
 | |
| 
 | |
| 		case 2:
 | |
| 			pt.x = x + w;
 | |
| 			pt.y = y + h;
 | |
| 			break;
 | |
| 
 | |
| 		case 3:
 | |
| 			pt.x = x;
 | |
| 			pt.y = y + h;
 | |
| 			break;
 | |
| 
 | |
| 		case 4:
 | |
| 			pt.x = x + w;
 | |
| 			pt.y = y;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
 | |
| 
 | |
| 		if(hMonitor != NULL)
 | |
| 		{
 | |
| 			mi.cbSize = sizeof(mi);
 | |
| 			GetMonitorInfo(hMonitor, &mi);
 | |
| 
 | |
| 			x = max(x, mi.rcMonitor.left);
 | |
| 			x = min(x, mi.rcMonitor.right - m_WindowW);
 | |
| 			y = max(y, mi.rcMonitor.top);
 | |
| 			y = min(y, mi.rcMonitor.bottom - m_WindowH);
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// No monitor found for the window -> Use the default work area
 | |
| 	RECT workArea;
 | |
| 	SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);	// Store the old value
 | |
| 	x = max(x, workArea.left);
 | |
| 	x = min(x, workArea.right - m_WindowW);
 | |
| 	y = max(y, workArea.top);
 | |
| 	y = min(y, workArea.bottom - m_WindowH);
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** MoveWindow
 | |
| **
 | |
| ** Moves the window to a new place
 | |
| **
 | |
| */
 | |
| void CMeterWindow::MoveWindow(int x, int y)
 | |
| {
 | |
| 	if (!m_AllowNegativeCoordinates)
 | |
| 	{
 | |
| 		RECT r;
 | |
| 		GetClientRect(GetDesktopWindow(), &r); 
 | |
| 		if(x < 0) x += r.right;
 | |
| 		if(y < 0) y += r.bottom;
 | |
| 	}
 | |
| 
 | |
| 	SetWindowPos(m_Window, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
 | |
| 
 | |
| 	if (m_SavePosition)
 | |
| 	{
 | |
| 		WriteConfig();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ChangeZPos
 | |
| **
 | |
| ** Sets the window's z-position
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ChangeZPos(ZPOSITION zPos)
 | |
| {
 | |
| 	if(!m_ChildWindow)
 | |
| 	{
 | |
| 		HWND parent = GetAncestor(m_Window, GA_PARENT);
 | |
| 		HWND winPos = HWND_NOTOPMOST;
 | |
| 		m_WindowZPosition = zPos;
 | |
| 
 | |
| 		switch (zPos)
 | |
| 		{
 | |
| 		case ZPOSITION_ONTOPMOST:
 | |
| 		case ZPOSITION_ONTOP:
 | |
| 			winPos = HWND_TOPMOST;
 | |
|  			break;
 | |
| 
 | |
| 		case ZPOSITION_ONBOTTOM:
 | |
| 			 winPos = HWND_BOTTOM;
 | |
| 			 break;
 | |
| 
 | |
| 		case ZPOSITION_ONDESKTOP:
 | |
| 			// Set the window's parent to progman, so it stays always on desktop
 | |
| 			HWND ProgmanHwnd = FindWindow(L"Progman", L"Program Manager");
 | |
| 			if (ProgmanHwnd && (parent != ProgmanHwnd))
 | |
| 			{
 | |
| 				SetParent(m_Window, ProgmanHwnd);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				return;		// The window is already on desktop
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (zPos != ZPOSITION_ONDESKTOP && (parent != GetDesktopWindow()))
 | |
| 		{
 | |
| 			SetParent(m_Window, NULL);
 | |
| 		}
 | |
| 
 | |
| 		bool refresh = m_Refreshing;
 | |
| 		m_Refreshing = true;	// Fake refreshing so that the z-position can be changed
 | |
| 		SetWindowPos(m_Window, winPos, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 | |
| 		m_Refreshing = refresh;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** RunBang
 | |
| **
 | |
| ** Runs the bang command
 | |
| **
 | |
| */
 | |
| void CMeterWindow::RunBang(BANGCOMMAND bang, const WCHAR* arg)
 | |
| {
 | |
| 	const WCHAR* pos = NULL;
 | |
| 	const WCHAR* pos2 = NULL;
 | |
| 
 | |
| 	if (!m_Window) return;
 | |
| 
 | |
| 	switch(bang) 
 | |
| 	{
 | |
| 	case BANG_REFRESH:
 | |
| 		Refresh(false);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_REDRAW:
 | |
| 		Redraw();
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_TOGGLEMETER:
 | |
| 		ToggleMeter(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_SHOWMETER:
 | |
| 		ShowMeter(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_HIDEMETER:
 | |
| 		HideMeter(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_TOGGLEMEASURE:
 | |
| 		ToggleMeasure(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_ENABLEMEASURE:
 | |
| 		EnableMeasure(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_DISABLEMEASURE:
 | |
| 		DisableMeasure(arg);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_SHOW:
 | |
| 		ShowWindow(m_Window, SW_SHOWNOACTIVATE);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_HIDE:
 | |
| 		ShowWindow(m_Window, SW_HIDE);
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_TOGGLE:
 | |
| 		if (IsWindowVisible(m_Window))
 | |
| 		{
 | |
| 			ShowWindow(m_Window, SW_HIDE);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			ShowWindow(m_Window, SW_SHOWNOACTIVATE);
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_MOVE:
 | |
| 		pos = wcschr(arg, ' ');
 | |
| 		if (pos != NULL)
 | |
| 		{
 | |
| 			MoveWindow(_wtoi(arg), _wtoi(pos));
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			DebugLog(L"Cannot parse parameters for !RainmeterMove");
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_ZPOS:
 | |
| 		ChangeZPos((ZPOSITION)_wtoi(arg));
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_LSHOOK:
 | |
| 		{
 | |
| 			pos = wcsrchr(arg, ' ');
 | |
| 			if (pos != NULL)
 | |
| 			{
 | |
| #ifdef _WIN64
 | |
| 				HWND hWnd = (HWND)_wtoi64(pos);
 | |
| #else
 | |
| 				HWND hWnd = (HWND)_wtoi(pos);
 | |
| #endif
 | |
| 				if (hWnd) 
 | |
| 				{
 | |
| 					// Disable native transparency
 | |
| 					m_NativeTransparency = false;
 | |
| 					UpdateTransparency(m_AlphaValue, true);
 | |
| 					SetWindowLong(m_Window, GWL_STYLE, (GetWindowLong(m_Window, GWL_STYLE) &~ WS_POPUP) | WS_CHILD);
 | |
| 					SetParent(m_Window, hWnd);
 | |
| 					m_ChildWindow = true;
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				DebugLog(L"Cannot parse parameters for !RainmeterLsBoxHook (%s)", arg);
 | |
| 			}
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_ABOUT:
 | |
| 		OpenAboutDialog(m_Window, m_Rainmeter->GetInstance());
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_MOVEMETER:
 | |
| 		pos = wcschr(arg, ' ');
 | |
| 		if (pos != NULL)
 | |
| 		{
 | |
| 			pos2 = wcschr(pos + 1, ' ');
 | |
| 			if (pos2 != NULL)
 | |
| 			{
 | |
| 				MoveMeter(_wtoi(arg), _wtoi(pos), pos2 + 1);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				DebugLog(L"Cannot parse the for !RainmeterMoveMeter");
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			DebugLog(L"Cannot parse the coordinates for !RainmeterMoveMeter");
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case BANG_PLUGIN:
 | |
| 		{
 | |
| 			std::wstring args = arg;
 | |
| 			std::wstring measure = arg;
 | |
| 			size_t pos = std::wstring::npos;
 | |
| 			do 
 | |
| 			{
 | |
| 				pos = args.find('\"');
 | |
| 				if (pos != std::wstring::npos)
 | |
| 				{
 | |
| 					args.erase(pos, 1);
 | |
| 				}
 | |
| 				
 | |
| 			} while(pos != std::wstring::npos);
 | |
| 
 | |
| 			pos = args.find(' ');
 | |
| 			if (pos != std::wstring::npos)
 | |
| 			{
 | |
| 				measure = args.substr(0, pos);
 | |
| 				args.erase(0, pos + 1);
 | |
| 			}
 | |
| 
 | |
| 			if (!measure.empty())
 | |
| 			{
 | |
| 				std::list<CMeasure*>::iterator iter = m_Measures.begin();
 | |
| 				for( ; iter != m_Measures.end(); iter++)
 | |
| 				{
 | |
| 					if (wcsicmp((*iter)->GetName(), measure.c_str()) == 0)
 | |
| 					{
 | |
| 						(*iter)->ExecuteBang(args.c_str());
 | |
| 						return;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				DebugLog(L"Unable to find [%s] for !RainmeterPluginBang", measure.c_str());
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				DebugLog(L"Cannot parse the !RainmeterPluginBang");
 | |
| 			}
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ShowMeter
 | |
| **
 | |
| ** Shows the given meter
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ShowMeter(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		if (wcscmp((*j)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			(*j)->Show();
 | |
| 			m_ResetRegion = true;	// Need to recalculate the window region
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to show the meter %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** HideMeter
 | |
| **
 | |
| ** Hides the given meter
 | |
| **
 | |
| */
 | |
| void CMeterWindow::HideMeter(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		if (wcscmp((*j)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			(*j)->Hide();
 | |
| 			m_ResetRegion = true;	// Need to recalculate the windowregion
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to hide the meter %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ToggleMeter
 | |
| **
 | |
| ** Toggles the given meter
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ToggleMeter(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		if (wcscmp((*j)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			if ((*j)->IsHidden())
 | |
| 			{
 | |
| 				(*j)->Show();
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				(*j)->Hide();
 | |
| 			}
 | |
| 			m_ResetRegion = true;	// Need to recalculate the window region
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to toggle the meter %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** MoveMeter
 | |
| **
 | |
| ** Moves the given meter
 | |
| **
 | |
| */
 | |
| void CMeterWindow::MoveMeter(int x, int y, const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		if (wcscmp((*j)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			(*j)->SetX(x);
 | |
| 				(*j)->SetY(y);
 | |
| 			m_ResetRegion = true;
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to move the meter %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| /*
 | |
| ** EnableMeasure
 | |
| **
 | |
| ** Enables the given measure
 | |
| **
 | |
| */
 | |
| void CMeterWindow::EnableMeasure(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 	for( ; i != m_Measures.end(); i++)
 | |
| 	{
 | |
| 		if (wcscmp((*i)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			(*i)->Enable();
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to enable the measure %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** DisableMeasure
 | |
| **
 | |
| ** Disables the given measure
 | |
| **
 | |
| */
 | |
| void CMeterWindow::DisableMeasure(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 	for( ; i != m_Measures.end(); i++)
 | |
| 	{
 | |
| 		if (wcscmp((*i)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			(*i)->Disable();
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to disable the measure %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** ToggleMeasure
 | |
| **
 | |
| ** Toggless the given measure
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ToggleMeasure(const WCHAR* name)
 | |
| {
 | |
| 	if (name == NULL || wcslen(name) == 0) return;
 | |
| 
 | |
| 	std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 	for( ; i != m_Measures.end(); i++)
 | |
| 	{
 | |
| 		if (wcscmp((*i)->GetName(), name) == 0)
 | |
| 		{
 | |
| 			if ((*i)->IsDisabled())
 | |
| 			{
 | |
| 				(*i)->Enable();
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				(*i)->Disable();
 | |
| 			}
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DebugLog(L"Unable to toggle the measure %s (there is no such thing in %s)", name, m_SkinName.c_str());
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ReadConfig
 | |
| **
 | |
| ** Reads the current config
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ReadConfig()
 | |
| {
 | |
| 	std::wstring iniFile = m_Rainmeter->GetIniFile();
 | |
| 	const WCHAR* section = L"Rainmeter";
 | |
| 
 | |
| 	m_SavePosition = true;		// Default value
 | |
| 
 | |
| 	CConfigParser parser;
 | |
| 	parser.Initialize(iniFile.c_str());
 | |
| 
 | |
| 	for (int i = 0; i < 2; i++)
 | |
| 	{
 | |
| 		m_WindowX = parser.ReadInt(section, L"WindowX", m_WindowX);
 | |
| 		m_WindowY = parser.ReadInt(section, L"WindowY", m_WindowY);
 | |
| 
 | |
| 		if (!m_Rainmeter->GetDummyLitestep())
 | |
| 		{
 | |
| 			// Check if step.rc has overrides these values
 | |
| 			m_WindowX = GetRCInt("RainmeterWindowX", m_WindowX);
 | |
| 			m_WindowY = GetRCInt("RainmeterWindowY", m_WindowY);
 | |
| 		}
 | |
| 
 | |
| 		if(m_WindowX != 0 || m_WindowY != 0)
 | |
| 		{
 | |
| 			// TODO: check that pt is somewhere on screen
 | |
| 		}
 | |
| 
 | |
| 		int zPos = parser.ReadInt(section, L"AlwaysOnTop", m_WindowZPosition);
 | |
| 		if (zPos == -1)
 | |
| 		{
 | |
| 			m_WindowZPosition = ZPOSITION_ONBOTTOM;
 | |
| 		}
 | |
| 		else if (zPos == -2)
 | |
| 		{
 | |
| 			m_WindowZPosition = ZPOSITION_ONDESKTOP;
 | |
| 		}
 | |
| 		else if (zPos == 1)
 | |
| 		{
 | |
| 			m_WindowZPosition = ZPOSITION_ONTOP;
 | |
| 		}
 | |
| 		else if (zPos == 2)
 | |
| 		{
 | |
| 			m_WindowZPosition = ZPOSITION_ONTOPMOST;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			m_WindowZPosition = ZPOSITION_NORMAL;
 | |
| 		}
 | |
| 
 | |
| 		m_WindowDraggable = 0!=parser.ReadInt(section, L"Draggable", m_WindowDraggable);
 | |
| 		m_WindowHide = (HIDEMODE)parser.ReadInt(section, L"HideOnMouseOver", m_WindowHide);
 | |
| 		m_WindowStartHidden = 0!=parser.ReadInt(section, L"StartHidden", m_WindowStartHidden);
 | |
| 		m_SavePosition = 0!=parser.ReadInt(section, L"SavePosition", m_SavePosition);
 | |
| 		m_SnapEdges = 0!=parser.ReadInt(section, L"SnapEdges", m_SnapEdges);
 | |
| 		m_MeasuresToVariables = 0!=parser.ReadInt(section, L"MeasuresToVariables", m_MeasuresToVariables);
 | |
| 		m_AllowNegativeCoordinates = 0!=parser.ReadInt(section, L"AllowNegativeCoordinates", m_AllowNegativeCoordinates);
 | |
| 		m_NativeTransparency = 0!=parser.ReadInt(section, L"NativeTransparency", m_NativeTransparency);
 | |
| 		m_ClickThrough = 0!=parser.ReadInt(section, L"ClickThrough", m_ClickThrough);
 | |
| 		m_KeepOnScreen = 0!=parser.ReadInt(section, L"KeepOnScreen", m_KeepOnScreen);
 | |
| 
 | |
| 		m_AlphaValue = parser.ReadInt(section, L"AlphaValue", m_AlphaValue);
 | |
| 		m_AlphaValue = min(255, m_AlphaValue);
 | |
| 		m_AlphaValue = max(0, m_AlphaValue);
 | |
| 
 | |
| 		m_FadeDuration = parser.ReadInt(section, L"FadeDuration", m_FadeDuration);
 | |
| 
 | |
| 		// Disable native transparency if not 2K/XP
 | |
| 		if(CRainmeter::IsNT() == PLATFORM_9X || CRainmeter::IsNT() == PLATFORM_NT4)
 | |
| 		{
 | |
| 			m_NativeTransparency = 0;
 | |
| 		}
 | |
| 
 | |
| 		// On the second loop override settings from the skin's section
 | |
| 		section = m_SkinName.c_str();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** WriteConfig
 | |
| **
 | |
| ** Writes the new settings to the config
 | |
| **
 | |
| */
 | |
| void CMeterWindow::WriteConfig()
 | |
| {
 | |
| 	WCHAR buffer[256];
 | |
| 	std::wstring iniFile = m_Rainmeter->GetIniFile();
 | |
| 	const WCHAR* section = m_SkinName.c_str();
 | |
| 
 | |
| 	if(!iniFile.empty())
 | |
| 	{
 | |
| 		// If position needs to be save, do so.
 | |
| 		if(m_SavePosition)
 | |
| 		{
 | |
| 			int x = m_WindowX, y = m_WindowY;
 | |
| 			if (!m_AllowNegativeCoordinates)
 | |
| 			{
 | |
| 				x = max(0, x);
 | |
| 				y = max(0, y);
 | |
| 			}
 | |
| 
 | |
| 			wsprintf(buffer, L"%i", x);
 | |
| 			WritePrivateProfileString(section, L"WindowX", buffer, iniFile.c_str());
 | |
| 			wsprintf(buffer, L"%i", y);
 | |
| 			WritePrivateProfileString(section, L"WindowY", buffer, iniFile.c_str());
 | |
| 		}
 | |
| 
 | |
| 		wsprintf(buffer, L"%i", m_AlphaValue);
 | |
| 		WritePrivateProfileString(section, L"AlphaValue", buffer, iniFile.c_str());
 | |
| 
 | |
| 		wsprintf(buffer, L"%i", m_FadeDuration);
 | |
| 		WritePrivateProfileString(section, L"FadeDuration", buffer, iniFile.c_str());
 | |
| 		
 | |
| 		wsprintf(buffer, L"%i", m_ClickThrough);
 | |
| 		WritePrivateProfileString(section, L"ClickThrough", buffer, iniFile.c_str());
 | |
| 		wsprintf(buffer, L"%i", m_WindowDraggable);
 | |
| 		WritePrivateProfileString(section, L"Draggable", buffer, iniFile.c_str());
 | |
| 		wsprintf(buffer, L"%i", m_WindowHide);
 | |
| 		WritePrivateProfileString(section, L"HideOnMouseOver", buffer, iniFile.c_str());
 | |
| 		wsprintf(buffer, L"%i", m_SavePosition);
 | |
| 		WritePrivateProfileString(section, L"SavePosition", buffer, iniFile.c_str());
 | |
| 		wsprintf(buffer, L"%i", m_SnapEdges);
 | |
| 		WritePrivateProfileString(section, L"SnapEdges", buffer, iniFile.c_str());
 | |
| 		wsprintf(buffer, L"%i", m_KeepOnScreen);
 | |
| 		WritePrivateProfileString(section, L"KeepOnScreen", buffer, iniFile.c_str());
 | |
| 
 | |
| 		wsprintf(buffer, L"%i", m_WindowZPosition);
 | |
| 		WritePrivateProfileString(section, L"AlwaysOnTop", buffer, iniFile.c_str());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** ReadSkin
 | |
| **
 | |
| ** Reads the skin config, creates the meters and measures and does the bindings.
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ReadSkin()
 | |
| {
 | |
| 	std::wstring iniFile = m_Rainmeter->GetSkinPath();
 | |
| 	iniFile += m_SkinName;
 | |
| 	iniFile += L"\\";
 | |
| 	iniFile += m_SkinIniFile;
 | |
| 
 | |
| 	m_Parser.Initialize(iniFile.c_str());
 | |
| 
 | |
| 	// Global settings
 | |
| 
 | |
| 	// Check the version 
 | |
| 	int appVersion = m_Parser.ReadInt(L"Rainmeter", L"AppVersion", 0);
 | |
| 	if (appVersion > RAINMETER_VERSION)
 | |
| 	{
 | |
| 		WCHAR buffer[256];
 | |
| 		std::wstring text;
 | |
| 		wsprintf(buffer, L"%i.%i", appVersion / 1000, appVersion % 1000);
 | |
| 		text = L"This skin needs Rainmeter version 0.";
 | |
| 		text += buffer;
 | |
| 		text += L" or newer.\nIt might not function as well as it should.\nYou should get an updated version or Rainmeter\nfrom http://www.rainmeter.net";
 | |
| 		MessageBox(m_Window, text.c_str(), L"Rainmeter", MB_OK);
 | |
| 	}
 | |
| 
 | |
| 	m_Author = m_Parser.ReadString(L"Rainmeter", L"Author", L"");
 | |
| 	m_BackgroundName = m_Parser.ReadString(L"Rainmeter", L"Background", L"");
 | |
| 	m_BackgroundName = Rainmeter->FixPath(m_BackgroundName, PATH_FOLDER_CURRENT_SKIN, m_SkinName);
 | |
| 
 | |
| 	std::wstring margins = m_Parser.ReadString(L"Rainmeter", L"BackgroundMargins", L"0, 0, 0, 0");
 | |
| 	int left = 0, top = 0, right = 0, bottom = 0;
 | |
| 	swscanf(margins.c_str(), L"%i, %i, %i, %i", &left, &top, &right, &bottom);
 | |
| 	m_BackgroundMargins.X = left;
 | |
| 	m_BackgroundMargins.Width = right - left;
 | |
| 	m_BackgroundMargins.Y = top;
 | |
| 	m_BackgroundMargins.Height = bottom - top;
 | |
| 
 | |
| 	margins = m_Parser.ReadString(L"Rainmeter", L"DragMargins", L"0, 0, 0, 0");
 | |
| 	left = 0, top = 0, right = 0, bottom = 0;
 | |
| 	swscanf(margins.c_str(), L"%i, %i, %i, %i", &left, &top, &right, &bottom);
 | |
| 	m_DragMargins.X = left;
 | |
| 	m_DragMargins.Width = right - left;
 | |
| 	m_DragMargins.Y = top;
 | |
| 	m_DragMargins.Height = bottom - top;
 | |
| 
 | |
| 	m_BackgroundMode = (BGMODE)m_Parser.ReadInt(L"Rainmeter", L"BackgroundMode", 0);
 | |
| 	m_SolidBevel = (BEVELTYPE)m_Parser.ReadInt(L"Rainmeter", L"BevelType", m_SolidBevel);
 | |
| 
 | |
| 	m_SolidColor = m_Parser.ReadColor(L"Rainmeter", L"SolidColor", Color::Gray);
 | |
| 	m_SolidColor2 = m_Parser.ReadColor(L"Rainmeter", L"SolidColor2", m_SolidColor);
 | |
| 	m_SolidAngle = (Gdiplus::REAL)m_Parser.ReadFloat(L"Rainmeter", L"GradientAngle", 0.0);
 | |
| 
 | |
| 	m_DynamicWindowSize = 0!=m_Parser.ReadInt(L"Rainmeter", L"DynamicWindowSize", m_DynamicWindowSize);
 | |
| 
 | |
| 	if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE) && m_BackgroundName.empty())
 | |
| 	{
 | |
| 		m_BackgroundMode = BGMODE_COPY;
 | |
| 	}
 | |
| 
 | |
| 	m_RightMouseDownAction = m_Parser.ReadString(L"Rainmeter", L"RightMouseDownAction", L"");
 | |
| 	m_LeftMouseDownAction = m_Parser.ReadString(L"Rainmeter", L"LeftMouseDownAction", L"");
 | |
| 	m_RightMouseUpAction = m_Parser.ReadString(L"Rainmeter", L"RightMouseUpAction", L"");
 | |
| 	m_LeftMouseUpAction = m_Parser.ReadString(L"Rainmeter", L"LeftMouseUpAction", L"");
 | |
| 	m_MouseOverAction = m_Parser.ReadString(L"Rainmeter", L"MouseOverAction", L"");
 | |
| 	m_MouseLeaveAction = m_Parser.ReadString(L"Rainmeter", L"MouseLeaveAction", L"");
 | |
| 	m_OnRefreshAction = m_Parser.ReadString(L"Rainmeter", L"OnRefreshAction", L"");
 | |
| 
 | |
| 	m_WindowUpdate = m_Parser.ReadInt(L"Rainmeter", L"Update", m_WindowUpdate);
 | |
| 
 | |
| 	// Create the meters and measures
 | |
| 
 | |
| 	// Get all the sections (i.e. different meters)
 | |
| 	WCHAR* items = new WCHAR[MAX_LINE_LENGTH];
 | |
| 	int size = MAX_LINE_LENGTH;
 | |
| 
 | |
| 	// Get all the sections
 | |
| 	while(true)
 | |
| 	{
 | |
| 		int res = GetPrivateProfileString( NULL, NULL, NULL, items, size, iniFile.c_str());
 | |
| 		if (res == 0) return;		// File not found
 | |
| 		if (res != size - 2) break;		// Fits in the buffer
 | |
| 
 | |
| 		delete [] items;
 | |
| 		size *= 2;
 | |
| 		items = new WCHAR[size];
 | |
| 	};
 | |
| 
 | |
| 	WCHAR* pos = items;
 | |
| 	while(wcslen(pos) > 0)
 | |
| 	{
 | |
| 		if(wcsicmp(L"Rainmeter", pos) != 0 && wcsicmp(L"Variables", pos) != 0)
 | |
| 		{
 | |
| 			std::wstring meterName, measureName;
 | |
| 
 | |
| 			// Check if the item is a meter or a measure (or perhaps something else)
 | |
| 			measureName = m_Parser.ReadString(pos, L"Measure", L"");
 | |
| 			meterName = m_Parser.ReadString(pos, L"Meter", L"");
 | |
| 			if (measureName.length() > 0)
 | |
| 			{
 | |
| 				try
 | |
| 				{
 | |
| 					// It's a measure
 | |
| 					CMeasure* measure = CMeasure::Create(measureName.c_str(), this);
 | |
| 					measure->SetName(pos);
 | |
| 					measure->ReadConfig(m_Parser, pos);
 | |
| 					m_Measures.push_back(measure);
 | |
| 				}
 | |
| 				catch (CError& error)
 | |
| 				{
 | |
| 					MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 				}
 | |
| 			}
 | |
| 			else if (meterName.length() > 0)
 | |
| 			{
 | |
| 				try
 | |
| 				{
 | |
| 					// It's a meter
 | |
| 					CMeter* meter = CMeter::Create(meterName.c_str(), this);
 | |
| 					meter->SetName(pos);
 | |
| 					meter->ReadConfig(pos);
 | |
| 					m_Meters.push_back(meter);
 | |
| 				}
 | |
| 				catch (CError& error)
 | |
| 				{
 | |
| 					MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 				}
 | |
| 			} 
 | |
| 			else
 | |
| 			{
 | |
| 				// It's something else
 | |
|                 throw CError(std::wstring(L"Section [") + pos + L"] is not a meter or a measure!", __LINE__, __FILE__);
 | |
|             }
 | |
| 		}
 | |
| 		pos = pos + wcslen(pos) + 1;
 | |
| 	}
 | |
| 
 | |
| 	delete [] items;
 | |
| 
 | |
| 	if (m_Meters.empty())
 | |
| 	{
 | |
| 		MessageBox(m_Window, L"Your configuration file doesn't contain any meters!\nYour skin's ini-file might be out of date.", APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// Bind the meters to the measures
 | |
| 		std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 		for( ; j != m_Meters.end(); j++)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				(*j)->BindMeasure(m_Measures);
 | |
| 			}
 | |
| 			catch (CError& error)
 | |
| 			{
 | |
| 				MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** InitializeMeters
 | |
| **
 | |
| ** Initializes all the meters and the background
 | |
| **
 | |
| */
 | |
| void CMeterWindow::InitializeMeters()
 | |
| {
 | |
| 	// Initalize all meters
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		try
 | |
| 		{
 | |
| 			(*j)->Initialize();
 | |
| 		}
 | |
| 		catch (CError& error)
 | |
| 		{
 | |
| 			MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Handle negative coordinates
 | |
| 	if (!m_AllowNegativeCoordinates)
 | |
| 	{
 | |
| 		RECT r;
 | |
| 		GetClientRect(GetDesktopWindow(), &r); 
 | |
| 		if(m_WindowX < 0) m_WindowX += r.right;
 | |
| 		if(m_WindowY < 0) m_WindowY += r.bottom;
 | |
| 	}
 | |
| 
 | |
| 	Update(true);
 | |
| 
 | |
| 	ResizeWindow(true);
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ResizeWindow
 | |
| ** 
 | |
| ** Changes the size of the window and re-adjusts the background
 | |
| */
 | |
| bool CMeterWindow::ResizeWindow(bool reset)
 | |
| {
 | |
| 	int w = m_BackgroundMargins.GetLeft();
 | |
| 	int h = m_BackgroundMargins.GetTop();
 | |
| 
 | |
| 	// Get the largest meter point
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		w = max(w, (*j)->GetX() + (*j)->GetW());
 | |
| 		h = max(h, (*j)->GetY() + (*j)->GetH());
 | |
| 	}
 | |
| 
 | |
| 	w += m_BackgroundMargins.GetRight();
 | |
| 	h += m_BackgroundMargins.GetBottom();
 | |
| 
 | |
| 	w = max(w, m_BackgroundSize.cx);
 | |
| 	h = max(h, m_BackgroundSize.cy);
 | |
| 
 | |
| 	if (!reset && m_WindowW == w && m_WindowH == h)
 | |
| 	{
 | |
| 		return false;		// The window is already correct size
 | |
| 	}
 | |
| 
 | |
| 	// Reset size (this is calculated below)
 | |
| 	m_WindowW = 0;
 | |
| 	m_WindowH = 0;
 | |
| 
 | |
| 	if (m_Background)
 | |
| 	{
 | |
| 		delete m_Background;
 | |
| 		m_Background = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE) && !m_BackgroundName.empty())
 | |
| 	{
 | |
| 		// Load the background
 | |
| 		m_Background = new Bitmap(m_BackgroundName.c_str());
 | |
| 		Status status = m_Background->GetLastStatus();
 | |
| 		if(Ok != status)
 | |
| 		{
 | |
| 			std::wstring err = L"Unable to load background: " + m_BackgroundName;
 | |
| 			MessageBox(m_Window, err.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 			delete m_Background;
 | |
| 			m_Background = NULL;
 | |
| 			m_BackgroundSize.cx = 0;
 | |
| 			m_BackgroundSize.cy = 0;
 | |
| 		}
 | |
| 
 | |
| 		// Calculate the window dimensions
 | |
| 		if(m_Background)
 | |
| 		{
 | |
| 			m_BackgroundSize.cx = m_Background->GetWidth();
 | |
| 			m_BackgroundSize.cy = m_Background->GetHeight();
 | |
| 
 | |
| 			w = max(w, m_BackgroundSize.cx);
 | |
| 			h = max(h, m_BackgroundSize.cy);
 | |
| 
 | |
| 			if (m_BackgroundMode == BGMODE_SCALED_IMAGE)
 | |
| 			{
 | |
| 				// Scale the background to fill the whole window
 | |
| 				Bitmap* scaledBackground = new Bitmap(w, h, PixelFormat32bppARGB);
 | |
| 
 | |
| 				Graphics graphics(scaledBackground);
 | |
| 
 | |
| 				if (m_BackgroundMargins.GetTop() > 0) 
 | |
| 				{
 | |
| 					if (m_BackgroundMargins.GetLeft() > 0) 
 | |
| 					{
 | |
| 						// Top-Left
 | |
| 						Rect r(0, 0, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop());
 | |
| 						graphics.DrawImage(m_Background, r, 0, 0, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), UnitPixel);
 | |
| 					}
 | |
| 
 | |
| 					// Top
 | |
| 					Rect r(m_BackgroundMargins.GetLeft(), 0, w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop());
 | |
| 					graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), 0, m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), UnitPixel);
 | |
| 
 | |
| 					if (m_BackgroundMargins.GetRight() > 0) 
 | |
| 					{
 | |
| 						// Top-Right
 | |
| 						Rect r(w - m_BackgroundMargins.GetRight(), 0, m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop());
 | |
| 						graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), 0, m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), UnitPixel);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (m_BackgroundMargins.GetLeft() > 0) 
 | |
| 				{
 | |
| 					// Left
 | |
| 					Rect r(0, m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetLeft(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom());
 | |
| 					graphics.DrawImage(m_Background, r, 0, m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetLeft(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 				}
 | |
| 
 | |
| 				// Center
 | |
| 				Rect r(m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom());
 | |
| 				graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 
 | |
| 				if (m_BackgroundMargins.GetRight() > 0) 
 | |
| 				{
 | |
| 					// Right
 | |
| 					Rect r(w - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom());
 | |
| 					graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 				}
 | |
| 				
 | |
| 				if (m_BackgroundMargins.GetBottom() > 0) 
 | |
| 				{
 | |
| 					if (m_BackgroundMargins.GetLeft() > 0) 
 | |
| 					{
 | |
| 						// Bottom-Left
 | |
| 						Rect r(0, h - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetBottom());
 | |
| 						graphics.DrawImage(m_Background, r, 0, m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 					}
 | |
| 					// Bottom
 | |
| 					Rect r(m_BackgroundMargins.GetLeft(), h - m_BackgroundMargins.GetBottom(), w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom());
 | |
| 					graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 
 | |
| 					if (m_BackgroundMargins.GetRight() > 0) 
 | |
| 					{
 | |
| 						// Bottom-Right
 | |
| 						Rect r(w - m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom());
 | |
| 						graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom(), UnitPixel);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				delete m_Background;
 | |
| 				m_Background = scaledBackground;
 | |
| 			}
 | |
| 
 | |
| 			// Get the size form the background bitmap
 | |
| 			m_WindowW = m_Background->GetWidth();
 | |
| 			m_WindowH = m_Background->GetHeight();
 | |
| 
 | |
| 			if (!m_NativeTransparency)
 | |
| 			{
 | |
| 				// Graph the desktop and place the background on top of it
 | |
| 				Bitmap* desktop = GrabDesktop(m_WindowX, m_WindowY, m_WindowW, m_WindowH);
 | |
| 				Graphics graphics(desktop);
 | |
| 				Rect r(0, 0, m_WindowW, m_WindowH);
 | |
| 				graphics.DrawImage(m_Background, r, 0, 0, m_WindowW, m_WindowH, UnitPixel);
 | |
| 				delete m_Background;
 | |
| 				m_Background = desktop;
 | |
| 			}
 | |
| 		} 
 | |
| 	} 
 | |
| 	else
 | |
| 	{
 | |
| 		m_WindowW = w;
 | |
| 		m_WindowH = h;
 | |
| 	}
 | |
| 
 | |
| 	// If Background is not set, take a copy from the desktop
 | |
| 	if(m_Background == NULL) 
 | |
| 	{
 | |
| 		if (m_BackgroundMode == BGMODE_COPY)
 | |
| 		{
 | |
| 			if (!m_NativeTransparency)
 | |
| 			{
 | |
| 				m_Background = GrabDesktop(m_WindowX, m_WindowY, m_WindowW, m_WindowH);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			// Create a solid color bitmap for the background
 | |
| 			m_Background = new Bitmap(m_WindowW, m_WindowH, PixelFormat32bppARGB);
 | |
| 			Graphics graphics(m_Background);
 | |
| 
 | |
| 			if (m_SolidColor.GetValue() == m_SolidColor2.GetValue())
 | |
| 			{
 | |
| 				SolidBrush solid(m_SolidColor);
 | |
| 				graphics.FillRectangle(&solid, 0, 0, m_WindowW, m_WindowH);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				Rect r(0, 0, m_WindowW, m_WindowH);
 | |
| 				LinearGradientBrush gradient(r, m_SolidColor, m_SolidColor2, m_SolidAngle, TRUE);
 | |
| 				graphics.FillRectangle(&gradient, r);
 | |
| 			}
 | |
| 
 | |
| 			if (m_SolidBevel != BEVELTYPE_NONE)
 | |
| 			{
 | |
| 				Pen light(Color(255, 255, 255, 255));
 | |
| 				Pen dark(Color(255, 0, 0, 0));
 | |
| 
 | |
| 				if (m_SolidBevel == BEVELTYPE_DOWN)
 | |
| 				{
 | |
| 					light.SetColor(Color(255, 0, 0, 0));
 | |
| 					dark.SetColor(Color(255, 255, 255, 255));
 | |
| 				}
 | |
| 				Rect rect(0, 0, m_WindowW, m_WindowH);	
 | |
| 				CMeter::DrawBevel(graphics, rect, light, dark);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** GrabDesktop
 | |
| ** 
 | |
| ** Grabs a part of the desktop
 | |
| */
 | |
| Bitmap* CMeterWindow::GrabDesktop(int x, int y, int w, int h)
 | |
| {
 | |
| 	HDC desktopDC = GetDC(GetDesktopWindow());
 | |
| 	HDC dc = CreateCompatibleDC(desktopDC);
 | |
| 	HBITMAP desktopBM = CreateCompatibleBitmap(desktopDC, w, h);
 | |
| 	HBITMAP oldBM = (HBITMAP)SelectObject(dc, desktopBM);
 | |
| 	BitBlt(dc, 0, 0, w, h, desktopDC, x, y, SRCCOPY);
 | |
| 	SelectObject(dc, oldBM);
 | |
| 	DeleteDC(dc);
 | |
| 	ReleaseDC(GetDesktopWindow(), desktopDC);
 | |
| 	Bitmap* background = new Bitmap(desktopBM, NULL);
 | |
| 	DeleteObject(desktopBM);
 | |
| 	return background;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** CreateRegion
 | |
| **
 | |
| ** Creates/Clears a window region
 | |
| **
 | |
| */
 | |
| void CMeterWindow::CreateRegion(bool clear)
 | |
| {
 | |
| 	if (clear)
 | |
| 	{
 | |
| 		SetWindowRgn(m_Window, NULL, TRUE);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// Set window region if needed
 | |
| 		if(!m_BackgroundName.empty()) 
 | |
| 		{
 | |
| 			HBITMAP background = NULL;
 | |
| 			m_DoubleBuffer->GetHBITMAP(Color(255,0,255), &background);
 | |
| 			if (background)
 | |
| 			{
 | |
| 				HRGN region = BitmapToRegion(background, RGB(255,0,255), 0x101010, 0, 0);
 | |
| 				SetWindowRgn(m_Window, region, TRUE);
 | |
| 				DeleteObject(background);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Redraw
 | |
| **
 | |
| ** Redraws the meters and paints the window
 | |
| **
 | |
| */
 | |
| void CMeterWindow::Redraw() 
 | |
| {
 | |
| 	if (m_DoubleBuffer) delete m_DoubleBuffer;
 | |
| 	m_DoubleBuffer = new Bitmap(m_WindowW, m_WindowH, PixelFormat32bppARGB);
 | |
| 
 | |
| 	if (m_ResetRegion)
 | |
| 	{
 | |
| 		ResizeWindow(false);
 | |
| 		CreateRegion(true);
 | |
| 	}
 | |
| 
 | |
| 	if (m_Background)
 | |
| 	{
 | |
| 		// Copy the background over the doublebuffer
 | |
| 		Graphics graphics(GetDoubleBuffer());
 | |
| 		Rect r(0, 0, m_WindowW, m_WindowH);
 | |
| 		graphics.DrawImage(m_Background, r, 0, 0, m_Background->GetWidth(), m_Background->GetHeight(), UnitPixel);
 | |
| 	}
 | |
| 
 | |
| 	// Draw the meters
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		try
 | |
| 		{
 | |
| 			(*j)->Draw();
 | |
| 		}
 | |
| 		catch (CError& error)
 | |
| 		{
 | |
| 			MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	if (m_ResetRegion) CreateRegion(false);
 | |
| 	m_ResetRegion = false;
 | |
| 
 | |
| 	UpdateTransparency(m_TransparencyValue, false);
 | |
| 
 | |
| 	if (!m_NativeTransparency)
 | |
| 	{
 | |
| 		InvalidateRect(m_Window, NULL, FALSE);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** Update
 | |
| **
 | |
| ** Updates all the measures and redraws the meters
 | |
| **
 | |
| */
 | |
| void CMeterWindow::Update(bool nodraw)
 | |
| {
 | |
| 	m_UpdateCounter++;
 | |
| 
 | |
| 	// Pre-updates
 | |
| 	CMeasureNet::UpdateIFTable();
 | |
| 	CMeasureCalc::UpdateVariableMap(*this);
 | |
| 
 | |
| 	// Update all measures
 | |
| 	std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| 	for( ; i != m_Measures.end(); i++)
 | |
| 	{
 | |
| 		try
 | |
| 		{
 | |
| 			(*i)->Update();
 | |
| 		}
 | |
| 		catch (CError& error)
 | |
| 		{
 | |
| 			MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Update the meters
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		try
 | |
| 		{
 | |
| 			(*j)->Update();
 | |
| 		}
 | |
| 		catch (CError& error)
 | |
| 		{
 | |
| 			MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Statistics
 | |
| 	CMeasureNet::UpdateStats();
 | |
| 
 | |
| 	if (!nodraw)
 | |
| 	{
 | |
| 		if (m_DynamicWindowSize)
 | |
| 		{
 | |
| 			// Resize the window
 | |
| 			m_ResetRegion = true;
 | |
| 		}
 | |
| 
 | |
| 		Redraw();
 | |
| 	}
 | |
| 
 | |
| //	if (m_MeasuresToVariables)	// BUG: LSSetVariable doens't seem to work for some reason.
 | |
| //	{
 | |
| //		std::list<CMeasure*>::iterator i = m_Measures.begin();
 | |
| //		for( ; i != m_Measures.end(); i++)
 | |
| //		{
 | |
| //			const char* sz = (*i)->GetStringValue(true, 1, 1, false);
 | |
| //			if (sz && wcslen(sz) > 0)
 | |
| //			{
 | |
| //				WCHAR* wideSz = CMeter::ConvertToWide(sz);
 | |
| //				WCHAR* wideName = CMeter::ConvertToWide((*i)->GetName());
 | |
| //				LSSetVariable(wideName, wideSz);
 | |
| //				delete [] wideSz;
 | |
| //				delete [] wideName;
 | |
| //			}
 | |
| //		}
 | |
| //	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** UpdateTransparency
 | |
| **
 | |
| ** Updates the native Windows transparency
 | |
| */
 | |
| void CMeterWindow::UpdateTransparency(int alpha, bool reset)
 | |
| {
 | |
| 	if (m_NativeTransparency)
 | |
| 	{
 | |
| 		if (reset)
 | |
| 		{
 | |
| 			// Add the window flag
 | |
| 			LONG style = GetWindowLong(m_Window, GWL_EXSTYLE);
 | |
| 			SetWindowLong(m_Window, GWL_EXSTYLE, style | WS_EX_LAYERED);
 | |
| 		}
 | |
| 
 | |
| 		typedef BOOL (WINAPI * FPUPDATELAYEREDWINDOW)(HWND hWnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags);
 | |
| 		FPUPDATELAYEREDWINDOW UpdateLayeredWindow = (FPUPDATELAYEREDWINDOW)GetProcAddress(m_User32Library, "UpdateLayeredWindow");
 | |
| 
 | |
| 		BLENDFUNCTION blendPixelFunction= {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
 | |
| 		POINT ptWindowScreenPosition = {m_WindowX, m_WindowY};
 | |
| 		POINT ptSrc = {0, 0};
 | |
| 		SIZE szWindow = {m_WindowW, m_WindowH};
 | |
| 
 | |
| 		HDC dcScreen = GetDC(GetDesktopWindow());
 | |
| 		HDC dcMemory = CreateCompatibleDC(dcScreen);
 | |
| 
 | |
| 		HBITMAP dbBitmap;
 | |
| 		m_DoubleBuffer->GetHBITMAP(Color(0, 0, 0, 0), &dbBitmap);
 | |
| 		HBITMAP oldBitmap = (HBITMAP)SelectObject(dcMemory, dbBitmap);
 | |
| 		UpdateLayeredWindow(m_Window, dcScreen, &ptWindowScreenPosition, &szWindow, dcMemory, &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);
 | |
| 		ReleaseDC(GetDesktopWindow(), dcScreen);
 | |
| 		SelectObject(dcMemory, oldBitmap);
 | |
| 		DeleteDC(dcMemory);
 | |
| 		DeleteObject(dbBitmap);
 | |
| 
 | |
| 		m_TransparencyValue = alpha;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (reset)
 | |
| 		{
 | |
| 			// Remove the window flag
 | |
| 			LONG style = GetWindowLong(m_Window, GWL_EXSTYLE);
 | |
| 			SetWindowLong(m_Window, GWL_EXSTYLE, style & ~WS_EX_LAYERED);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnPaint
 | |
| **
 | |
| ** Repaints the window. This does not cause update of the measures.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnPaint(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	PAINTSTRUCT ps;
 | |
| 	HDC winDC = BeginPaint(m_Window, &ps);
 | |
| 
 | |
| 	Graphics graphics(winDC);
 | |
| 	graphics.DrawImage(m_DoubleBuffer, 0, 0);
 | |
| 
 | |
| 	EndPaint(m_Window, &ps);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnTimer
 | |
| **
 | |
| ** Handles the timers. The METERTIMER updates all the measures 
 | |
| ** MOUSETIMER is used to hide/show the window.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnTimer(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	if(wParam == METERTIMER) 
 | |
| 	{
 | |
| 		Update(false);
 | |
| 		UpdateAboutStatistics();
 | |
| 
 | |
| 		if (m_KeepOnScreen) 
 | |
| 		{
 | |
| 			int x = m_WindowX;
 | |
| 			int y = m_WindowY;
 | |
| 			MapCoordsToScreen(x, y, m_WindowW, m_WindowH);
 | |
| 			if (x != m_WindowX || y != m_WindowY)
 | |
| 			{
 | |
| 				MoveWindow(x, y);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else if(wParam == MOUSETIMER)
 | |
| 	{
 | |
| 		ShowWindowIfAppropriate();
 | |
| 
 | |
| 		POINT pos;
 | |
| 		GetCursorPos(&pos);
 | |
| 		MapWindowPoints(NULL, m_Window, &pos, 1);
 | |
| 		
 | |
| 		if (!m_MouseLeaveAction.empty())
 | |
| 		{
 | |
| 			// Check mouse leave actions
 | |
| 			DoAction(pos.x, pos.y, MOUSE_LEAVE, false);
 | |
| 		}
 | |
| 
 | |
| 		if (m_WindowZPosition == ZPOSITION_ONTOPMOST)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_ONTOPMOST);
 | |
| 		}
 | |
| 
 | |
| 		// Handle buttons
 | |
| 		bool redraw = false;
 | |
| 		std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 		for( ; j != m_Meters.end(); j++)
 | |
| 		{
 | |
| 			// Hidden meters are ignored
 | |
| 			if ((*j)->IsHidden()) continue;
 | |
| 
 | |
| 			CMeterButton* button = dynamic_cast<CMeterButton*>(*j);
 | |
| 			if (button)
 | |
| 			{
 | |
| 				redraw |= button->MouseMove(pos);
 | |
| 			}
 | |
| 		}
 | |
| 		if (redraw)
 | |
| 		{
 | |
| 			Redraw();
 | |
| 		}
 | |
| 	}
 | |
| 	else if(wParam == FADETIMER)
 | |
| 	{
 | |
| 		DWORD ticks = GetTickCount();
 | |
| 		if (m_FadeStartTime == 0)
 | |
| 		{
 | |
| 			m_FadeStartTime = ticks;
 | |
| 		}
 | |
| 
 | |
| 		if (ticks - m_FadeStartTime > (DWORD)m_FadeDuration)
 | |
| 		{
 | |
| 			KillTimer(m_Window, FADETIMER);
 | |
| 			m_FadeStartTime = 0;
 | |
| 			if (m_FadeEndValue == 0)
 | |
| 			{
 | |
| 				ShowWindow(m_Window, SW_HIDE);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				UpdateTransparency(m_FadeEndValue, false);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			double value = (ticks - m_FadeStartTime);
 | |
| 			value /= m_FadeDuration;
 | |
|  			value *= m_FadeEndValue - m_FadeStartValue;
 | |
| 			value += m_FadeStartValue;
 | |
| 			value = min(value, 255);
 | |
| 			value = max(value, 0);
 | |
| 
 | |
| 			UpdateTransparency((int)value, false);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| //	// TEST
 | |
| //	if (!m_ChildWindow)
 | |
| //	{
 | |
| //		RECT rect;
 | |
| //		GetWindowRect(m_Window, &rect);
 | |
| //		if (rect.left != m_WindowX && rect.top != m_WindowY)
 | |
| //		{
 | |
| //			DebugLog(L"Window position has been changed. Moving it back to the place it belongs.");
 | |
| //			SetWindowPos(m_Window, NULL, m_WindowX, m_WindowY, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
 | |
| //		}
 | |
| //	}
 | |
| 
 | |
| 	// ~TEST
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void CMeterWindow::FadeWindow(int from, int to)
 | |
| {
 | |
| 	if (!m_NativeTransparency || m_FadeDuration == 0)
 | |
| 	{
 | |
| 		if (to == 0)
 | |
| 		{
 | |
| 			ShowWindow(m_Window, SW_HIDE);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if (m_FadeDuration == 0)
 | |
| 			{
 | |
| 				UpdateTransparency(to, false);
 | |
| 			}
 | |
| 			if (from == 0) 
 | |
| 			{
 | |
| 				ShowWindow(m_Window, SW_SHOWNOACTIVATE);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		m_FadeStartValue = from;
 | |
| 		m_FadeEndValue = to;
 | |
| 		UpdateTransparency(from, false);
 | |
| 		if (from == 0) 
 | |
| 		{
 | |
| 			ShowWindow(m_Window, SW_SHOWNOACTIVATE);
 | |
| 		}
 | |
| 
 | |
| 		SetTimer(m_Window, FADETIMER, 10, NULL);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** ShowWindowIfAppropriate
 | |
| **
 | |
| ** Show the window if it is temporarily hidden.
 | |
| **
 | |
| */
 | |
| void CMeterWindow::ShowWindowIfAppropriate()
 | |
| {
 | |
| 	bool inside = false;
 | |
| 	bool keyDown = GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_SHIFT) & 0x8000 || GetKeyState(VK_MENU) & 0x8000;
 | |
| 	POINT pos;
 | |
| 	RECT rect;
 | |
| 
 | |
| 	GetWindowRect(m_Window, &rect);
 | |
| 	GetCursorPos(&pos);
 | |
| 
 | |
| 	if(rect.left <= pos.x && rect.right >= pos.x &&
 | |
| 	   rect.top <= pos.y && rect.bottom >= pos.y) 
 | |
| 	{
 | |
| 		// Check transparent pixels
 | |
| 		if (m_DoubleBuffer)
 | |
| 		{
 | |
| 			Color color;
 | |
| 			m_DoubleBuffer->GetPixel(pos.x - rect.left, pos.y - rect.top, &color);
 | |
| 			if (color.GetA() != 0)
 | |
| 			{
 | |
| 				inside = true;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			inside = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (m_ClickThrough)
 | |
| 	{
 | |
| 		if (!inside || keyDown)
 | |
| 		{
 | |
| 			// If Alt, shift or control is down, remove the transparent flag
 | |
| 			LONG style = GetWindowLong(m_Window, GWL_EXSTYLE);
 | |
| 			if ((style & WS_EX_TRANSPARENT) != 0)
 | |
| 			{
 | |
| 				SetWindowLong(m_Window, GWL_EXSTYLE, style & ~WS_EX_TRANSPARENT);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if(m_WindowHide)
 | |
| 	{
 | |
| 		if (!inside && !keyDown)
 | |
| 		{
 | |
| 			switch(m_WindowHide) 
 | |
| 			{
 | |
| 			case HIDEMODE_HIDE:
 | |
| 				if (m_TransparencyValue == 0 || !IsWindowVisible(m_Window))
 | |
| 				{
 | |
| 					ShowWindow(m_Window, SW_SHOWNOACTIVATE);
 | |
| 					FadeWindow(0, m_AlphaValue);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case HIDEMODE_FADEIN:
 | |
| 				if (m_TransparencyValue == 255)
 | |
| 				{
 | |
| 					FadeWindow(255, m_AlphaValue);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case HIDEMODE_FADEOUT:
 | |
| 				if (m_TransparencyValue == m_AlphaValue)
 | |
| 				{
 | |
| 					FadeWindow(m_AlphaValue, 255);
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** OnMouseMove
 | |
| **
 | |
| ** When we get WM_MOUSEMOVE messages, hide the window as the mouse is over it.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnMouseMove(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	bool keyDown = GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_SHIFT) & 0x8000 || GetKeyState(VK_MENU) & 0x8000;
 | |
| 
 | |
| 	if (!keyDown)
 | |
| 	{
 | |
| 		if (m_ClickThrough)
 | |
| 		{
 | |
| 			LONG style = GetWindowLong(m_Window, GWL_EXSTYLE);
 | |
| 			if ((style & WS_EX_TRANSPARENT) == 0)
 | |
| 			{
 | |
| 				SetWindowLong(m_Window, GWL_EXSTYLE, style | WS_EX_TRANSPARENT);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// If Alt, shift or control is down, do not hide the window
 | |
| 		switch(m_WindowHide) 
 | |
| 		{
 | |
| 		case HIDEMODE_HIDE:
 | |
| 			if (m_TransparencyValue == m_AlphaValue)
 | |
| 			{
 | |
| 				FadeWindow(m_AlphaValue, 0);
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case HIDEMODE_FADEIN:
 | |
| 			if (m_TransparencyValue == m_AlphaValue)
 | |
| 			{
 | |
| 				FadeWindow(m_AlphaValue, 255);
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case HIDEMODE_FADEOUT:
 | |
| 			if (m_TransparencyValue == 255)
 | |
| 			{
 | |
| 				FadeWindow(255, m_AlphaValue);
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	POINT pos;
 | |
| 	pos.x = (SHORT)LOWORD(lParam);
 | |
| 	pos.y = (SHORT)HIWORD(lParam);
 | |
| 
 | |
| 	if (m_Message == WM_NCMOUSEMOVE)
 | |
| 	{
 | |
| 		// Map to local window
 | |
| 		MapWindowPoints(GetDesktopWindow(), m_Window, &pos, 1);
 | |
| 	}
 | |
| 	
 | |
| 	DoAction(pos.x, pos.y, MOUSE_OVER, false);
 | |
| 
 | |
| 	// Handle buttons
 | |
| 	bool redraw = false;
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		// Hidden meters are ignored
 | |
| 		if ((*j)->IsHidden()) continue;
 | |
| 
 | |
| 		CMeterButton* button = dynamic_cast<CMeterButton*>(*j);
 | |
| 		if (button)
 | |
| 		{
 | |
| 			redraw |= button->MouseMove(pos);
 | |
| 		}
 | |
| 	}
 | |
| 	if (redraw)
 | |
| 	{
 | |
| 		Redraw();
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnCreate
 | |
| **
 | |
| ** During window creation we do nothing.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnCreate(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnCommand
 | |
| **
 | |
| ** Handle the menu commands.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	try 
 | |
| 	{
 | |
| 		if(wParam == ID_CONTEXT_SKINMENU_EDITSKIN)
 | |
| 		{
 | |
| 			std::wstring command = m_Rainmeter->GetConfigEditor();
 | |
| 			command += L" \"";
 | |
| 			command += m_Rainmeter->GetSkinPath() + L"\\" + m_SkinName + L"\\" + m_SkinIniFile + L"\"";
 | |
| 			m_Rainmeter->ExecuteCommand(command.c_str(), this);
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_REFRESH)
 | |
| 		{
 | |
| 			Refresh(false);
 | |
| 		} 
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_VERYTOPMOST)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_ONTOPMOST);
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_TOPMOST)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_ONTOP);
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_BOTTOM)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_ONBOTTOM);
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_NORMAL)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_NORMAL);
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_ONDESKTOP)
 | |
| 		{
 | |
| 			ChangeZPos(ZPOSITION_ONDESKTOP);
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_KEEPONSCREEN)
 | |
| 		{
 | |
| 			m_KeepOnScreen = !m_KeepOnScreen;
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_CLICKTHROUGH)
 | |
| 		{
 | |
| 			m_ClickThrough = !m_ClickThrough;
 | |
| 			WriteConfig();
 | |
| 			Refresh(false);
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_DRAGGABLE)
 | |
| 		{
 | |
| 			m_WindowDraggable = !m_WindowDraggable;
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_HIDEONMOUSE)
 | |
| 		{
 | |
| 			if (m_WindowHide == HIDEMODE_NONE)
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_HIDE;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_NONE;
 | |
| 			}
 | |
| 			WriteConfig();
 | |
| 			Refresh(false);
 | |
| 		}		
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEIN)
 | |
| 		{
 | |
| 			if (m_WindowHide == HIDEMODE_NONE)
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_FADEIN;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_NONE;
 | |
| 			}
 | |
| 			WriteConfig();
 | |
| 			Refresh(false);
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEOUT)
 | |
| 		{
 | |
| 			if (m_WindowHide == HIDEMODE_NONE)
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_FADEOUT;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				m_WindowHide = HIDEMODE_NONE;
 | |
| 			}
 | |
| 			WriteConfig();
 | |
| 			Refresh(false);
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_REMEMBERPOSITION)
 | |
| 		{
 | |
| 			m_SavePosition = !m_SavePosition;
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_SKINMENU_SNAPTOEDGES)
 | |
| 		{
 | |
| 			m_SnapEdges = !m_SnapEdges;
 | |
| 			WriteConfig();
 | |
| 		}
 | |
| 		else if(wParam >= ID_CONTEXT_SKINMENU_TRANSPARENCY_0 && wParam <= ID_CONTEXT_SKINMENU_TRANSPARENCY_90)
 | |
| 		{
 | |
| 			m_AlphaValue = (int)(255.0 - 230.0 * (double)(wParam - ID_CONTEXT_SKINMENU_TRANSPARENCY_0) / (double)(ID_CONTEXT_SKINMENU_TRANSPARENCY_90 - ID_CONTEXT_SKINMENU_TRANSPARENCY_0));
 | |
| 			WriteConfig();
 | |
| 			Refresh(false);
 | |
| 		}
 | |
| 		else if(wParam == ID_CONTEXT_CLOSESKIN)
 | |
| 		{
 | |
| 			const std::vector<CRainmeter::CONFIG>& configs = m_Rainmeter->GetAllConfigs();
 | |
| 
 | |
| 			for (int i = 0; i < configs.size(); i++)
 | |
| 			{
 | |
| 				if (configs[i].config == m_SkinName)
 | |
| 				{
 | |
| 					m_Rainmeter->DeactivateConfig(this, i);
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			// Forward to tray window, which handles all the other commands
 | |
| 			SendMessage(m_Rainmeter->GetTrayWindow()->GetWindow(), WM_COMMAND, wParam, lParam);
 | |
| 		}
 | |
| 	} 
 | |
|     catch(CError& error) 
 | |
|     {
 | |
| 		MessageBox(m_Window, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnNcHitTest
 | |
| **
 | |
| ** This is overwritten so that the window can be dragged
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnNcHitTest(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	if (m_WindowDraggable)
 | |
| 	{
 | |
| 		POINT pos;
 | |
| 		pos.x = (SHORT)LOWORD(lParam);
 | |
| 		pos.y = (SHORT)HIWORD(lParam);
 | |
| 		MapWindowPoints(GetDesktopWindow(), m_Window, &pos, 1);
 | |
| 
 | |
| 		int x1 = m_DragMargins.GetLeft();
 | |
| 		int x2 = m_WindowW - m_DragMargins.GetRight();
 | |
| 		int y1 = m_DragMargins.GetTop();
 | |
| 		int y2 = m_WindowH - m_DragMargins.GetBottom();
 | |
| 
 | |
| 		if (x1 < 0) x1 += m_WindowW;
 | |
| 		if (y1 < 0) y1 += m_WindowH;
 | |
| 		if (x2 > m_WindowW) x2 -= m_WindowW;
 | |
| 		if (y2 > m_WindowH) y2 -= m_WindowH;
 | |
| 
 | |
| 		if (pos.x >= x1 && pos.x < x2) 
 | |
| 		{
 | |
| 			if (pos.y >= y1 && pos.y < y2) 
 | |
| 			{
 | |
| 				return HTCAPTION;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return HTCLIENT;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnWindowPosChanging
 | |
| **
 | |
| ** Called when windows position is about to change
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnWindowPosChanging(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	LPWINDOWPOS wp=(LPWINDOWPOS)lParam;
 | |
| 
 | |
| 	if(m_WindowZPosition == ZPOSITION_ONBOTTOM && !m_Refreshing)
 | |
| 	{
 | |
| 		// do not change the z-order. This keeps the window on bottom.
 | |
| 		wp->flags|=SWP_NOZORDER;
 | |
| 	}
 | |
| 
 | |
| 	if ((wp->flags & SWP_NOMOVE) == 0) 
 | |
| 	{
 | |
| 		if (m_SnapEdges && !(GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_SHIFT) & 0x8000))
 | |
| 		{
 | |
| 			RECT workArea;
 | |
| 			GetClientRect(GetDesktopWindow(), &workArea);
 | |
| 
 | |
| 			// only process movement (ignore anything without winpos values)
 | |
| 			if(wp->cx != 0 && wp->cy != 0)
 | |
| 			{
 | |
| 				HMONITOR hMonitor;
 | |
| 				MONITORINFO mi;
 | |
| 
 | |
| 				hMonitor = MonitorFromWindow(m_Window, MONITOR_DEFAULTTONULL);
 | |
| 
 | |
| 				if(hMonitor != NULL)
 | |
| 				{
 | |
| 					mi.cbSize = sizeof(mi);
 | |
| 					GetMonitorInfo(hMonitor, &mi);
 | |
| 					workArea = mi.rcWork;
 | |
| 				}
 | |
| 
 | |
| 				// Snap to other windows
 | |
| 				std::map<std::wstring, CMeterWindow*>& windows = Rainmeter->GetAllMeterWindows();
 | |
| 				std::map<std::wstring, CMeterWindow*>::iterator iter = windows.begin();
 | |
| 				for( ; iter != windows.end(); iter++)
 | |
| 				{
 | |
| 					if ((*iter).second != this)
 | |
| 					{
 | |
| 						SnapToWindow((*iter).second, wp);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				int w = workArea.right - m_WindowW;
 | |
| 				int h = workArea.bottom - m_WindowH;
 | |
| 
 | |
| 				if ((wp->x < SNAPDISTANCE + workArea.left) && (wp->x > workArea.left - SNAPDISTANCE)) wp->x = workArea.left;
 | |
| 				if ((wp->y < SNAPDISTANCE + workArea.top) && (wp->y > workArea.top - SNAPDISTANCE)) wp->y = workArea.top;
 | |
| 				if ((wp->x < SNAPDISTANCE + w) && (wp->x > -SNAPDISTANCE + w)) wp->x = w;
 | |
| 				if ((wp->y < SNAPDISTANCE + h) && (wp->y > -SNAPDISTANCE + h)) wp->y = h;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (m_KeepOnScreen) 
 | |
| 		{
 | |
| 			MapCoordsToScreen(wp->x, wp->y, m_WindowW, m_WindowH);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return DefWindowProc(m_Window, m_Message, wParam, lParam);
 | |
| }
 | |
| 
 | |
| void CMeterWindow::SnapToWindow(CMeterWindow* window, LPWINDOWPOS wp)
 | |
| {
 | |
| 	int x = window->m_WindowX;
 | |
| 	int y = window->m_WindowY;
 | |
| 	int w = window->m_WindowW;
 | |
| 	int h = window->m_WindowH;
 | |
| 
 | |
| 	if (wp->y < y + h && wp->y + m_WindowH > y)
 | |
| 	{
 | |
| 		if((wp->x < SNAPDISTANCE + x) && (wp->x > x - SNAPDISTANCE)) wp->x = x;
 | |
| 		if((wp->x < SNAPDISTANCE + x + w) && (wp->x > x + w - SNAPDISTANCE)) wp->x = x + w;
 | |
| 
 | |
| 		if((wp->x + m_WindowW < SNAPDISTANCE + x) && (wp->x + m_WindowW > x - SNAPDISTANCE)) wp->x = x - m_WindowW;
 | |
| 		if((wp->x + m_WindowW < SNAPDISTANCE + x + w) && (wp->x + m_WindowW > x + w - SNAPDISTANCE)) wp->x = x + w - m_WindowW;
 | |
| 	}
 | |
| 
 | |
| 	if (wp->x < x + w && wp->x + m_WindowW > x)
 | |
| 	{
 | |
| 		if((wp->y < SNAPDISTANCE + y) && (wp->y > y - SNAPDISTANCE)) wp->y = y;
 | |
| 		if((wp->y < SNAPDISTANCE + y + h) && (wp->y > y + h - SNAPDISTANCE)) wp->y = y + h;
 | |
| 
 | |
| 		if((wp->y + m_WindowH < SNAPDISTANCE + y) && (wp->y + m_WindowH > y - SNAPDISTANCE)) wp->y = y - m_WindowH;
 | |
| 		if((wp->y + m_WindowH < SNAPDISTANCE + y + h) && (wp->y + m_WindowH > y + h - SNAPDISTANCE)) wp->y = y + h - m_WindowH;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnDestroy
 | |
| **
 | |
| ** During destruction of the window do nothing.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnDestroy(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** OnLeftButtonDown
 | |
| **
 | |
| ** Runs the action when left mouse button is down
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnLeftButtonDown(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	POINT pos;
 | |
| 	pos.x = (SHORT)LOWORD(lParam); 
 | |
| 	pos.y = (SHORT)HIWORD(lParam); 
 | |
| 
 | |
| 	if (m_Message == WM_NCLBUTTONDOWN)
 | |
| 	{
 | |
| 		// Transform the point to client rect
 | |
| 		RECT rect;
 | |
| 		GetWindowRect(m_Window, &rect);
 | |
| 		pos.x = pos.x - rect.left;
 | |
| 		pos.y = pos.y - rect.top;
 | |
| 	}
 | |
| 
 | |
| 	// Handle buttons
 | |
| 	bool redraw = false;
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		// Hidden meters are ignored
 | |
| 		if ((*j)->IsHidden()) continue;
 | |
| 
 | |
| 		CMeterButton* button = dynamic_cast<CMeterButton*>(*j);
 | |
| 		if (button)
 | |
| 		{
 | |
| 			redraw |= button->MouseDown(pos);
 | |
| 		}
 | |
| 	}
 | |
| 	if (redraw)
 | |
| 	{
 | |
| 		Redraw();
 | |
| 	}
 | |
| 	else if(!DoAction(pos.x, pos.y, MOUSE_LMB_DOWN, false))
 | |
| 	{
 | |
| 		// Run the DefWindowProc so the dragging works
 | |
| 		return DefWindowProc(m_Window, m_Message, wParam, lParam);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnLeftButtonUp
 | |
| **
 | |
| ** Runs the action when left mouse button is up
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnLeftButtonUp(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	POINT pos;
 | |
| 	pos.x = (SHORT)LOWORD(lParam); 
 | |
| 	pos.y = (SHORT)HIWORD(lParam); 
 | |
| 
 | |
| 	if (m_Message == WM_NCLBUTTONUP)
 | |
| 	{
 | |
| 		// Transform the point to client rect
 | |
| 		RECT rect;
 | |
| 		GetWindowRect(m_Window, &rect);
 | |
| 		pos.x = pos.x - rect.left;
 | |
| 		pos.y = pos.y - rect.top;
 | |
| 	}
 | |
| 
 | |
| 	// Handle buttons
 | |
| 	bool redraw = false;
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		// Hidden meters are ignored
 | |
| 		if ((*j)->IsHidden()) continue;
 | |
| 
 | |
| 		CMeterButton* button = dynamic_cast<CMeterButton*>(*j);
 | |
| 		if (button)
 | |
| 		{
 | |
| 			redraw |= button->MouseUp(pos, this);
 | |
| 		}
 | |
| 	}
 | |
| 	if (redraw)
 | |
| 	{
 | |
| 		Redraw();
 | |
| 	}
 | |
| 
 | |
| 	DoAction(pos.x, pos.y, MOUSE_LMB_UP, false);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnRightButtonDown
 | |
| **
 | |
| ** Runs the action when right mouse button is down
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnRightButtonDown(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	POINT pos;
 | |
| 	pos.x = (SHORT)LOWORD(lParam); 
 | |
| 	pos.y = (SHORT)HIWORD(lParam); 
 | |
| 
 | |
| 	if (m_Message == WM_NCRBUTTONDOWN)
 | |
| 	{
 | |
| 		// Transform the point to client rect
 | |
| 		RECT rect;
 | |
| 		GetWindowRect(m_Window, &rect);
 | |
| 		pos.x = pos.x - rect.left;
 | |
| 		pos.y = pos.y - rect.top;
 | |
| 	}
 | |
| 
 | |
| 	DoAction(pos.x, pos.y, MOUSE_RMB_DOWN, false);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnRightButtonUp
 | |
| **
 | |
| ** Runs the action when right mouse button is up
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnRightButtonUp(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	if (!DoAction((SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam), MOUSE_RMB_UP, false))
 | |
| 	{
 | |
| 		// Run the DefWindowProc so the context menu works
 | |
| 		return DefWindowProc(m_Window, WM_RBUTTONUP, wParam, lParam);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnContextMenu
 | |
| **
 | |
| ** Handles the context menu. The menu is recreated every time it is shown.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnContextMenu(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	int xPos = (SHORT)LOWORD(lParam); 
 | |
| 	int yPos = (SHORT)HIWORD(lParam); 
 | |
| 
 | |
| 	// Transform the point to client rect
 | |
| 	int x = (INT)(SHORT)LOWORD(lParam); 
 | |
| 	int y = (INT)(SHORT)HIWORD(lParam); 
 | |
| 	RECT rect;
 | |
| 	GetWindowRect(m_Window, &rect);
 | |
| 	x = x - rect.left;
 | |
| 	y = y - rect.top;
 | |
| 
 | |
| 	// If RMB up or RMB down cause actions, do not show the menu!
 | |
| 	if (DoAction(x, y, MOUSE_RMB_UP, false) || DoAction(x, y, MOUSE_RMB_DOWN, true))
 | |
| 	{
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	POINT pos;
 | |
| 	pos.x = xPos;
 | |
| 	pos.y = yPos;
 | |
| 	m_Rainmeter->ShowContextMenu(pos, this);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** DoAction
 | |
| **
 | |
| ** Executes the action if such are defined. Returns true, if action was executed.
 | |
| ** If the test is true, the action is not executed.
 | |
| **
 | |
| */
 | |
| bool CMeterWindow::DoAction(int x, int y, MOUSE mouse, bool test) 
 | |
| {
 | |
| 	// Check if the hitpoint was over some meter
 | |
| 	std::list<CMeter*>::iterator j = m_Meters.begin();
 | |
| 	for( ; j != m_Meters.end(); j++)
 | |
| 	{
 | |
| 		// Hidden meters are ignored
 | |
| 		if ((*j)->IsHidden()) continue;
 | |
| 
 | |
| 		if ((*j)->HitTest(x, y))
 | |
| 		{
 | |
| 			switch (mouse)
 | |
| 			{
 | |
| 			case MOUSE_LMB_DOWN:
 | |
| 				if (!((*j)->GetLeftMouseDownAction().empty()))
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand((*j)->GetLeftMouseDownAction().c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case MOUSE_LMB_UP:
 | |
| 				if (!((*j)->GetLeftMouseUpAction().empty()))
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand((*j)->GetLeftMouseUpAction().c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case MOUSE_RMB_DOWN:
 | |
| 				if (!((*j)->GetRightMouseDownAction().empty()))
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand((*j)->GetRightMouseDownAction().c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case MOUSE_RMB_UP:
 | |
| 				if (!((*j)->GetRightMouseUpAction().empty()))
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand((*j)->GetRightMouseUpAction().c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case MOUSE_OVER:
 | |
| 				if (!(*j)->IsMouseOver())
 | |
| 				{
 | |
| 					(*j)->SetMouseOver(true);
 | |
| 
 | |
| 					if (!((*j)->GetMouseOverAction().empty()))
 | |
| 					{
 | |
| 						m_MouseOver = true;		// If the mouse is over a meter it's also over the main window
 | |
| 						if (!test) m_Rainmeter->ExecuteCommand((*j)->GetMouseOverAction().c_str(), this);
 | |
| 						return true;
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if (mouse == MOUSE_LEAVE || mouse == MOUSE_OVER)
 | |
| 			{
 | |
| 				if ((*j)->IsMouseOver())
 | |
| 				{
 | |
| 					(*j)->SetMouseOver(false);
 | |
| 
 | |
| 					if (!((*j)->GetMouseLeaveAction().empty()))
 | |
| 					{
 | |
| 						if (!test) m_Rainmeter->ExecuteCommand((*j)->GetMouseLeaveAction().c_str(), this);
 | |
| 						return true;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	bool inside = false;
 | |
| 	if (x >= 0 && y >= 0 && x < m_WindowW && y < m_WindowH)
 | |
| 	{
 | |
| 		// Check transparent pixels
 | |
| 		if (m_DoubleBuffer)
 | |
| 		{
 | |
| 			Color color;
 | |
| 			m_DoubleBuffer->GetPixel(x, y, &color);
 | |
| 			if (color.GetA() != 0)
 | |
| 			{
 | |
| 				inside = true;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			inside = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (inside)
 | |
| 	{
 | |
| 		// If no meters caused actions, do the default actions
 | |
| 		switch (mouse)
 | |
| 		{
 | |
| 		case MOUSE_LMB_DOWN:
 | |
| 			if (!m_LeftMouseDownAction.empty())
 | |
| 			{
 | |
| 				if (!test) m_Rainmeter->ExecuteCommand(m_LeftMouseDownAction.c_str(), this);
 | |
| 				return true;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case MOUSE_LMB_UP:
 | |
| 			if (!m_LeftMouseUpAction.empty())
 | |
| 			{
 | |
| 				if (!test) m_Rainmeter->ExecuteCommand(m_LeftMouseUpAction.c_str(), this);
 | |
| 				return true;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case MOUSE_RMB_DOWN:
 | |
| 			if (!m_RightMouseDownAction.empty())
 | |
| 			{
 | |
| 				if (!test) m_Rainmeter->ExecuteCommand(m_RightMouseDownAction.c_str(), this);
 | |
| 				return true;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case MOUSE_RMB_UP:
 | |
| 			if (!m_RightMouseUpAction.empty())
 | |
| 			{
 | |
| 				if (!test) m_Rainmeter->ExecuteCommand(m_RightMouseUpAction.c_str(), this);
 | |
| 				return true;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case MOUSE_OVER:
 | |
| 			if (!m_MouseOver)
 | |
| 			{
 | |
| 				m_MouseOver = true;
 | |
| 				if (!m_MouseOverAction.empty())
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand(m_MouseOverAction.c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// Mouse leave happens when the mouse is outside the window
 | |
| 		if (mouse == MOUSE_LEAVE)
 | |
| 		{
 | |
| 			if (m_MouseOver)
 | |
| 			{
 | |
| 				m_MouseOver = false;
 | |
| 				if (!m_MouseLeaveAction.empty())
 | |
| 				{
 | |
| 					if (!test) m_Rainmeter->ExecuteCommand(m_MouseLeaveAction.c_str(), this);
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** OnMove
 | |
| **
 | |
| ** Stores the new place of the window so that it can be written in the config file.
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnMove(WPARAM wParam, LPARAM lParam) 
 | |
| {
 | |
| 	// Store the new window position
 | |
| 	m_WindowX = (SHORT)LOWORD(lParam);
 | |
| 	m_WindowY = (SHORT)HIWORD(lParam);
 | |
| 
 | |
| 	if (m_SavePosition)
 | |
| 	{
 | |
| 		WriteConfig();
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* 
 | |
| ** WndProc
 | |
| **
 | |
| ** The window procedure for the Meter
 | |
| **
 | |
| */
 | |
| LRESULT CALLBACK CMeterWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
| 	CMeterWindow* Window = NULL;
 | |
| 
 | |
| 	if(uMsg == WM_CREATE) 
 | |
| 	{
 | |
| 		// Fetch this window-object from the CreateStruct
 | |
| 		Window=(CMeterWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
 | |
| 
 | |
| 		SetProp(hWnd, L"RAINMETER", Window);
 | |
| 	}
 | |
| 	else if(uMsg == WM_DESTROY) 
 | |
| 	{
 | |
| 		RemoveProp(hWnd, L"RAINMETER");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		Window = (CMeterWindow*)GetProp(hWnd, L"RAINMETER");
 | |
| 	}
 | |
| 
 | |
| 	if (Window) Window->m_Message = uMsg;
 | |
| 
 | |
| 	BEGIN_MESSAGEPROC
 | |
| 	MESSAGE(OnPaint, WM_PAINT)
 | |
| 	MESSAGE(OnMove, WM_MOVE)
 | |
| 	MESSAGE(OnCreate, WM_CREATE)
 | |
| 	MESSAGE(OnDestroy, WM_DESTROY)
 | |
| 	MESSAGE(OnTimer, WM_TIMER)
 | |
| 	MESSAGE(OnCommand, WM_COMMAND)
 | |
| 	MESSAGE(OnNcHitTest, WM_NCHITTEST)
 | |
| 	MESSAGE(OnMouseMove, WM_MOUSEMOVE)
 | |
| 	MESSAGE(OnMouseMove, WM_NCMOUSEMOVE)
 | |
| 	MESSAGE(OnContextMenu, WM_CONTEXTMENU)
 | |
| 	MESSAGE(OnRightButtonDown, WM_NCRBUTTONDOWN)
 | |
| 	MESSAGE(OnRightButtonDown, WM_RBUTTONDOWN)
 | |
| 	MESSAGE(OnRightButtonUp, WM_RBUTTONUP)
 | |
| 	MESSAGE(OnContextMenu, WM_NCRBUTTONUP)
 | |
| 	MESSAGE(OnLeftButtonDown, WM_NCLBUTTONDOWN)
 | |
| 	MESSAGE(OnLeftButtonDown, WM_LBUTTONDOWN)
 | |
| 	MESSAGE(OnLeftButtonUp, WM_LBUTTONUP)
 | |
| 	MESSAGE(OnLeftButtonUp, WM_NCLBUTTONUP)
 | |
| 	MESSAGE(OnWindowPosChanging, WM_WINDOWPOSCHANGING)
 | |
| 	MESSAGE(OnCopyData, WM_COPYDATA)
 | |
| 	MESSAGE(OnDelayedExecute, WM_DELAYED_EXECUTE)
 | |
| 	END_MESSAGEPROC
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** OnDelayedExecute
 | |
| **
 | |
| ** Handles delayed executes
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnDelayedExecute(WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
| 	if (lParam)
 | |
| 	{
 | |
| 		LPCTSTR szExecute = (LPCTSTR)lParam;
 | |
| 		COPYDATASTRUCT copyData;
 | |
| 
 | |
| 		copyData.dwData = 1;
 | |
| 		copyData.cbData = (DWORD)((lstrlen(szExecute))* sizeof(WCHAR));
 | |
| 		copyData.lpData = (void*)szExecute;
 | |
| 
 | |
| 		OnCopyData(NULL, (LPARAM)©Data);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** OnCopyData
 | |
| **
 | |
| ** Handles bangs from the exe
 | |
| **
 | |
| */
 | |
| LRESULT CMeterWindow::OnCopyData(WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
| 	COPYDATASTRUCT* pCopyDataStruct = (COPYDATASTRUCT*) lParam;
 | |
| 
 | |
| 	if (pCopyDataStruct && (pCopyDataStruct->dwData == 1) && (pCopyDataStruct->cbData > 0))
 | |
| 	{
 | |
| 		// Check that we're still alive
 | |
| 		bool found = false;
 | |
| 		std::map<std::wstring, CMeterWindow*>& meters = Rainmeter->GetAllMeterWindows();
 | |
| 		std::map<std::wstring, CMeterWindow*>::iterator iter = meters.begin();
 | |
| 
 | |
| 		for ( ; iter != meters.end(); iter++)
 | |
| 		{
 | |
| 			if ((*iter).second == this)
 | |
| 			{
 | |
| 				found = true;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		if (!found) 
 | |
| 		{
 | |
| 			DebugLog(L"Unable to send the !bang to a deactivated config.");
 | |
| 			return 0;	// This meterwindow has been deactivated
 | |
| 		}
 | |
| 
 | |
| 		std::wstring str = (const WCHAR*)pCopyDataStruct->lpData;
 | |
| 		std::wstring bang;
 | |
| 		std::wstring arg;
 | |
| 
 | |
| 		// Find the first space
 | |
| 		std::wstring::size_type pos = str.find(' ');
 | |
| 		if (pos != std::wstring::npos)
 | |
| 		{
 | |
| 			bang = str.substr(0, pos);
 | |
| 			str.erase(0, pos + 1);
 | |
| 			arg = str;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			bang = str;
 | |
| 		}
 | |
| 
 | |
| 		// Add the current config name to the args. If it's not defined already
 | |
| 		// the bang only affects this config, if there already is a config defined
 | |
| 		// another one doesn't matter.
 | |
| 		arg += L" \"";
 | |
| 		arg += m_SkinName.c_str();
 | |
| 		arg += L"\"";
 | |
| 
 | |
| 		return Rainmeter->ExecuteBang(bang, arg, this);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return FALSE;
 | |
| 	}
 | |
| }
 | |
| 
 | 
