moel@176: /* moel@176: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@176: moel@344: Copyright (C) 2010 Michael Möller moel@344: moel@176: */ moel@176: moel@176: using System; moel@176: using System.Runtime.InteropServices; moel@176: using System.Windows.Forms; moel@176: moel@176: namespace OpenHardwareMonitor.GUI { moel@176: public class ShowDesktop { moel@176: private static ShowDesktop instance = new ShowDesktop(); moel@176: moel@176: public delegate void ShowDesktopChangedEventHandler(bool showDesktop); moel@176: moel@176: private event ShowDesktopChangedEventHandler ShowDesktopChangedEvent; moel@176: moel@176: private System.Threading.Timer timer; moel@176: private bool showDesktop = false; moel@176: private NativeWindow referenceWindow; moel@176: private string referenceWindowCaption = moel@176: "OpenHardwareMonitorShowDesktopReferenceWindow"; moel@176: moel@176: private ShowDesktop() { moel@176: // create a reference window to detect show desktop moel@176: referenceWindow = new NativeWindow(); moel@176: CreateParams cp = new CreateParams(); moel@176: cp.ExStyle = GadgetWindow.WS_EX_TOOLWINDOW; moel@176: cp.Caption = referenceWindowCaption; moel@176: referenceWindow.CreateHandle(cp); moel@176: NativeMethods.SetWindowPos(referenceWindow.Handle, moel@176: GadgetWindow.HWND_BOTTOM, 0, 0, 0, 0, GadgetWindow.SWP_NOMOVE | moel@176: GadgetWindow.SWP_NOSIZE | GadgetWindow.SWP_NOACTIVATE | moel@176: GadgetWindow.SWP_NOSENDCHANGING); moel@176: moel@176: // start a repeated timer to detect "Show Desktop" events moel@176: timer = new System.Threading.Timer(OnTimer, null, moel@176: System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); moel@176: } moel@176: moel@176: private void StartTimer() { moel@176: timer.Change(0, 200); moel@176: } moel@176: moel@176: private void StopTimer() { moel@176: timer.Change(System.Threading.Timeout.Infinite, moel@176: System.Threading.Timeout.Infinite); moel@176: } moel@176: moel@176: // the desktop worker window (if available) can hide the reference window moel@176: private IntPtr GetDesktopWorkerWindow() { moel@176: IntPtr shellWindow = NativeMethods.GetShellWindow(); moel@176: if (shellWindow == IntPtr.Zero) moel@176: return IntPtr.Zero; moel@176: moel@176: int shellId; moel@176: NativeMethods.GetWindowThreadProcessId(shellWindow, out shellId); moel@176: moel@176: IntPtr workerWindow = IntPtr.Zero; moel@176: while ((workerWindow = NativeMethods.FindWindowEx( moel@176: IntPtr.Zero, workerWindow, "WorkerW", null)) != IntPtr.Zero) { moel@176: moel@176: int workerId; moel@176: NativeMethods.GetWindowThreadProcessId(workerWindow, out workerId); moel@176: if (workerId == shellId) { moel@176: IntPtr window = NativeMethods.FindWindowEx( moel@176: workerWindow, IntPtr.Zero, "SHELLDLL_DefView", null); moel@176: if (window != IntPtr.Zero) { moel@176: IntPtr desktopWindow = NativeMethods.FindWindowEx( moel@176: window, IntPtr.Zero, "SysListView32", null); moel@176: if (desktopWindow != IntPtr.Zero) moel@176: return workerWindow; moel@176: } moel@176: } moel@176: } moel@176: return IntPtr.Zero; moel@176: } moel@176: moel@176: private void OnTimer(Object state) { moel@176: bool showDesktopDetected; moel@176: moel@176: IntPtr workerWindow = GetDesktopWorkerWindow(); moel@176: if (workerWindow != IntPtr.Zero) { moel@176: // search if the reference window is behind the worker window moel@176: IntPtr reference = NativeMethods.FindWindowEx( moel@176: IntPtr.Zero, workerWindow, null, referenceWindowCaption); moel@179: showDesktopDetected = reference != IntPtr.Zero; moel@176: } else { moel@176: // if there is no worker window, then nothing can hide the reference moel@176: showDesktopDetected = false; moel@176: } moel@176: moel@176: if (showDesktop != showDesktopDetected) { moel@176: showDesktop = showDesktopDetected; moel@176: if (ShowDesktopChangedEvent != null) { moel@176: ShowDesktopChangedEvent(showDesktop); moel@176: } moel@176: } moel@176: } moel@176: moel@176: public static ShowDesktop Instance { moel@176: get { return instance; } moel@176: } moel@176: moel@176: // notify when the "show desktop" mode is changed moel@176: public event ShowDesktopChangedEventHandler ShowDesktopChanged { moel@176: add { moel@176: // start the monitor timer when someone is listening moel@176: if (ShowDesktopChangedEvent == null) moel@176: StartTimer(); moel@176: ShowDesktopChangedEvent += value; moel@176: } moel@176: remove { moel@176: ShowDesktopChangedEvent -= value; moel@176: // stop the monitor timer if nobody is interested moel@176: if (ShowDesktopChangedEvent == null) moel@176: StopTimer(); moel@176: } moel@176: } moel@176: moel@176: private static class NativeMethods { moel@176: private const string USER = "user32.dll"; moel@176: moel@176: [DllImport(USER, CallingConvention = CallingConvention.Winapi)] moel@176: public static extern bool SetWindowPos(IntPtr hWnd, moel@176: IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); moel@176: moel@176: [DllImport(USER, CallingConvention = CallingConvention.Winapi)] moel@176: public static extern IntPtr FindWindowEx(IntPtr hwndParent, moel@176: IntPtr hwndChildAfter, string lpszClass, string lpszWindow); moel@176: moel@176: [DllImport(USER, CallingConvention = CallingConvention.Winapi)] moel@176: public static extern IntPtr GetShellWindow(); moel@176: moel@176: [DllImport(USER, CallingConvention = CallingConvention.Winapi)] moel@176: public static extern int GetWindowThreadProcessId(IntPtr hWnd, moel@176: out int processId); moel@176: } moel@176: } moel@176: }