moel@176: /* moel@176: moel@176: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@176: moel@176: The contents of this file are subject to the Mozilla Public License Version moel@176: 1.1 (the "License"); you may not use this file except in compliance with moel@176: the License. You may obtain a copy of the License at moel@176: moel@176: http://www.mozilla.org/MPL/ moel@176: moel@176: Software distributed under the License is distributed on an "AS IS" basis, moel@176: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@176: for the specific language governing rights and limitations under the License. moel@176: moel@176: The Original Code is the Open Hardware Monitor code. moel@176: moel@176: The Initial Developer of the Original Code is moel@176: Michael Möller . moel@176: Portions created by the Initial Developer are Copyright (C) 2010 moel@176: the Initial Developer. All Rights Reserved. moel@176: moel@176: Contributor(s): moel@176: moel@176: Alternatively, the contents of this file may be used under the terms of moel@176: either the GNU General Public License Version 2 or later (the "GPL"), or moel@176: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@176: in which case the provisions of the GPL or the LGPL are applicable instead moel@176: of those above. If you wish to allow use of your version of this file only moel@176: under the terms of either the GPL or the LGPL, and not to allow others to moel@176: use your version of this file under the terms of the MPL, indicate your moel@176: decision by deleting the provisions above and replace them with the notice moel@176: and other provisions required by the GPL or the LGPL. If you do not delete moel@176: the provisions above, a recipient may use your version of this file under moel@176: the terms of any one of the MPL, the GPL or the LGPL. moel@176: 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@176: showDesktopDetected = reference == referenceWindow.Handle; 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: }