From 06ec730bfd586a5c5bbb75156455716792af674e Mon Sep 17 00:00:00 2001 From: spx Date: Sat, 20 Mar 2010 19:40:30 +0000 Subject: [PATCH] - Added the workaround to pin the window to desktop in Vista/7 with Aero. - Added !RainmeterSetTransparency, !RainmeterShowFade, !RainmeterHideFade, !RainmeterToggleFade. - Added the function to log the installed font families to the log file when Debug=1 is set. - Added the workaround for issue 145. The wrong drawing position was fixed when AntiAlias=0 is set. --- Library/ConfigParser.cpp | 9 +- Library/ConfigParser.h | 6 +- Library/Library.vcproj | 8 + Library/MeasureNet.cpp | 5 + Library/MeasurePlugin.cpp | 18 + Library/MeterImage.cpp | 9 +- Library/MeterString.cpp | 56 +++ Library/MeterString.h | 1 + Library/MeterWindow.cpp | 784 +++++++++++++------------------------ Library/MeterWindow.h | 34 +- Library/Rainmeter.cpp | 243 ++++++++++-- Library/Rainmeter.h | 2 +- Library/System.cpp | 793 ++++++++++++++++++++++++++++++++++++++ Library/System.h | 80 ++++ Library/TrayWindow.cpp | 26 -- 15 files changed, 1453 insertions(+), 621 deletions(-) create mode 100644 Library/System.cpp create mode 100644 Library/System.h diff --git a/Library/ConfigParser.cpp b/Library/ConfigParser.cpp index d2fce8a4..9df1fa40 100644 --- a/Library/ConfigParser.cpp +++ b/Library/ConfigParser.cpp @@ -20,6 +20,7 @@ #include "ConfigParser.h" #include "Litestep.h" #include "Rainmeter.h" +#include "System.h" #include extern CRainmeter* Rainmeter; @@ -219,9 +220,9 @@ void CConfigParser::SetMultiMonitorVariables(bool reset) SetMonitorVariable(L"VSCREENAREAHEIGHT", buffer); } - if (CMeterWindow::GetMonitorCount() > 0) + if (CSystem::GetMonitorCount() > 0) { - const MULTIMONITOR_INFO& multimonInfo = CMeterWindow::GetMultiMonitorInfo(); + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); const std::vector& monitors = multimonInfo.monitors; for (size_t i = 0; i < monitors.size(); i++) @@ -290,12 +291,12 @@ void CConfigParser::SetAutoSelectedMonitorVariables(CMeterWindow* meterWindow) if (meterWindow) { - if (CMeterWindow::GetMonitorCount() > 0) + if (CSystem::GetMonitorCount() > 0) { TCHAR buffer[256]; int w1, w2, s1, s2; - const MULTIMONITOR_INFO& multimonInfo = CMeterWindow::GetMultiMonitorInfo(); + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); const std::vector& monitors = multimonInfo.monitors; if (meterWindow->GetXScreenDefined()) diff --git a/Library/ConfigParser.h b/Library/ConfigParser.h index a02e0d98..97117f3f 100644 --- a/Library/ConfigParser.h +++ b/Library/ConfigParser.h @@ -54,11 +54,12 @@ public: std::wstring& GetFilename() { return m_Filename; } const std::vector& GetSections(); - // Returns an int if the formula was read successfully, -1 for failure. int ReadFormula(std::wstring& result, double* number); static std::vector Tokenize(const std::wstring& str, const std::wstring delimiters); + static double ParseDouble(const std::wstring& string, double defValue, bool rejectExp = false); + static Gdiplus::Color ParseColor(LPCTSTR string); static void ClearMultiMonitorVariables() { c_MonitorVariables.clear(); } static void UpdateWorkareaVariables() { SetMultiMonitorVariables(false); } @@ -68,9 +69,6 @@ private: void ReadVariables(); void ReplaceVariables(std::wstring& result); - double ParseDouble(const std::wstring& string, double defValue, bool rejectExp = false); - Gdiplus::Color ParseColor(LPCTSTR string); - void ReadIniFile(const std::wstring& strFileName, int depth = 0); void SetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strValue); const std::wstring& GetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strDefault); diff --git a/Library/Library.vcproj b/Library/Library.vcproj index 10f140e0..e2887ab0 100644 --- a/Library/Library.vcproj +++ b/Library/Library.vcproj @@ -2610,6 +2610,10 @@ /> + + @@ -2877,6 +2881,10 @@ RelativePath=".\StdAfx.h" > + + diff --git a/Library/MeasureNet.cpp b/Library/MeasureNet.cpp index 88c4c271..27d76ef6 100644 --- a/Library/MeasureNet.cpp +++ b/Library/MeasureNet.cpp @@ -682,6 +682,11 @@ void CMeasureNet::InitializeNewApi() c_FreeMibTable = NULL; } } + + if (CRainmeter::GetDebug()) + { + UpdateIFTable(); + } } /* diff --git a/Library/MeasurePlugin.cpp b/Library/MeasurePlugin.cpp index 3f60ce92..d5b5c584 100644 --- a/Library/MeasurePlugin.cpp +++ b/Library/MeasurePlugin.cpp @@ -116,16 +116,34 @@ void CMeasurePlugin::ReadConfig(CConfigParser& parser, const WCHAR* section) } m_PluginName = Rainmeter->GetPluginPath() + m_PluginName; + SetLastError(ERROR_SUCCESS); m_Plugin = LoadLibrary(m_PluginName.c_str()); if(m_Plugin == NULL) { + if (CRainmeter::GetDebug()) + { + DWORD err = GetLastError(); + DebugLog(L"Plugin: Unable to load plugin: \"%s\", ErrorCode=%i", m_PluginName.c_str(), err); + } + // Try to load from Rainmeter's folder pos = m_PluginName.rfind(L'\\'); if (pos != std::wstring::npos) { std::wstring pluginName = Rainmeter->GetPath() + m_PluginName.substr(pos + 1); + + SetLastError(ERROR_SUCCESS); m_Plugin = LoadLibrary(pluginName.c_str()); + + if (m_Plugin == NULL) + { + if (CRainmeter::GetDebug()) + { + DWORD err = GetLastError(); + DebugLog(L"Plugin: Unable to load plugin: \"%s\", ErrorCode=%i", pluginName.c_str(), err); + } + } } if (m_Plugin == NULL) diff --git a/Library/MeterImage.cpp b/Library/MeterImage.cpp index f25e5f5d..cd1f7598 100644 --- a/Library/MeterImage.cpp +++ b/Library/MeterImage.cpp @@ -643,10 +643,11 @@ bool CMeterImage::Draw(Graphics& graphics) drawH = m_H; } - //if (m_AntiAlias && m_Rotate != 0.0f) - //{ - // graphics.SetCompositingQuality(CompositingQualityHighQuality); - //} + if (!m_AntiAlias) + { + //graphics.SetInterpolationMode(InterpolationModeNearestNeighbor); + graphics.SetPixelOffsetMode(PixelOffsetModeHalf); + } Rect r(x, y, drawW, drawH); graphics.DrawImage(drawBitmap, r, 0, 0, imageW, imageH, UnitPixel); diff --git a/Library/MeterString.cpp b/Library/MeterString.cpp index c1e3e602..e68eb180 100644 --- a/Library/MeterString.cpp +++ b/Library/MeterString.cpp @@ -717,4 +717,60 @@ std::wstring StringToProper(std::wstring str) return str;//return the converted string } +/* +** EnumerateInstalledFontFamilies +** +** Static helper to log all installed font families. +** +*/ +void CMeterString::EnumerateInstalledFontFamilies() +{ + INT fontCount; + InstalledFontCollection fontCollection; + + if (Ok == fontCollection.GetLastStatus()) + { + fontCount = fontCollection.GetFamilyCount(); + if (fontCount > 0) + { + INT fontFound; + + FontFamily* fontFamilies = new FontFamily[fontCount]; + + if (Ok == fontCollection.GetFamilies(fontCount, fontFamilies, &fontFound)) + { + std::wstring fonts; + for (INT i = 0; i < fontCount; i++) + { + WCHAR familyName[LF_FACESIZE]; + if (Ok == fontFamilies[i].GetFamilyName(familyName)) + { + fonts += familyName; + } + else + { + fonts += L"***"; + } + fonts += L", "; + } + LSLog(LOG_DEBUG, L"Rainmeter", fonts.c_str()); + } + else + { + LSLog(LOG_DEBUG, L"Rainmeter", L"Failed to enumerate installed font families: GetFamilies() failed."); + } + + delete [] fontFamilies; + } + else + { + LSLog(LOG_DEBUG, L"Rainmeter", L"There are no installed font families!"); + } + } + else + { + LSLog(LOG_DEBUG, L"Rainmeter", L"Failed to enumerate installed font families: InstalledFontCollection() failed."); + } +} + // EOF diff --git a/Library/MeterString.h b/Library/MeterString.h index ad1b5329..0f60a2b6 100644 --- a/Library/MeterString.h +++ b/Library/MeterString.h @@ -41,6 +41,7 @@ public: virtual void BindMeasure(std::list& measures); static void FreeFontCache(); + static void EnumerateInstalledFontFamilies(); private: enum TEXTSTYLE diff --git a/Library/MeterWindow.cpp b/Library/MeterWindow.cpp index c18962cd..ee3473d9 100644 --- a/Library/MeterWindow.cpp +++ b/Library/MeterWindow.cpp @@ -21,6 +21,7 @@ #include #include "MeterWindow.h" #include "Rainmeter.h" +#include "System.h" #include "Error.h" #include #include @@ -51,8 +52,6 @@ using namespace Gdiplus; int CMeterWindow::c_InstanceCount = 0; -MULTIMONITOR_INFO CMeterWindow::c_Monitors = { 0 }; - extern CRainmeter* Rainmeter; /* @@ -98,6 +97,7 @@ CMeterWindow::CMeterWindow(std::wstring& path, std::wstring& config, std::wstrin m_WindowStartHidden = false; m_SnapEdges = true; m_Rainmeter = NULL; + m_Hidden = false; m_ResetRegion = false; m_Refreshing = false; m_NativeTransparency = true; @@ -242,19 +242,7 @@ int CMeterWindow::Initialize(CRainmeter& Rainmeter) setlocale(LC_NUMERIC, "C"); // Mark the window to ignore the Aero peek - typedef HRESULT (WINAPI * FPDWMSETWINDOWATTRIBUTE)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); - #define DWMWA_EXCLUDED_FROM_PEEK 12 - HINSTANCE h = LoadLibrary(L"dwmapi.dll"); - if (h) - { - FPDWMSETWINDOWATTRIBUTE DwmSetWindowAttribute = (FPDWMSETWINDOWATTRIBUTE)GetProcAddress(h, "DwmSetWindowAttribute"); - BOOL bValue = TRUE; - if (DwmSetWindowAttribute) - { - DwmSetWindowAttribute(m_Window, DWMWA_EXCLUDED_FROM_PEEK, &bValue, sizeof(bValue)); - } - FreeLibrary(h); - } + IgnoreAeroPeek(); // Gotta have some kind of buffer during initialization m_DoubleBuffer = new Bitmap(1, 1, PixelFormat32bppARGB); @@ -277,6 +265,29 @@ int CMeterWindow::Initialize(CRainmeter& Rainmeter) return 0; } +/* +** IgnoreAeroPeek +** +** Excludes this window from the Aero Peek. +** +*/ +void CMeterWindow::IgnoreAeroPeek() +{ + typedef HRESULT (WINAPI * FPDWMSETWINDOWATTRIBUTE)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + #define DWMWA_EXCLUDED_FROM_PEEK 12 + HINSTANCE h = LoadLibrary(L"dwmapi.dll"); + if (h) + { + FPDWMSETWINDOWATTRIBUTE DwmSetWindowAttribute = (FPDWMSETWINDOWATTRIBUTE)GetProcAddress(h, "DwmSetWindowAttribute"); + if (DwmSetWindowAttribute) + { + BOOL bValue = TRUE; + DwmSetWindowAttribute(m_Window, DWMWA_EXCLUDED_FROM_PEEK, &bValue, sizeof(bValue)); + } + FreeLibrary(h); + } +} + /* ** Refresh ** @@ -350,6 +361,8 @@ void CMeterWindow::Refresh(bool init) SetWindowLong(m_Window, GWL_EXSTYLE, style & ~WS_EX_TRANSPARENT); } + m_Hidden = m_WindowStartHidden; + // Set the window region CreateRegion(true); // Clear the region Update(false); @@ -436,10 +449,10 @@ void CMeterWindow::MapCoordsToScreen(int& x, int& y, int w, int h) 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); + x = max(x, mi.rcMonitor.left); y = min(y, mi.rcMonitor.bottom - m_WindowH); + y = max(y, mi.rcMonitor.top); return; } } @@ -447,10 +460,10 @@ void CMeterWindow::MapCoordsToScreen(int& x, int& y, int w, int h) // 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); + x = max(x, workArea.left); y = min(y, workArea.bottom - m_WindowH); + y = max(y, workArea.top); } /* @@ -462,7 +475,7 @@ void CMeterWindow::MapCoordsToScreen(int& x, int& y, int w, int h) void CMeterWindow::MoveWindow(int x, int y) { // Convert the screen coordinates to the client coordinates of the shell window - if (!m_ChildWindow && !m_NativeTransparency && m_WindowZPosition == ZPOSITION_ONDESKTOP) + if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP && GetAncestor(m_Window, GA_PARENT) != GetDesktopWindow()) { POINT pos = {x, y}; if (ScreenToClient(GetAncestor(m_Window, GA_PARENT), &pos)) @@ -508,25 +521,105 @@ void CMeterWindow::ChangeZPos(ZPOSITION zPos) break; case ZPOSITION_ONDESKTOP: - // Set the window's parent to progman, so it stays always on desktop - HWND ProgmanHwnd = FindWindowEx(FindWindowEx(FindWindow(L"Progman", L"Program Manager"), NULL, L"SHELLDLL_DefView", L""), NULL, L"SysListView32", L"FolderView"); - if (!ProgmanHwnd) + if (!m_NativeTransparency || !CSystem::GetDwmCompositionEnabled()) { - HWND WorkerWHwnd = NULL; - while ((WorkerWHwnd = FindWindowEx(NULL, WorkerWHwnd, L"WorkerW", L"")) != NULL) + winPos = HWND_BOTTOM; + + // Set the window's parent to progman, so it stays always on desktop + HWND ProgmanHwnd = CSystem::GetShellDesktopWindow(); + + if (ProgmanHwnd && (parent != ProgmanHwnd)) { - ProgmanHwnd = FindWindowEx(FindWindowEx(WorkerWHwnd, NULL, L"SHELLDLL_DefView", L""), NULL, L"SysListView32", L"FolderView"); - if (ProgmanHwnd) break; + m_PreventMoving = true; // Prevent moving the window by SetParent + SetParent(m_Window, ProgmanHwnd); } - } - if (ProgmanHwnd && (parent != ProgmanHwnd)) - { - m_PreventMoving = true; // Prevent moving the window by SetParent - SetParent(m_Window, ProgmanHwnd); + //else + //{ + // return; // The window is already on desktop + //} } else { - return; // The window is already on desktop + if (parent != GetDesktopWindow()) + { + m_PreventMoving = true; // Prevent moving the window by SetParent + SetParent(m_Window, NULL); + + IgnoreAeroPeek(); + } + + if (CSystem::GetShowDesktop()) + { + bool logging = false; // Set true if you need verbose logging. + std::wstring msg; + + if (logging) + { + msg += (GetWindowLong(m_Window, GWL_EXSTYLE) & WS_EX_TOPMOST) ? L"TOPMOST" : L"NORMAL"; + } + + // Set WS_EX_TOPMOST flag + SetWindowPos(m_Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + + if (logging) + { + msg += L" - "; + msg += (GetWindowLong(m_Window, GWL_EXSTYLE) & WS_EX_TOPMOST) ? L"TOPMOST" : L"NORMAL"; + } + + // Get WorkerW window + HWND WorkerW = CSystem::GetWorkerW(); + + // Find the "backmost" topmost window + if (WorkerW) + { + HWND hwnd = WorkerW; + while (hwnd = ::GetNextWindow(hwnd, GW_HWNDPREV)) + { + if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) + { + WCHAR className[128], windowText[128]; + + if (logging) + { + GetClassName(hwnd, className, 128); + GetWindowText(hwnd, windowText, 128); + } + + if (0 == SetWindowPos(m_Window, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING)) + { + if (logging) + { + DebugLog(L" %s: hwnd=0x%08X (WorkerW=0x%08X), hwndInsertAfter=0x%08X (\"%s\" %s) - FAILED", + m_SkinName.c_str(), m_Window, WorkerW, hwnd, windowText, className); + } + continue; + } + + if (logging) + { + msg += L" - "; + msg += (GetWindowLong(m_Window, GWL_EXSTYLE) & WS_EX_TOPMOST) ? L"TOPMOST" : L"NORMAL"; + + DebugLog(L" %s: hwnd=0x%08X (WorkerW=0x%08X), hwndInsertAfter=0x%08X (\"%s\" %s) - %s", + m_SkinName.c_str(), m_Window, WorkerW, hwnd, windowText, className, msg.c_str()); + } + return; + } + } + } + + if (logging) + { + DebugLog(L" %s: hwnd=0x%08X (WorkerW=0x%08X), hwndInsertAfter=HWND_TOPMOST - %s", + m_SkinName.c_str(), m_Window, WorkerW, msg.c_str()); + } + return; + } + else + { + winPos = HWND_BOTTOM; + } } break; } @@ -535,6 +628,8 @@ void CMeterWindow::ChangeZPos(ZPOSITION zPos) { m_PreventMoving = true; // Prevent moving the window by SetParent SetParent(m_Window, NULL); + + IgnoreAeroPeek(); } bool refresh = m_Refreshing; @@ -593,24 +688,54 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const WCHAR* arg) break; case BANG_SHOW: + m_Hidden = false; ShowWindow(m_Window, SW_SHOWNOACTIVATE); + if (m_WindowHide == HIDEMODE_FADEOUT) + { + UpdateTransparency(255, false); + } + else + { + UpdateTransparency(m_AlphaValue, false); + } break; case BANG_HIDE: + m_Hidden = true; ShowWindow(m_Window, SW_HIDE); break; case BANG_TOGGLE: + RunBang(m_Hidden ? BANG_SHOW : BANG_HIDE, arg); + break; + + case BANG_SHOWFADE: + m_Hidden = false; + if (!IsWindowVisible(m_Window)) + { + if (m_WindowHide == HIDEMODE_FADEOUT) + { + FadeWindow(0, 255); + } + else + { + FadeWindow(0, m_AlphaValue); + } + } + break; + + case BANG_HIDEFADE: + m_Hidden = true; if (IsWindowVisible(m_Window)) { - ShowWindow(m_Window, SW_HIDE); - } - else - { - ShowWindow(m_Window, SW_SHOWNOACTIVATE); + FadeWindow(m_AlphaValue, 0); } break; + case BANG_TOGGLEFADE: + RunBang(m_Hidden ? BANG_SHOWFADE : BANG_HIDEFADE, arg); + break; + case BANG_MOVE: pos = wcschr(arg, ' '); if (pos != NULL) @@ -627,6 +752,16 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const WCHAR* arg) ChangeZPos((ZPOSITION)_wtoi(arg)); break; + case BANG_SETTRANSPARENCY: + if (arg != NULL) + { + int alpha = (int)CConfigParser::ParseDouble(arg, 255, true); + alpha = max(alpha, 0); + m_AlphaValue = min(alpha, 255); + UpdateTransparency(m_AlphaValue, false); + } + break; + case BANG_LSHOOK: { pos = wcsrchr(arg, ' '); @@ -939,397 +1074,6 @@ void CMeterWindow::ToggleMeasure(const WCHAR* name) DebugLog(L"Unable to toggle the measure %s (there is no such thing in %s)", name, m_SkinName.c_str()); } -/* MyInfoEnumProc -** -** Retrieves the multi-monitor information -** -*/ -BOOL CALLBACK MyInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - MULTIMONITOR_INFO* m = (MULTIMONITOR_INFO*)dwData; - - MONITORINFOEX info; - info.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfo(hMonitor, &info); - - if (CRainmeter::GetDebug()) - { - DebugLog(info.szDevice); - DebugLog(L" Flags : %s(0x%08X)", (info.dwFlags & MONITORINFOF_PRIMARY) ? L"PRIMARY " : L"", info.dwFlags); - DebugLog(L" Handle : 0x%08X", hMonitor); - DebugLog(L" ScrArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - lprcMonitor->left, lprcMonitor->top, lprcMonitor->right, lprcMonitor->bottom, - lprcMonitor->right - lprcMonitor->left, lprcMonitor->bottom - lprcMonitor->top); - DebugLog(L" WorkArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, - info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); - } - if (m == NULL) return TRUE; - - if (m->useEnumDisplayDevices) - { - for (size_t i = 0; i < m->monitors.size(); i++) - { - if (m->monitors[i].handle == NULL && _wcsnicmp(info.szDevice, m->monitors[i].deviceName, 32) == 0) - { - m->monitors[i].handle = hMonitor; - m->monitors[i].screen = *lprcMonitor; - m->monitors[i].work = info.rcWork; - break; - } - } - } - else // use only EnumDisplayMonitors - { - MONITOR_INFO monitor = {0}; - monitor.active = true; - - monitor.handle = hMonitor; - monitor.screen = *lprcMonitor; - monitor.work = info.rcWork; - - wcsncpy(monitor.deviceName, info.szDevice, 32); // E.g. "\\.\DISPLAY1" - - // Get the monitor name (E.g. "Generic Non-PnP Monitor") - DISPLAY_DEVICE ddm = {0}; - ddm.cb = sizeof(DISPLAY_DEVICE); - DWORD dwMon = 0; - while (EnumDisplayDevices(info.szDevice, dwMon++, &ddm, 0)) - { - if (ddm.StateFlags & DISPLAY_DEVICE_ACTIVE && ddm.StateFlags & DISPLAY_DEVICE_ATTACHED) - { - wcsncpy(monitor.monitorName, ddm.DeviceString, 128); - break; - } - } - - m->monitors.push_back(monitor); - - if (info.dwFlags & MONITORINFOF_PRIMARY) - { - // It's primary monitor! - m->primary = (int)m->monitors.size(); - } - } - - return TRUE; -} - -/* GetMonitorCount -** -** Returns the number of monitors -** -*/ -size_t CMeterWindow::GetMonitorCount() -{ - if (c_Monitors.monitors.size() == 0) - { - SetMultiMonitorInfo(); - } - return c_Monitors.monitors.size(); -} - -/* SetMultiMonitorInfo -** -** Sets the multi-monitor information -** -*/ -void CMeterWindow::SetMultiMonitorInfo() -{ - std::vector& monitors = c_Monitors.monitors; - bool logging = CRainmeter::GetDebug(); - - if (monitors.capacity() < 16) { monitors.reserve(16); } - - c_Monitors.vsT = GetSystemMetrics(SM_YVIRTUALSCREEN); - c_Monitors.vsL = GetSystemMetrics(SM_XVIRTUALSCREEN); - c_Monitors.vsH = GetSystemMetrics(SM_CYVIRTUALSCREEN); - c_Monitors.vsW = GetSystemMetrics(SM_CXVIRTUALSCREEN); - - c_Monitors.primary = 1; // If primary screen is not found, 1st screen is assumed as primary screen. - - c_Monitors.useEnumDisplayDevices = true; - c_Monitors.useEnumDisplayMonitors = false; - - if (logging) - { - DebugLog(L"------------------------------"); - DebugLog(L"* EnumDisplayDevices / EnumDisplaySettings API"); - } - - DISPLAY_DEVICE dd = {0}; - dd.cb = sizeof(DISPLAY_DEVICE); - - if (EnumDisplayDevices(NULL, 0, &dd, 0)) - { - DWORD dwDevice = 0; - - do - { - std::wstring msg; - - if (logging) - { - DebugLog(dd.DeviceName); - - if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) - { - msg += L"ACTIVE "; - } - if (dd.StateFlags & DISPLAY_DEVICE_MULTI_DRIVER) - { - msg += L"MULTI "; - } - if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - { - msg += L"PRIMARY "; - } - if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) - { - msg += L"MIRROR "; - } - if (dd.StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) - { - msg += L"VGA "; - } - if (dd.StateFlags & DISPLAY_DEVICE_REMOVABLE) - { - msg += L"REMOVABLE "; - } - if (dd.StateFlags & DISPLAY_DEVICE_MODESPRUNED) - { - msg += L"PRUNED "; - } - if (dd.StateFlags & DISPLAY_DEVICE_REMOTE) - { - msg += L"REMOTE "; - } - if (dd.StateFlags & DISPLAY_DEVICE_DISCONNECT) - { - msg += L"DISCONNECT "; - } - } - - if ((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0) - { - MONITOR_INFO monitor = {0}; - - monitor.handle = NULL; - wcsncpy(monitor.deviceName, dd.DeviceName, 32); // E.g. "\\.\DISPLAY1" - - // Get the monitor name (E.g. "Generic Non-PnP Monitor") - DISPLAY_DEVICE ddm = {0}; - ddm.cb = sizeof(DISPLAY_DEVICE); - DWORD dwMon = 0; - while (EnumDisplayDevices(dd.DeviceName, dwMon++, &ddm, 0)) - { - if (ddm.StateFlags & DISPLAY_DEVICE_ACTIVE && ddm.StateFlags & DISPLAY_DEVICE_ATTACHED) - { - wcsncpy(monitor.monitorName, ddm.DeviceString, 128); - - if (logging) - { - DebugLog(L" Name : %s", ddm.DeviceString); - } - break; - } - } - - if (logging) - { - DebugLog(L" Adapter : %s", dd.DeviceString); - DebugLog(L" Flags : %s(0x%08X)", msg.c_str(), dd.StateFlags); - } - - if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) - { - monitor.active = true; - - DEVMODE dm = {0}; - dm.dmSize = sizeof(DEVMODE); - - if (EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) - { - POINT pos = {dm.dmPosition.x, dm.dmPosition.y}; - monitor.handle = MonitorFromPoint(pos, MONITOR_DEFAULTTONULL); - - if (logging) - { - DebugLog(L" Handle : 0x%08X", monitor.handle); - } - } - - if (monitor.handle != NULL) - { - MONITORINFO info = {0}; - info.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(monitor.handle, &info); - - monitor.screen = info.rcMonitor; - monitor.work = info.rcWork; - - if (logging) - { - DebugLog(L" ScrArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right, info.rcMonitor.bottom, - info.rcMonitor.right - info.rcMonitor.left, info.rcMonitor.bottom - info.rcMonitor.top); - DebugLog(L" WorkArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, - info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); - } - } - else // monitor not found - { - c_Monitors.useEnumDisplayMonitors = true; - } - } - else - { - monitor.active = false; - } - - monitors.push_back(monitor); - - if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - { - // It's primary monitor! - c_Monitors.primary = (int)monitors.size(); - } - } - else - { - if (logging) - { - DebugLog(L" Adapter : %s", dd.DeviceString); - DebugLog(L" Flags : %s(0x%08X)", msg.c_str(), dd.StateFlags); - } - } - dwDevice++; - } while (EnumDisplayDevices(NULL, dwDevice, &dd, 0)); - } - - if (monitors.empty()) // Failed to enumerate the non-mirroring monitors - { - DebugLog(L"Failed to enumerate the non-mirroring monitors. Only EnumDisplayMonitors is used instead."); - c_Monitors.useEnumDisplayDevices = false; - c_Monitors.useEnumDisplayMonitors = true; - } - - if (logging) - { - DebugLog(L"------------------------------"); - DebugLog(L"* EnumDisplayMonitors API"); - } - - if (c_Monitors.useEnumDisplayMonitors) - { - EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, (LPARAM)(&c_Monitors)); - - if (monitors.empty()) // Failed to enumerate the monitors - { - DebugLog(L"Failed to enumerate the monitors. Prepares the dummy monitor information."); - c_Monitors.useEnumDisplayMonitors = false; - - MONITOR_INFO monitor = {0}; - wcscpy(monitor.deviceName, L"DUMMY"); - POINT pos = {0, 0}; - monitor.handle = MonitorFromPoint(pos, MONITOR_DEFAULTTOPRIMARY); - monitor.screen.left = 0; - monitor.screen.top = 0; - monitor.screen.right = GetSystemMetrics(SM_CXSCREEN); - monitor.screen.bottom = GetSystemMetrics(SM_CYSCREEN); - SystemParametersInfo(SPI_GETWORKAREA, 0, &(monitor.work), 0); - monitor.active = true; - - monitors.push_back(monitor); - - c_Monitors.primary = 1; - } - } - else - { - if (logging) - { - EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, (LPARAM)NULL); // Only logging - } - } - - if (logging) - { - DebugLog(L"------------------------------"); - - std::wstring method = L"* METHOD: "; - if (c_Monitors.useEnumDisplayDevices) - { - method += L"EnumDisplayDevices + "; - method += c_Monitors.useEnumDisplayMonitors ? L"EnumDisplayMonitors Mode" : L"EnumDisplaySettings Mode"; - } - else - { - method += c_Monitors.useEnumDisplayMonitors ? L"EnumDisplayMonitors Mode" : L"Dummy Mode"; - } - DebugLog(method.c_str()); - - DebugLog(L"* MONITORS: Count=%i, Primary=@%i", monitors.size(), c_Monitors.primary); - DebugLog(L"@0: Virtual screen"); - DebugLog(L" L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - c_Monitors.vsL, c_Monitors.vsT, c_Monitors.vsL + c_Monitors.vsW, c_Monitors.vsT + c_Monitors.vsH, - c_Monitors.vsW, c_Monitors.vsH); - - for (size_t i = 0; i < monitors.size(); i++) - { - if (monitors[i].active) - { - DebugLog(L"@%i: %s (active), MonitorName: %s", i + 1, monitors[i].deviceName, monitors[i].monitorName); - DebugLog(L" L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - monitors[i].screen.left, monitors[i].screen.top, monitors[i].screen.right, monitors[i].screen.bottom, - monitors[i].screen.right - monitors[i].screen.left, monitors[i].screen.bottom - monitors[i].screen.top); - } - else - { - DebugLog(L"@%i: %s (inactive), MonitorName: %s", i + 1, monitors[i].deviceName, monitors[i].monitorName); - } - } - DebugLog(L"------------------------------"); - } -} - -/* UpdateWorkareaInfo -** -** Updates the workarea information -** -*/ -void CMeterWindow::UpdateWorkareaInfo() -{ - std::vector& monitors = c_Monitors.monitors; - - if (monitors.empty()) - { - SetMultiMonitorInfo(); - return; - } - - for (size_t i = 0; i < monitors.size(); i++) - { - if (monitors[i].active && monitors[i].handle != NULL) - { - MONITORINFO info = {0}; - info.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(monitors[i].handle, &info); - - monitors[i].work = info.rcWork; - - if (CRainmeter::GetDebug()) - { - DebugLog(L"WorkArea @%i : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", - i + 1, - info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, - info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); - } - } - } -} - /* WindowToScreen ** ** Calculates the screen cordinates from the WindowX/Y config @@ -1337,27 +1081,22 @@ void CMeterWindow::UpdateWorkareaInfo() */ void CMeterWindow::WindowToScreen() { + if (CSystem::GetMonitorCount() == 0) + { + DebugLog(L"There are no monitors. WindowToScreen function fails."); + return; + } + std::wstring::size_type index, index2; int pixel = 0; float num; int screenx, screeny, screenh, screenw; - std::vector& monitors = c_Monitors.monitors; - - if (monitors.empty()) - { - // Retrieve the multi-monitor information - SetMultiMonitorInfo(); - - if (monitors.empty()) - { - DebugLog(L"There are no monitors. WindowToScreen function fails."); - return; - } - } + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); + const std::vector& monitors = multimonInfo.monitors; // Clear position flags - m_WindowXScreen = m_WindowYScreen = c_Monitors.primary; // Default to primary screen + m_WindowXScreen = m_WindowYScreen = multimonInfo.primary; // Default to primary screen m_WindowXScreenDefined = m_WindowYScreenDefined = false; m_WindowXFromRight = m_WindowYFromBottom = false; // Default to from left/top m_WindowXPercentage = m_WindowYPercentage = false; // Default to pixels @@ -1459,8 +1198,8 @@ void CMeterWindow::WindowToScreen() } if (m_WindowXScreen == 0) { - screenx = c_Monitors.vsL; - screenw = c_Monitors.vsW; + screenx = multimonInfo.vsL; + screenw = multimonInfo.vsW; } else { @@ -1526,8 +1265,8 @@ void CMeterWindow::WindowToScreen() } if (m_WindowYScreen == 0) { - screeny = c_Monitors.vsT; - screenh = c_Monitors.vsH; + screeny = multimonInfo.vsT; + screenh = multimonInfo.vsH; } else { @@ -1565,7 +1304,8 @@ void CMeterWindow::ScreenToWindow() float num; int screenx, screeny, screenh, screenw; - std::vector& monitors = c_Monitors.monitors; + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); + const std::vector& monitors = multimonInfo.monitors; if (monitors.empty()) { @@ -1606,8 +1346,8 @@ void CMeterWindow::ScreenToWindow() if (m_WindowXScreen == 0) { - screenx = c_Monitors.vsL; - screenw = c_Monitors.vsW; + screenx = multimonInfo.vsL; + screenw = multimonInfo.vsW; } else { @@ -1647,8 +1387,8 @@ void CMeterWindow::ScreenToWindow() if (m_WindowYScreen == 0) { - screeny = c_Monitors.vsT; - screenh = c_Monitors.vsH; + screeny = multimonInfo.vsT; + screenh = multimonInfo.vsH; } else { @@ -2506,7 +2246,6 @@ void CMeterWindow::Update(bool nodraw) // Statistics CMeasureNet::UpdateStats(); - OutputDebugString(L"Butts"); Rainmeter->WriteStats(false); if (!nodraw) @@ -2778,7 +2517,10 @@ void CMeterWindow::FadeWindow(int from, int to) } if (from == 0) { - ShowWindow(m_Window, SW_SHOWNOACTIVATE); + if (!m_Hidden) + { + ShowWindow(m_Window, SW_SHOWNOACTIVATE); + } } } } @@ -2789,7 +2531,10 @@ void CMeterWindow::FadeWindow(int from, int to) UpdateTransparency(from, false); if (from == 0) { - ShowWindow(m_Window, SW_SHOWNOACTIVATE); + if (!m_Hidden) + { + ShowWindow(m_Window, SW_SHOWNOACTIVATE); + } } SetTimer(m_Window, FADETIMER, 10, NULL); @@ -2846,7 +2591,7 @@ void CMeterWindow::ShowWindowIfAppropriate() if(m_WindowHide) { - if (!inside && !keyDown) + if (!m_Hidden && !inside && !keyDown) { switch(m_WindowHide) { @@ -2859,14 +2604,14 @@ void CMeterWindow::ShowWindowIfAppropriate() break; case HIDEMODE_FADEIN: - if (m_TransparencyValue == 255) + if (m_AlphaValue != 255 && m_TransparencyValue == 255) { FadeWindow(255, m_AlphaValue); } break; case HIDEMODE_FADEOUT: - if (m_TransparencyValue == m_AlphaValue) + if (m_AlphaValue != 255 && m_TransparencyValue == m_AlphaValue) { FadeWindow(m_AlphaValue, 255); } @@ -2874,6 +2619,17 @@ void CMeterWindow::ShowWindowIfAppropriate() } } } + else + { + if (!m_Hidden) + { + if (m_TransparencyValue == 0 || !IsWindowVisible(m_Window)) + { + ShowWindow(m_Window, SW_SHOWNOACTIVATE); + FadeWindow(0, m_AlphaValue); + } + } + } } @@ -2898,29 +2654,32 @@ LRESULT CMeterWindow::OnMouseMove(WPARAM wParam, LPARAM lParam) } } - // If Alt, shift or control is down, do not hide the window - switch(m_WindowHide) + if (!m_Hidden) { - case HIDEMODE_HIDE: - if (m_TransparencyValue == m_AlphaValue) + // If Alt, shift or control is down, do not hide the window + switch(m_WindowHide) { - FadeWindow(m_AlphaValue, 0); - } - break; + case HIDEMODE_HIDE: + if (!m_NativeTransparency || m_TransparencyValue == m_AlphaValue) + { + FadeWindow(m_AlphaValue, 0); + } + break; - case HIDEMODE_FADEIN: - if (m_TransparencyValue == m_AlphaValue) - { - FadeWindow(m_AlphaValue, 255); - } - break; + case HIDEMODE_FADEIN: + if (m_AlphaValue != 255 && m_TransparencyValue == m_AlphaValue) + { + FadeWindow(m_AlphaValue, 255); + } + break; - case HIDEMODE_FADEOUT: - if (m_TransparencyValue == 255) - { - FadeWindow(255, m_AlphaValue); + case HIDEMODE_FADEOUT: + if (m_AlphaValue != 255 && m_TransparencyValue == 255) + { + FadeWindow(255, m_AlphaValue); + } + break; } - break; } } @@ -3068,7 +2827,16 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) { m_ClickThrough = !m_ClickThrough; WriteConfig(); - Refresh(false); + + if (!m_ClickThrough) + { + // 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); + } + } } else if(wParam == ID_CONTEXT_SKINMENU_DRAGGABLE) { @@ -3086,8 +2854,8 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) m_WindowHide = HIDEMODE_NONE; } WriteConfig(); - Refresh(false); - } + UpdateTransparency(m_AlphaValue, false); + } else if(wParam == ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEIN) { if (m_WindowHide == HIDEMODE_NONE) @@ -3099,7 +2867,7 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) m_WindowHide = HIDEMODE_NONE; } WriteConfig(); - Refresh(false); + UpdateTransparency(m_AlphaValue, false); } else if(wParam == ID_CONTEXT_SKINMENU_TRANSPARENCY_FADEOUT) { @@ -3112,7 +2880,7 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) m_WindowHide = HIDEMODE_NONE; } WriteConfig(); - Refresh(false); + UpdateTransparency(m_AlphaValue, false); } else if(wParam == ID_CONTEXT_SKINMENU_REMEMBERPOSITION) { @@ -3128,7 +2896,7 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) { 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); + UpdateTransparency(m_AlphaValue, false); } else if(wParam == ID_CONTEXT_CLOSESKIN) { @@ -3197,13 +2965,14 @@ LRESULT CMeterWindow::OnCommand(WPARAM wParam, LPARAM lParam) } else if (wParam == ID_CONTEXT_SKINMENU_MONITOR_PRIMARY || wParam >= ID_MONITOR_FIRST && wParam <= ID_MONITOR_LAST) { - std::vector& monitors = c_Monitors.monitors; + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); + const std::vector& monitors = multimonInfo.monitors; int screenIndex; bool screenDefined; if (wParam == ID_CONTEXT_SKINMENU_MONITOR_PRIMARY) { - screenIndex = c_Monitors.primary; + screenIndex = multimonInfo.primary; screenDefined = false; } else @@ -3366,10 +3135,13 @@ LRESULT CMeterWindow::OnWindowPosChanging(WPARAM wParam, LPARAM lParam) { LPWINDOWPOS wp=(LPWINDOWPOS)lParam; - if(m_WindowZPosition == ZPOSITION_ONBOTTOM && !m_Refreshing) + if (!m_Refreshing) { - // do not change the z-order. This keeps the window on bottom. - wp->flags|=SWP_NOZORDER; + if (m_WindowZPosition == ZPOSITION_ONBOTTOM || m_WindowZPosition == ZPOSITION_ONDESKTOP) + { + // do not change the z-order. This keeps the window on bottom. + wp->flags|=SWP_NOZORDER; + } } if ((wp->flags & SWP_NOMOVE) == 0) @@ -3382,30 +3154,14 @@ LRESULT CMeterWindow::OnWindowPosChanging(WPARAM wParam, LPARAM lParam) return DefWindowProc(m_Window, m_Message, wParam, lParam); } - if (m_Dragging) + // Convert the client coordinates of the shell window to the screen coordinates + if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP && (m_Dragging || !m_NativeTransparency) && GetAncestor(m_Window, GA_PARENT) != GetDesktopWindow()) { - // Convert the client coordinates of the shell window to the screen coordinates - if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP) + POINT pos = {wp->x, wp->y}; + if (ClientToScreen(GetAncestor(m_Window, GA_PARENT), &pos)) { - POINT pos = {wp->x, wp->y}; - if (ClientToScreen(GetAncestor(m_Window, GA_PARENT), &pos)) - { - wp->x = pos.x; - wp->y = pos.y; - } - } - } - else - { - // Convert the client coordinates of the shell window to the screen coordinates - if (!m_ChildWindow && !m_NativeTransparency && m_WindowZPosition == ZPOSITION_ONDESKTOP) - { - POINT pos = {wp->x, wp->y}; - if (ClientToScreen(GetAncestor(m_Window, GA_PARENT), &pos)) - { - wp->x = pos.x; - wp->y = pos.y; - } + wp->x = pos.x; + wp->y = pos.y; } } @@ -3459,7 +3215,7 @@ LRESULT CMeterWindow::OnWindowPosChanging(WPARAM wParam, LPARAM lParam) } // Convert the screen coordinates to the client coordinates of the shell window - if (!m_ChildWindow && !m_NativeTransparency && m_WindowZPosition == ZPOSITION_ONDESKTOP) + if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP && GetAncestor(m_Window, GA_PARENT) != GetDesktopWindow()) { POINT pos = {wp->x, wp->y}; if (ScreenToClient(GetAncestor(m_Window, GA_PARENT), &pos)) @@ -3994,8 +3750,8 @@ bool CMeterWindow::DoAction(int x, int y, MOUSE mouse, bool test) if (m_DoubleBuffer) { Color color; - m_DoubleBuffer->GetPixel(x, y, &color); - if (color.GetA() != 0) + Status status = m_DoubleBuffer->GetPixel(x, y, &color); + if (status != Ok || color.GetA() > 0) { inside = true; } @@ -4133,7 +3889,7 @@ LRESULT CMeterWindow::OnMove(WPARAM wParam, LPARAM lParam) m_ScreenY = (SHORT)HIWORD(lParam); // Convert the client coordinates of the shell window to the screen coordinates - if (!m_ChildWindow && !m_NativeTransparency && m_WindowZPosition == ZPOSITION_ONDESKTOP) + if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP && GetAncestor(m_Window, GA_PARENT) != GetDesktopWindow()) { POINT pos = {m_ScreenX, m_ScreenY}; if (ClientToScreen(GetAncestor(m_Window, GA_PARENT), &pos)) @@ -4149,7 +3905,7 @@ LRESULT CMeterWindow::OnMove(WPARAM wParam, LPARAM lParam) } // Redraw itself if the window is "On Desktop" - if (m_WindowZPosition == ZPOSITION_ONDESKTOP) + if (!m_ChildWindow && m_WindowZPosition == ZPOSITION_ONDESKTOP && m_NativeTransparency && GetAncestor(m_Window, GA_PARENT) != GetDesktopWindow()) { UpdateTransparency(m_TransparencyValue, false); } diff --git a/Library/MeterWindow.h b/Library/MeterWindow.h index 01134698..eb5d9f33 100644 --- a/Library/MeterWindow.h +++ b/Library/MeterWindow.h @@ -99,8 +99,12 @@ enum BANGCOMMAND BANG_SHOW, BANG_HIDE, BANG_TOGGLE, + BANG_SHOWFADE, + BANG_HIDEFADE, + BANG_TOGGLEFADE, BANG_MOVE, BANG_ZPOS, + BANG_SETTRANSPARENCY, BANG_LSHOOK, BANG_ABOUT, BANG_MOVEMETER, @@ -109,26 +113,6 @@ enum BANGCOMMAND BANG_SETVARIABLE }; -struct MONITOR_INFO -{ - bool active; - HMONITOR handle; - RECT screen; - RECT work; - WCHAR deviceName[32]; //Device name (E.g. "\\.\DISPLAY1") - WCHAR monitorName[128]; //Monitor name (E.g. "Generic Non-PnP Monitor") -}; - -struct MULTIMONITOR_INFO -{ - bool useEnumDisplayDevices; //If true, use EnumDisplayDevices function to obtain the multi-monitor information - bool useEnumDisplayMonitors; //If true, use EnumDisplayMonitors function to obtain the multi-monitor information - - int vsT, vsL, vsH, vsW; //Coordinates of the top-left corner (vsT,vsL) and size (vsH,vsW) of the virtual screen - int primary; //Index of the primary monitor - std::vector monitors; //Monitor information -}; - class CRainmeter; class CMeasure; class CMeter; @@ -200,11 +184,6 @@ public: Gdiplus::PrivateFontCollection* GetPrivateFontCollection(){ return m_FontCollection; } - static const MULTIMONITOR_INFO& GetMultiMonitorInfo() { return c_Monitors; } - static void ClearMultiMonitorInfo() { c_Monitors.monitors.clear(); } - static size_t GetMonitorCount(); - static void UpdateWorkareaInfo(); - protected: static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -255,8 +234,7 @@ private: void ShowWindowIfAppropriate(); bool DoAction(int x, int y, MOUSE mouse, bool test); bool ResizeWindow(bool reset); - - static void SetMultiMonitorInfo(); + void IgnoreAeroPeek(); CConfigParser m_Parser; @@ -360,8 +338,6 @@ private: static int c_InstanceCount; - static MULTIMONITOR_INFO c_Monitors; // Multi-Monitor info - Gdiplus::PrivateFontCollection* m_FontCollection; bool m_MouseActionCursor; diff --git a/Library/Rainmeter.cpp b/Library/Rainmeter.cpp index d8ad7b89..8a85feae 100644 --- a/Library/Rainmeter.cpp +++ b/Library/Rainmeter.cpp @@ -18,6 +18,7 @@ #include "StdAfx.h" #include "Rainmeter.h" +#include "System.h" #include "Error.h" #include "AboutDialog.h" #include "MeasureNet.h" @@ -244,11 +245,55 @@ void BangWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs) else { // No config defined -> apply to all. + + // Make the sending order by using order of the config sections + std::vector sections; + { + CConfigParser parser; + parser.Initialize(Rainmeter->GetIniFile().c_str(), Rainmeter); + sections = parser.GetSections(); + } + std::vector windows(sections.size(), NULL); + std::vector windowsMissing; + std::map::iterator iter = Rainmeter->GetAllMeterWindows().begin(); for (; iter != Rainmeter->GetAllMeterWindows().end(); iter++) { - ((*iter).second)->RunBang(bang, argument.c_str()); + CMeterWindow* window = (*iter).second; + bool find = false; + + for (size_t i = 0; i < windows.size(); i++) + { + if (windows[i] == NULL && wcsicmp(sections[i].c_str(), window->GetSkinName().c_str()) == 0) + { + windows[i] = window; + find = true; + break; + } + } + + if (!find) // Not found for some reasons + { + windowsMissing.push_back(window); + } + } + + // Apply to all + std::vector::const_reverse_iterator iter2 = windows.rbegin(); + for ( ; iter2 != windows.rend(); iter2++) + { + if (*iter2) + { + (*iter2)->RunBang(bang, argument.c_str()); + } + } + for (size_t i = 0; i < windowsMissing.size(); i++) + { + if (windowsMissing[i]) + { + windowsMissing[i]->RunBang(bang, argument.c_str()); + } } } } @@ -293,6 +338,39 @@ void RainmeterToggle(HWND, const char* arg) BangWithArgs(BANG_TOGGLE, ConvertToWide(arg).c_str(), 0); } +/* +** RainmeterHideFade +** +** Callback for the !RainmeterHideFade bang +** +*/ +void RainmeterHideFade(HWND, const char* arg) +{ + BangWithArgs(BANG_HIDEFADE, ConvertToWide(arg).c_str(), 0); +} + +/* +** RainmeterShowFade +** +** Callback for the !RainmeterShowFade bang +** +*/ +void RainmeterShowFade(HWND, const char* arg) +{ + BangWithArgs(BANG_SHOWFADE, ConvertToWide(arg).c_str(), 0); +} + +/* +** RainmeterToggleFade +** +** Callback for the !RainmeterToggleFade bang +** +*/ +void RainmeterToggleFade(HWND, const char* arg) +{ + BangWithArgs(BANG_TOGGLEFADE, ConvertToWide(arg).c_str(), 0); +} + /* ** RainmeterHideMeter ** @@ -511,6 +589,17 @@ void RainmeterZPos(HWND, const char* arg) BangWithArgs(BANG_ZPOS, ConvertToWide(arg).c_str(), 1); } +/* +** RainmeterSetTransparency +** +** Callback for the !RainmeterSetTransparency bang +** +*/ +void RainmeterSetTransparency(HWND, const char* arg) +{ + BangWithArgs(BANG_SETTRANSPARENCY, ConvertToWide(arg).c_str(), 1); +} + /* ** RainmeterLsHook ** @@ -662,6 +751,8 @@ CRainmeter::~CRainmeter() CMeterString::FreeFontCache(); + CSystem::Finalize(); + GdiplusShutdown(m_GDIplusToken); } @@ -865,6 +956,18 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath) CheckSkinVersions(); } + // Read Debug first + c_Debug = 0!=GetPrivateProfileInt(L"Rainmeter", L"Debug", 0, m_IniFile.c_str()); + + CSystem::Initialize(Instance); + CMeasureNet::InitializeNewApi(); + + if (c_Debug) + { + LSLog(LOG_DEBUG, L"Rainmeter", L"Enumerating installed font families ..."); + CMeterString::EnumerateInstalledFontFamilies(); + } + // Tray must exist before configs are read m_TrayWindow = new CTrayWindow(m_Instance); @@ -884,8 +987,6 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath) CheckUpdate(); } - CMeasureNet::InitializeNewApi(); - ResetStats(); ReadStats(); @@ -915,6 +1016,9 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath) AddBangCommand("!RainmeterHide", RainmeterHide); AddBangCommand("!RainmeterShow", RainmeterShow); AddBangCommand("!RainmeterToggle", RainmeterToggle); + AddBangCommand("!RainmeterHideFade", RainmeterHideFade); + AddBangCommand("!RainmeterShowFade", RainmeterShowFade); + AddBangCommand("!RainmeterToggleFade", RainmeterToggleFade); AddBangCommand("!RainmeterHideMeter", RainmeterHideMeter); AddBangCommand("!RainmeterShowMeter", RainmeterShowMeter); AddBangCommand("!RainmeterToggleMeter", RainmeterToggleMeter); @@ -926,6 +1030,7 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath) AddBangCommand("!RainmeterDeactivateConfig", RainmeterDeactivateConfig); AddBangCommand("!RainmeterMove", RainmeterMove); AddBangCommand("!RainmeterZPos", RainmeterZPos); + AddBangCommand("!RainmeterSetTransparency", RainmeterSetTransparency); AddBangCommand("!RainmeterLsBoxHook", RainmeterLsHook); AddBangCommand("!RainmeterAbout", RainmeterAbout); AddBangCommand("!RainmeterResetStats", RainmeterResetStats); @@ -935,12 +1040,54 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath) AddBangCommand("!RainmeterSetVariable", RainmeterSetVariable); } - // Create meter windows for active configs + // Make the starting order by using order of the config sections + std::vector sections; + { + CConfigParser parser; + parser.Initialize(m_IniFile.c_str(), this); + sections = parser.GetSections(); + } + std::vector > startup(sections.size(), std::pair(0, 0)); + std::vector > startupMissing; + for (size_t i = 0; i < m_ConfigStrings.size(); i++) { if (m_ConfigStrings[i].active > 0 && m_ConfigStrings[i].active <= (int)m_ConfigStrings[i].iniFiles.size()) { - ActivateConfig(i, m_ConfigStrings[i].active - 1); + bool find = false; + + for (size_t j = 0; j < startup.size(); j++) + { + if (startup[j].second == 0 && wcsicmp(sections[j].c_str(), m_ConfigStrings[i].config.c_str()) == 0) + { + startup[j].first = i; + startup[j].second = m_ConfigStrings[i].active; + find = true; + break; + } + } + + if (!find) // Not found for some reasons + { + startupMissing.push_back(std::pair(i, m_ConfigStrings[i].active)); + } + } + } + + // Create meter windows for active configs + std::vector >::const_reverse_iterator iter = startup.rbegin(); + for ( ; iter != startup.rend(); iter++) + { + if ((*iter).second > 0) + { + ActivateConfig((*iter).first, (*iter).second - 1); + } + } + for (size_t i = 0; i < startupMissing.size(); i++) + { + if (startupMissing[i].second > 0) + { + ActivateConfig(startupMissing[i].first, startupMissing[i].second - 1); } } @@ -1278,7 +1425,8 @@ bool CRainmeter::DeleteMeterWindow(CMeterWindow* meterWindow, bool bLater) if (bLater) { m_DelayDeleteList.push_back(meterWindow); - meterWindow->FadeWindow(meterWindow->GetAlphaValue(), 0); // Fade out the window + meterWindow->RunBang(BANG_HIDEFADE, NULL); // Fade out the window + //meterWindow->FadeWindow(meterWindow->GetAlphaValue(), 0); // Fade out the window } else { @@ -1344,6 +1492,9 @@ void CRainmeter::Quit(HINSTANCE dllInst) RemoveBangCommand("!RainmeterHide"); RemoveBangCommand("!RainmeterShow"); RemoveBangCommand("!RainmeterToggle"); + RemoveBangCommand("!RainmeterHideFade"); + RemoveBangCommand("!RainmeterShowFade"); + RemoveBangCommand("!RainmeterToggleFade"); RemoveBangCommand("!RainmeterHideMeter"); RemoveBangCommand("!RainmeterShowMeter"); RemoveBangCommand("!RainmeterToggleMeter"); @@ -1355,6 +1506,7 @@ void CRainmeter::Quit(HINSTANCE dllInst) RemoveBangCommand("!RainmeterToggleConfig"); RemoveBangCommand("!RainmeterMove"); RemoveBangCommand("!RainmeterZPos"); + RemoveBangCommand("!RainmeterSetTransparency"); RemoveBangCommand("!RainmeterLsBoxHook"); RemoveBangCommand("!RainmeterAbout"); RemoveBangCommand("!RainmeterResetStats"); @@ -1518,6 +1670,18 @@ BOOL CRainmeter::ExecuteBang(const std::wstring& bang, const std::wstring& arg, { BangWithArgs(BANG_TOGGLE, arg.c_str(), 0); } + else if (wcsicmp(bang.c_str(), L"!RainmeterHideFade") == 0) + { + BangWithArgs(BANG_HIDEFADE, arg.c_str(), 0); + } + else if (wcsicmp(bang.c_str(), L"!RainmeterShowFade") == 0) + { + BangWithArgs(BANG_SHOWFADE, arg.c_str(), 0); + } + else if (wcsicmp(bang.c_str(), L"!RainmeterToggleFade") == 0) + { + BangWithArgs(BANG_TOGGLEFADE, arg.c_str(), 0); + } else if (wcsicmp(bang.c_str(), L"!RainmeterHideMeter") == 0) { BangWithArgs(BANG_HIDEMETER, arg.c_str(), 1); @@ -1566,6 +1730,10 @@ BOOL CRainmeter::ExecuteBang(const std::wstring& bang, const std::wstring& arg, { BangWithArgs(BANG_ZPOS, arg.c_str(), 1); } + else if (wcsicmp(bang.c_str(), L"!RainmeterSetTransparency") == 0) + { + BangWithArgs(BANG_SETTRANSPARENCY, arg.c_str(), 1); + } else if (wcsicmp(bang.c_str(), L"!RainmeterAbout") == 0) { BangWithArgs(BANG_ABOUT, arg.c_str(), 0); @@ -1778,9 +1946,6 @@ void CRainmeter::ExecuteCommand(const WCHAR* command, CMeterWindow* meterWindow) */ void CRainmeter::ReadGeneralSettings(std::wstring& iniFile) { - // Read Debug first - c_Debug = 0!=GetPrivateProfileInt(L"Rainmeter", L"Debug", 0, iniFile.c_str()); - CConfigParser parser; parser.Initialize(iniFile.c_str(), this); @@ -1891,34 +2056,34 @@ bool CRainmeter::SetActiveConfig(std::wstring& skinName, std::wstring& skinIni) ** Refreshes Rainmeter. If argument is given the config is refreshed ** otherwise all active meters are refreshed */ -void CRainmeter::Refresh(const WCHAR* arg) -{ - std::wstring config, iniFile; - - try - { - if (arg != NULL && wcslen(arg) > 0) - { - std::wstring config = arg; - CMeterWindow* meterWindow = GetMeterWindow(config); - meterWindow->Refresh(false); - } - else - { - std::map::iterator iter = m_Meters.begin(); - - // Refresh all - for (; iter != m_Meters.end(); iter++) - { - (*iter).second->Refresh(false); - } - } - } - catch(CError& error) - { - MessageBox(NULL, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); - } -} +//void CRainmeter::Refresh(const WCHAR* arg) +//{ +// std::wstring config, iniFile; +// +// try +// { +// if (arg != NULL && wcslen(arg) > 0) +// { +// std::wstring config = arg; +// CMeterWindow* meterWindow = GetMeterWindow(config); +// meterWindow->Refresh(false); +// } +// else +// { +// std::map::iterator iter = m_Meters.begin(); +// +// // Refresh all +// for (; iter != m_Meters.end(); iter++) +// { +// (*iter).second->Refresh(false); +// } +// } +// } +// catch(CError& error) +// { +// MessageBox(NULL, error.GetString().c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); +// } +//} /* ** ReadStats @@ -2313,11 +2478,11 @@ HMENU CRainmeter::CreateMonitorMenu(CMeterWindow* meterWindow) AppendMenu(monitorMenu, flags, ID_MONITOR_FIRST, L"@0: Virtual screen"); // for the "Specified monitor" (@n) - if (CMeterWindow::GetMonitorCount() > 0) + if (CSystem::GetMonitorCount() > 0) { AppendMenu(monitorMenu, MF_SEPARATOR, 0, NULL); - const MULTIMONITOR_INFO& multimonInfo = CMeterWindow::GetMultiMonitorInfo(); + const MULTIMONITOR_INFO& multimonInfo = CSystem::GetMultiMonitorInfo(); const std::vector& monitors = multimonInfo.monitors; for (size_t i = 0; i < monitors.size(); i++) diff --git a/Library/Rainmeter.h b/Library/Rainmeter.h index ea69b3d6..c1ec1129 100644 --- a/Library/Rainmeter.h +++ b/Library/Rainmeter.h @@ -175,7 +175,7 @@ private: void ScanForThemes(std::wstring& path); void ReadGeneralSettings(std::wstring& path); bool SetActiveConfig(std::wstring& skinName, std::wstring& skinIni); - void Refresh(const WCHAR* arg); + //void Refresh(const WCHAR* arg); HMENU CreateSkinMenu(CMeterWindow* meterWindow, int index); void ChangeSkinIndex(HMENU subMenu, int index); int ScanForConfigsRecursive(std::wstring& path, std::wstring base, int index, std::vector& menu, bool DontRecurse); diff --git a/Library/System.cpp b/Library/System.cpp new file mode 100644 index 00000000..9bfe5377 --- /dev/null +++ b/Library/System.cpp @@ -0,0 +1,793 @@ +/* + Copyright (C) 2010 spx + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "StdAfx.h" +#include "System.h" +#include "Litestep.h" +#include "Rainmeter.h" +#include "Error.h" + +enum TIMER +{ + TIMER_SHOWDESKTOP = 1, + TIMER_COMPOSITION = 2 +}; +enum INTERVAL +{ + INTERVAL_SHOWDESKTOP = 250, + INTERVAL_COMPOSITION = 250 +}; + +MULTIMONITOR_INFO CSystem::c_Monitors = { 0 }; + +HWND CSystem::c_Window = NULL; +bool CSystem::c_DwmCompositionEnabled = false; +bool CSystem::c_ShowDesktop = false; + +extern CRainmeter* Rainmeter; + +/* +** Initialize +** +** Creates a window to detect changes in the system. +** +*/ +void CSystem::Initialize(HINSTANCE instance) +{ + WNDCLASS wc = {0}; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.hInstance = instance; + wc.lpszClassName = L"RainmeterSystemClass"; + + RegisterClass(&wc); + + c_Window = CreateWindowEx( + WS_EX_TOOLWINDOW, + L"RainmeterSystemClass", + NULL, + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + instance, + NULL); + + SetWindowPos(c_Window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + +#ifndef _WIN64 + SetWindowLong(c_Window, GWL_USERDATA, magicDWord); +#endif + + SetMultiMonitorInfo(); + + c_DwmCompositionEnabled = (DwmIsCompositionEnabled() == TRUE); + if (c_DwmCompositionEnabled) + { + SetTimer(c_Window, TIMER_SHOWDESKTOP, INTERVAL_SHOWDESKTOP, NULL); + } +} + +/* +** Finalize +** +** Destroys a window. +** +*/ +void CSystem::Finalize() +{ + KillTimer(c_Window, TIMER_SHOWDESKTOP); + KillTimer(c_Window, TIMER_COMPOSITION); + + if (c_Window) DestroyWindow(c_Window); +} + +/* MyInfoEnumProc +** +** Retrieves the multi-monitor information. +** +*/ +BOOL CALLBACK MyInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + MULTIMONITOR_INFO* m = (MULTIMONITOR_INFO*)dwData; + + MONITORINFOEX info; + info.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(hMonitor, &info); + + if (CRainmeter::GetDebug()) + { + DebugLog(info.szDevice); + DebugLog(L" Flags : %s(0x%08X)", (info.dwFlags & MONITORINFOF_PRIMARY) ? L"PRIMARY " : L"", info.dwFlags); + DebugLog(L" Handle : 0x%08X", hMonitor); + DebugLog(L" ScrArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + lprcMonitor->left, lprcMonitor->top, lprcMonitor->right, lprcMonitor->bottom, + lprcMonitor->right - lprcMonitor->left, lprcMonitor->bottom - lprcMonitor->top); + DebugLog(L" WorkArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, + info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); + } + if (m == NULL) return TRUE; + + if (m->useEnumDisplayDevices) + { + for (size_t i = 0; i < m->monitors.size(); i++) + { + if (m->monitors[i].handle == NULL && _wcsnicmp(info.szDevice, m->monitors[i].deviceName, 32) == 0) + { + m->monitors[i].handle = hMonitor; + m->monitors[i].screen = *lprcMonitor; + m->monitors[i].work = info.rcWork; + break; + } + } + } + else // use only EnumDisplayMonitors + { + MONITOR_INFO monitor = {0}; + monitor.active = true; + + monitor.handle = hMonitor; + monitor.screen = *lprcMonitor; + monitor.work = info.rcWork; + + wcsncpy(monitor.deviceName, info.szDevice, 32); // E.g. "\\.\DISPLAY1" + + // Get the monitor name (E.g. "Generic Non-PnP Monitor") + DISPLAY_DEVICE ddm = {0}; + ddm.cb = sizeof(DISPLAY_DEVICE); + DWORD dwMon = 0; + while (EnumDisplayDevices(info.szDevice, dwMon++, &ddm, 0)) + { + if (ddm.StateFlags & DISPLAY_DEVICE_ACTIVE && ddm.StateFlags & DISPLAY_DEVICE_ATTACHED) + { + wcsncpy(monitor.monitorName, ddm.DeviceString, 128); + break; + } + } + + m->monitors.push_back(monitor); + + if (info.dwFlags & MONITORINFOF_PRIMARY) + { + // It's primary monitor! + m->primary = (int)m->monitors.size(); + } + } + + return TRUE; +} + +/* GetMonitorCount +** +** Returns the number of monitors. +** +*/ +size_t CSystem::GetMonitorCount() +{ + if (c_Monitors.monitors.size() == 0) + { + SetMultiMonitorInfo(); + } + return c_Monitors.monitors.size(); +} + +/* SetMultiMonitorInfo +** +** Sets the multi-monitor information. +** +*/ +void CSystem::SetMultiMonitorInfo() +{ + std::vector& monitors = c_Monitors.monitors; + bool logging = CRainmeter::GetDebug(); + + if (monitors.capacity() < 16) { monitors.reserve(16); } + + c_Monitors.vsT = GetSystemMetrics(SM_YVIRTUALSCREEN); + c_Monitors.vsL = GetSystemMetrics(SM_XVIRTUALSCREEN); + c_Monitors.vsH = GetSystemMetrics(SM_CYVIRTUALSCREEN); + c_Monitors.vsW = GetSystemMetrics(SM_CXVIRTUALSCREEN); + + c_Monitors.primary = 1; // If primary screen is not found, 1st screen is assumed as primary screen. + + c_Monitors.useEnumDisplayDevices = true; + c_Monitors.useEnumDisplayMonitors = false; + + if (logging) + { + DebugLog(L"------------------------------"); + DebugLog(L"* EnumDisplayDevices / EnumDisplaySettings API"); + } + + DISPLAY_DEVICE dd = {0}; + dd.cb = sizeof(DISPLAY_DEVICE); + + if (EnumDisplayDevices(NULL, 0, &dd, 0)) + { + DWORD dwDevice = 0; + + do + { + std::wstring msg; + + if (logging) + { + DebugLog(dd.DeviceName); + + if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) + { + msg += L"ACTIVE "; + } + if (dd.StateFlags & DISPLAY_DEVICE_MULTI_DRIVER) + { + msg += L"MULTI "; + } + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + msg += L"PRIMARY "; + } + if (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) + { + msg += L"MIRROR "; + } + if (dd.StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) + { + msg += L"VGA "; + } + if (dd.StateFlags & DISPLAY_DEVICE_REMOVABLE) + { + msg += L"REMOVABLE "; + } + if (dd.StateFlags & DISPLAY_DEVICE_MODESPRUNED) + { + msg += L"PRUNED "; + } + if (dd.StateFlags & DISPLAY_DEVICE_REMOTE) + { + msg += L"REMOTE "; + } + if (dd.StateFlags & DISPLAY_DEVICE_DISCONNECT) + { + msg += L"DISCONNECT "; + } + } + + if ((dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0) + { + MONITOR_INFO monitor = {0}; + + monitor.handle = NULL; + wcsncpy(monitor.deviceName, dd.DeviceName, 32); // E.g. "\\.\DISPLAY1" + + // Get the monitor name (E.g. "Generic Non-PnP Monitor") + DISPLAY_DEVICE ddm = {0}; + ddm.cb = sizeof(DISPLAY_DEVICE); + DWORD dwMon = 0; + while (EnumDisplayDevices(dd.DeviceName, dwMon++, &ddm, 0)) + { + if (ddm.StateFlags & DISPLAY_DEVICE_ACTIVE && ddm.StateFlags & DISPLAY_DEVICE_ATTACHED) + { + wcsncpy(monitor.monitorName, ddm.DeviceString, 128); + + if (logging) + { + DebugLog(L" Name : %s", ddm.DeviceString); + } + break; + } + } + + if (logging) + { + DebugLog(L" Adapter : %s", dd.DeviceString); + DebugLog(L" Flags : %s(0x%08X)", msg.c_str(), dd.StateFlags); + } + + if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) + { + monitor.active = true; + + DEVMODE dm = {0}; + dm.dmSize = sizeof(DEVMODE); + + if (EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) + { + POINT pos = {dm.dmPosition.x, dm.dmPosition.y}; + monitor.handle = MonitorFromPoint(pos, MONITOR_DEFAULTTONULL); + + if (logging) + { + DebugLog(L" Handle : 0x%08X", monitor.handle); + } + } + + if (monitor.handle != NULL) + { + MONITORINFO info = {0}; + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitor.handle, &info); + + monitor.screen = info.rcMonitor; + monitor.work = info.rcWork; + + if (logging) + { + DebugLog(L" ScrArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right, info.rcMonitor.bottom, + info.rcMonitor.right - info.rcMonitor.left, info.rcMonitor.bottom - info.rcMonitor.top); + DebugLog(L" WorkArea : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, + info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); + } + } + else // monitor not found + { + c_Monitors.useEnumDisplayMonitors = true; + } + } + else + { + monitor.active = false; + } + + monitors.push_back(monitor); + + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + // It's primary monitor! + c_Monitors.primary = (int)monitors.size(); + } + } + else + { + if (logging) + { + DebugLog(L" Adapter : %s", dd.DeviceString); + DebugLog(L" Flags : %s(0x%08X)", msg.c_str(), dd.StateFlags); + } + } + dwDevice++; + } while (EnumDisplayDevices(NULL, dwDevice, &dd, 0)); + } + + if (monitors.empty()) // Failed to enumerate the non-mirroring monitors + { + DebugLog(L"Failed to enumerate the non-mirroring monitors. Only EnumDisplayMonitors is used instead."); + c_Monitors.useEnumDisplayDevices = false; + c_Monitors.useEnumDisplayMonitors = true; + } + + if (logging) + { + DebugLog(L"------------------------------"); + DebugLog(L"* EnumDisplayMonitors API"); + } + + if (c_Monitors.useEnumDisplayMonitors) + { + EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, (LPARAM)(&c_Monitors)); + + if (monitors.empty()) // Failed to enumerate the monitors + { + DebugLog(L"Failed to enumerate the monitors. Prepares the dummy monitor information."); + c_Monitors.useEnumDisplayMonitors = false; + + MONITOR_INFO monitor = {0}; + wcscpy(monitor.deviceName, L"DUMMY"); + POINT pos = {0, 0}; + monitor.handle = MonitorFromPoint(pos, MONITOR_DEFAULTTOPRIMARY); + monitor.screen.left = 0; + monitor.screen.top = 0; + monitor.screen.right = GetSystemMetrics(SM_CXSCREEN); + monitor.screen.bottom = GetSystemMetrics(SM_CYSCREEN); + SystemParametersInfo(SPI_GETWORKAREA, 0, &(monitor.work), 0); + monitor.active = true; + + monitors.push_back(monitor); + + c_Monitors.primary = 1; + } + } + else + { + if (logging) + { + EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, (LPARAM)NULL); // Only logging + } + } + + if (logging) + { + DebugLog(L"------------------------------"); + + std::wstring method = L"* METHOD: "; + if (c_Monitors.useEnumDisplayDevices) + { + method += L"EnumDisplayDevices + "; + method += c_Monitors.useEnumDisplayMonitors ? L"EnumDisplayMonitors Mode" : L"EnumDisplaySettings Mode"; + } + else + { + method += c_Monitors.useEnumDisplayMonitors ? L"EnumDisplayMonitors Mode" : L"Dummy Mode"; + } + DebugLog(method.c_str()); + + DebugLog(L"* MONITORS: Count=%i, Primary=@%i", monitors.size(), c_Monitors.primary); + DebugLog(L"@0: Virtual screen"); + DebugLog(L" L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + c_Monitors.vsL, c_Monitors.vsT, c_Monitors.vsL + c_Monitors.vsW, c_Monitors.vsT + c_Monitors.vsH, + c_Monitors.vsW, c_Monitors.vsH); + + for (size_t i = 0; i < monitors.size(); i++) + { + if (monitors[i].active) + { + DebugLog(L"@%i: %s (active), MonitorName: %s", i + 1, monitors[i].deviceName, monitors[i].monitorName); + DebugLog(L" L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + monitors[i].screen.left, monitors[i].screen.top, monitors[i].screen.right, monitors[i].screen.bottom, + monitors[i].screen.right - monitors[i].screen.left, monitors[i].screen.bottom - monitors[i].screen.top); + } + else + { + DebugLog(L"@%i: %s (inactive), MonitorName: %s", i + 1, monitors[i].deviceName, monitors[i].monitorName); + } + } + DebugLog(L"------------------------------"); + } +} + +/* UpdateWorkareaInfo +** +** Updates the workarea information. +** +*/ +void CSystem::UpdateWorkareaInfo() +{ + std::vector& monitors = c_Monitors.monitors; + + if (monitors.empty()) + { + SetMultiMonitorInfo(); + return; + } + + for (size_t i = 0; i < monitors.size(); i++) + { + if (monitors[i].active && monitors[i].handle != NULL) + { + MONITORINFO info = {0}; + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitors[i].handle, &info); + + monitors[i].work = info.rcWork; + + if (CRainmeter::GetDebug()) + { + DebugLog(L"WorkArea @%i : L=%i, T=%i, R=%i, B=%i (W=%i, H=%i)", + i + 1, + info.rcWork.left, info.rcWork.top, info.rcWork.right, info.rcWork.bottom, + info.rcWork.right - info.rcWork.left, info.rcWork.bottom - info.rcWork.top); + } + } + } +} + +/* +** GetShellDesktopWindow +** +** Finds the Shell's desktop window. +** +*/ +HWND CSystem::GetShellDesktopWindow() +{ + HWND DesktopW = NULL; + + HWND hwnd = FindWindow(L"Progman", L"Program Manager"); + if (!hwnd) return NULL; // Default Shell (Explorer) not started + + if (!(hwnd = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", L"")) || + !(DesktopW = FindWindowEx(hwnd, NULL, L"SysListView32", L"FolderView"))) // for Windows 7 (with Aero) + { + HWND WorkerW = NULL; + while (WorkerW = FindWindowEx(NULL, WorkerW, L"WorkerW", L"")) + { + if ((hwnd = FindWindowEx(WorkerW, NULL, L"SHELLDLL_DefView", L"")) && + (DesktopW = FindWindowEx(hwnd, NULL, L"SysListView32", L"FolderView"))) break; + } + } + + return DesktopW; +} + +/* +** GetWorkerW +** +** Finds the WorkerW window. +** If the Progman or WorkerW window is not found, this function returns NULL. +** +** In Windows Vista / 7 (without Aero): +** This function returns a topmost window handle which is visible. +** +** In Windows 7 (with Aero): +** This function returns a window handle which has the "SHELLDLL_DefView". +** +*/ +HWND CSystem::GetWorkerW() +{ + HWND WorkerW = NULL; + + HWND hwnd = FindWindow(L"Progman", L"Program Manager"); + if (!hwnd) return NULL; // Default Shell (Explorer) not started + + if ((hwnd = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", L"")) && + (hwnd = FindWindowEx(hwnd, NULL, L"SysListView32", L"FolderView"))) // for Windows Vista / 7 (without Aero) + { + while (WorkerW = FindWindowEx(NULL, WorkerW, L"WorkerW", L"")) + { + if (IsWindowVisible(WorkerW)) + { + // Check whether WorkerW covers whole of the screens + WINDOWPLACEMENT wp = {sizeof(WINDOWPLACEMENT)}; + GetWindowPlacement(WorkerW, &wp); + + if (wp.rcNormalPosition.left == c_Monitors.vsL && + wp.rcNormalPosition.top == c_Monitors.vsT && + (wp.rcNormalPosition.right - wp.rcNormalPosition.left) == c_Monitors.vsW && + (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) == c_Monitors.vsH) break; + } + } + } + else // for Windows 7 (with Aero) + { + while (WorkerW = FindWindowEx(NULL, WorkerW, L"WorkerW", L"")) + { + if ((hwnd = FindWindowEx(WorkerW, NULL, L"SHELLDLL_DefView", L"")) && + FindWindowEx(hwnd, NULL, L"SysListView32", L"FolderView")) break; + } + } + + return WorkerW; +} + +/* +** MyEnumWindowsProc +** +** Retrieves the Rainmeter meter window pinned on desktop in Z-order. +** +*/ +BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + bool logging = false; // Set true if you need verbose logging. + WCHAR className[128] = {0}; + CMeterWindow* Window; + + if (GetClassName(hwnd, className, 128) > 0 && + wcscmp(className, L"RainmeterMeterWindow") == 0 && + (Window = (CMeterWindow*)GetProp(hwnd, L"RAINMETER"))) + { + if (Window->GetWindowZPosition() == ZPOSITION_ONDESKTOP) + { + if (logging) DebugLog(L"+ [%c] 0x%08X : %s (Name: \"%s\")", IsWindowVisible(hwnd) ? L'V' : L'H', hwnd, className, Window->GetSkinName().c_str()); + + if (lParam) + { + ((std::vector*)lParam)->push_back(Window); + } + } + else + { + if (logging) DebugLog(L"- [%c] 0x%08X : %s (Name: \"%s\")", IsWindowVisible(hwnd) ? L'V' : L'H', hwnd, className, Window->GetSkinName().c_str()); + } + } + else + { + if (logging) DebugLog(L" [%c] 0x%08X : %s", IsWindowVisible(hwnd) ? L'V' : L'H', hwnd, className); + } + + return TRUE; +} + +/* +** ChangeZPosInOrder +** +** Arranges the meter window in Z-order. +** +*/ +void CSystem::ChangeZPosInOrder() +{ + if (Rainmeter) + { + bool logging = false; // Set true if you need verbose logging. + std::vector windowsInZOrder; + + if (logging) LSLog(LOG_DEBUG, L"Rainmeter", L"1: -----"); + + // Retrieve the Rainmeter meter window in Z-order + if (logging) LSLog(LOG_DEBUG, L"Rainmeter", L" [Top-level window]"); + EnumWindows(MyEnumWindowsProc, (LPARAM)(&windowsInZOrder)); + + HWND DesktopW = GetShellDesktopWindow(); + if (DesktopW) + { + if (logging) LSLog(LOG_DEBUG, L"Rainmeter", L" [Child of Shell's desktop window]"); + EnumChildWindows(DesktopW, MyEnumWindowsProc, (LPARAM)(&windowsInZOrder)); + } + + if (logging) LSLog(LOG_DEBUG, L"Rainmeter", L"2: -----"); + + // Reset ZPos in Z-order + for (size_t i = 0; i < windowsInZOrder.size(); i++) + { + windowsInZOrder[i]->ChangeZPos(ZPOSITION_ONDESKTOP); // reset + } + + if (logging) + { + LSLog(LOG_DEBUG, L"Rainmeter", L"3: -----"); + LSLog(LOG_DEBUG, L"Rainmeter", L" [Top-level window]"); + + // Log all windows in Z-order + EnumWindows(MyEnumWindowsProc, (LPARAM)NULL); + + if (DesktopW) + { + LSLog(LOG_DEBUG, L"Rainmeter", L" [Child of Shell's desktop window]"); + EnumChildWindows(DesktopW, MyEnumWindowsProc, (LPARAM)NULL); + } + } + } +} + +/* +** WndProc +** +** The window procedure +** +*/ +LRESULT CALLBACK CSystem::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static int DesktopCompositionCheckCount = 0; + + switch (uMsg) + { + case WM_WINDOWPOSCHANGING: + ((LPWINDOWPOS)lParam)->flags |= SWP_NOZORDER; + return 0; + + case WM_TIMER: + switch (wParam) + { + case TIMER_SHOWDESKTOP: + { + HWND WorkerW = GetWorkerW(), hwnd = NULL; + + if (WorkerW) + { + hwnd = FindWindowEx(NULL, WorkerW, L"RainmeterSystemClass", L""); + } + + if ((hwnd && !c_ShowDesktop) || (!hwnd && c_ShowDesktop)) + { + c_ShowDesktop = !c_ShowDesktop; + + if (CRainmeter::GetDebug()) + { + DebugLog(L"System: %s", + c_ShowDesktop ? L"\"Show the desktop\" has been detected." : L"\"Show open windows\" has been detected."); + } + + ChangeZPosInOrder(); + } + } + return 0; + + case TIMER_COMPOSITION: + { + if (GetShellDesktopWindow() || DesktopCompositionCheckCount >= 10) // 250ms * 10 = 2.5s + { + KillTimer(c_Window, TIMER_COMPOSITION); + + ChangeZPosInOrder(); + + if (c_DwmCompositionEnabled) + { + SetTimer(c_Window, TIMER_SHOWDESKTOP, INTERVAL_SHOWDESKTOP, NULL); + } + } + else + { + DesktopCompositionCheckCount++; + } + } + return 0; + } + break; + + case WM_DWMCOMPOSITIONCHANGED: + DebugLog(L"System: DWM desktop composition has been changed."); + + KillTimer(c_Window, TIMER_SHOWDESKTOP); + KillTimer(c_Window, TIMER_COMPOSITION); + + c_DwmCompositionEnabled = (DwmIsCompositionEnabled() == TRUE); + + DesktopCompositionCheckCount = 0; + SetTimer(c_Window, TIMER_COMPOSITION, INTERVAL_COMPOSITION, NULL); + + return 0; + + case WM_DISPLAYCHANGE: + DebugLog(L"System: Display setting has been changed."); + ClearMultiMonitorInfo(); + CConfigParser::ClearMultiMonitorVariables(); + case WM_SETTINGCHANGE: + if (uMsg == WM_DISPLAYCHANGE || (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA)) + { + if (uMsg == WM_SETTINGCHANGE) // SPI_SETWORKAREA + { + DebugLog(L"System: Work area has been changed."); + UpdateWorkareaInfo(); + CConfigParser::UpdateWorkareaVariables(); + } + + if (Rainmeter) + { + // Deliver WM_DISPLAYCHANGE / WM_SETTINGCHANGE message to all meter windows + std::map& windows = Rainmeter->GetAllMeterWindows(); + std::map::const_iterator iter = windows.begin(); + for( ; iter != windows.end(); iter++) + { + PostMessage((*iter).second->GetWindow(), WM_DELAYED_MOVE, (WPARAM)uMsg, (LPARAM)0); + } + } + } + return 0; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +/* +** DwmIsCompositionEnabled +** +** Returns TRUE if the DWM desktop composition is enabled. +** +*/ +BOOL CSystem::DwmIsCompositionEnabled() +{ + BOOL fEnabled = FALSE; + + typedef HRESULT (WINAPI * FPDWMISCOMPOSITIONENABLED)(BOOL* pfEnabled); + HINSTANCE h = LoadLibrary(L"dwmapi.dll"); + if (h) + { + FPDWMISCOMPOSITIONENABLED DwmIsCompositionEnabled = (FPDWMISCOMPOSITIONENABLED)GetProcAddress(h, "DwmIsCompositionEnabled"); + if (DwmIsCompositionEnabled) + { + if (DwmIsCompositionEnabled(&fEnabled) != S_OK) + { + fEnabled = FALSE; + } + } + FreeLibrary(h); + } + return fEnabled; +} diff --git a/Library/System.h b/Library/System.h new file mode 100644 index 00000000..fccaec6c --- /dev/null +++ b/Library/System.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2010 spx + + 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. +*/ + +#ifndef __RAINMETER_SYSTEM_H__ +#define __RAINMETER_SYSTEM_H__ + +#pragma warning(disable: 4786) + +#include +#include + +struct MONITOR_INFO +{ + bool active; + HMONITOR handle; + RECT screen; + RECT work; + WCHAR deviceName[32]; //Device name (E.g. "\\.\DISPLAY1") + WCHAR monitorName[128]; //Monitor name (E.g. "Generic Non-PnP Monitor") +}; + +struct MULTIMONITOR_INFO +{ + bool useEnumDisplayDevices; //If true, use EnumDisplayDevices function to obtain the multi-monitor information + bool useEnumDisplayMonitors; //If true, use EnumDisplayMonitors function to obtain the multi-monitor information + + int vsT, vsL, vsH, vsW; //Coordinates of the top-left corner (vsT,vsL) and size (vsH,vsW) of the virtual screen + int primary; //Index of the primary monitor + std::vector monitors; //Monitor information +}; + +class CSystem +{ +public: + static void Initialize(HINSTANCE instance); + static void Finalize(); + + static const MULTIMONITOR_INFO& GetMultiMonitorInfo() { return c_Monitors; } + static size_t GetMonitorCount(); + + static bool GetDwmCompositionEnabled() { return c_DwmCompositionEnabled; } + static bool GetShowDesktop() { return c_ShowDesktop; } + + static HWND GetShellDesktopWindow(); + static HWND GetWorkerW(); + +private: + static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static BOOL DwmIsCompositionEnabled(); + + static void SetMultiMonitorInfo(); + static void ClearMultiMonitorInfo() { c_Monitors.monitors.clear(); } + static void UpdateWorkareaInfo(); + + static void ChangeZPosInOrder(); + + static HWND c_Window; + + static MULTIMONITOR_INFO c_Monitors; // Multi-Monitor info + + static bool c_DwmCompositionEnabled; + static bool c_ShowDesktop; +}; + +#endif diff --git a/Library/TrayWindow.cpp b/Library/TrayWindow.cpp index 3cce51d8..c5cfa0b3 100644 --- a/Library/TrayWindow.cpp +++ b/Library/TrayWindow.cpp @@ -649,32 +649,6 @@ LRESULT CALLBACK CTrayWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return strlen(Buffer); } return 0; - - // --- for CMeterWindow --- - - case WM_DISPLAYCHANGE: - DebugLog(L"* Display setting has been changed."); - CMeterWindow::ClearMultiMonitorInfo(); - CConfigParser::ClearMultiMonitorVariables(); - case WM_SETTINGCHANGE: - if (uMsg == WM_DISPLAYCHANGE || (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA)) - { - if (uMsg == WM_SETTINGCHANGE) // SPI_SETWORKAREA - { - DebugLog(L"* Work area has been changed."); - CMeterWindow::UpdateWorkareaInfo(); - CConfigParser::UpdateWorkareaVariables(); - } - - // Deliver WM_DISPLAYCHANGE / WM_SETTINGCHANGE message to all meter windows - std::map& windows = Rainmeter->GetAllMeterWindows(); - std::map::iterator iter = windows.begin(); - for( ; iter != windows.end(); iter++) - { - PostMessage((*iter).second->GetWindow(), WM_DELAYED_MOVE, (WPARAM)uMsg, (LPARAM)0); - } - } - return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam);