GUI/ShowDesktop.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 176 c16fd81b520a
child 344 3145aadca3d2
permissions -rw-r--r--
Fixed a problem, where the MainForm location and size was lost when the application is started minimized and exited without ever showing the form. This caused MainForm_Load to be never called (location and size was not loaded), but the default size and location were still saved. The new implementation only saves the location and size when one of the two is changed.
moel@176
     1
/*
moel@176
     2
  
moel@176
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@176
     4
moel@176
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@176
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@176
     7
  the License. You may obtain a copy of the License at
moel@176
     8
 
moel@176
     9
  http://www.mozilla.org/MPL/
moel@176
    10
moel@176
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@176
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@176
    13
  for the specific language governing rights and limitations under the License.
moel@176
    14
moel@176
    15
  The Original Code is the Open Hardware Monitor code.
moel@176
    16
moel@176
    17
  The Initial Developer of the Original Code is 
moel@176
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@176
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@176
    20
  the Initial Developer. All Rights Reserved.
moel@176
    21
moel@176
    22
  Contributor(s):
moel@176
    23
moel@176
    24
  Alternatively, the contents of this file may be used under the terms of
moel@176
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@176
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@176
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@176
    28
  of those above. If you wish to allow use of your version of this file only
moel@176
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@176
    30
  use your version of this file under the terms of the MPL, indicate your
moel@176
    31
  decision by deleting the provisions above and replace them with the notice
moel@176
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@176
    33
  the provisions above, a recipient may use your version of this file under
moel@176
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@176
    35
 
moel@176
    36
*/
moel@176
    37
moel@176
    38
using System;
moel@176
    39
using System.Runtime.InteropServices;
moel@176
    40
using System.Windows.Forms;
moel@176
    41
moel@176
    42
namespace OpenHardwareMonitor.GUI {
moel@176
    43
  public class ShowDesktop {
moel@176
    44
    private static ShowDesktop instance = new ShowDesktop();
moel@176
    45
moel@176
    46
    public delegate void ShowDesktopChangedEventHandler(bool showDesktop);
moel@176
    47
    
moel@176
    48
    private event ShowDesktopChangedEventHandler ShowDesktopChangedEvent;
moel@176
    49
moel@176
    50
    private System.Threading.Timer timer;
moel@176
    51
    private bool showDesktop = false;   
moel@176
    52
    private NativeWindow referenceWindow;
moel@176
    53
    private string referenceWindowCaption =
moel@176
    54
      "OpenHardwareMonitorShowDesktopReferenceWindow";
moel@176
    55
moel@176
    56
    private ShowDesktop() {
moel@176
    57
      // create a reference window to detect show desktop
moel@176
    58
      referenceWindow = new NativeWindow();
moel@176
    59
      CreateParams cp = new CreateParams();
moel@176
    60
      cp.ExStyle = GadgetWindow.WS_EX_TOOLWINDOW;
moel@176
    61
      cp.Caption = referenceWindowCaption;
moel@176
    62
      referenceWindow.CreateHandle(cp);
moel@176
    63
      NativeMethods.SetWindowPos(referenceWindow.Handle, 
moel@176
    64
        GadgetWindow.HWND_BOTTOM, 0, 0, 0, 0, GadgetWindow.SWP_NOMOVE | 
moel@176
    65
        GadgetWindow.SWP_NOSIZE | GadgetWindow.SWP_NOACTIVATE | 
moel@176
    66
        GadgetWindow.SWP_NOSENDCHANGING);
moel@176
    67
moel@176
    68
      // start a repeated timer to detect "Show Desktop" events 
moel@176
    69
      timer = new System.Threading.Timer(OnTimer, null,
moel@176
    70
        System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
moel@176
    71
    }
moel@176
    72
moel@176
    73
    private void StartTimer() {
moel@176
    74
      timer.Change(0, 200);
moel@176
    75
    }
moel@176
    76
moel@176
    77
    private void StopTimer() {
moel@176
    78
      timer.Change(System.Threading.Timeout.Infinite,
moel@176
    79
        System.Threading.Timeout.Infinite);
moel@176
    80
    }
moel@176
    81
moel@176
    82
    // the desktop worker window (if available) can hide the reference window
moel@176
    83
    private IntPtr GetDesktopWorkerWindow() {
moel@176
    84
      IntPtr shellWindow = NativeMethods.GetShellWindow();
moel@176
    85
      if (shellWindow == IntPtr.Zero)
moel@176
    86
        return IntPtr.Zero;
moel@176
    87
moel@176
    88
      int shellId;
moel@176
    89
      NativeMethods.GetWindowThreadProcessId(shellWindow, out shellId);
moel@176
    90
moel@176
    91
      IntPtr workerWindow = IntPtr.Zero;
moel@176
    92
      while ((workerWindow = NativeMethods.FindWindowEx(
moel@176
    93
          IntPtr.Zero, workerWindow, "WorkerW", null)) != IntPtr.Zero) {
moel@176
    94
moel@176
    95
        int workerId;
moel@176
    96
        NativeMethods.GetWindowThreadProcessId(workerWindow, out workerId);
moel@176
    97
        if (workerId == shellId) {
moel@176
    98
          IntPtr window = NativeMethods.FindWindowEx(
moel@176
    99
            workerWindow, IntPtr.Zero, "SHELLDLL_DefView", null);
moel@176
   100
          if (window != IntPtr.Zero) {
moel@176
   101
            IntPtr desktopWindow = NativeMethods.FindWindowEx(
moel@176
   102
              window, IntPtr.Zero, "SysListView32", null);
moel@176
   103
            if (desktopWindow != IntPtr.Zero)
moel@176
   104
              return workerWindow;
moel@176
   105
          }
moel@176
   106
        }
moel@176
   107
      }
moel@176
   108
      return IntPtr.Zero;
moel@176
   109
    }
moel@176
   110
moel@176
   111
    private void OnTimer(Object state) {
moel@176
   112
      bool showDesktopDetected;
moel@176
   113
moel@176
   114
      IntPtr workerWindow = GetDesktopWorkerWindow();
moel@176
   115
      if (workerWindow != IntPtr.Zero) {
moel@176
   116
        // search if the reference window is behind the worker window
moel@176
   117
        IntPtr reference = NativeMethods.FindWindowEx(
moel@176
   118
          IntPtr.Zero, workerWindow, null, referenceWindowCaption);
moel@179
   119
        showDesktopDetected = reference != IntPtr.Zero;
moel@176
   120
      } else {
moel@176
   121
        // if there is no worker window, then nothing can hide the reference
moel@176
   122
        showDesktopDetected = false;
moel@176
   123
      }
moel@176
   124
moel@176
   125
      if (showDesktop != showDesktopDetected) {
moel@176
   126
        showDesktop = showDesktopDetected;
moel@176
   127
        if (ShowDesktopChangedEvent != null) {
moel@176
   128
          ShowDesktopChangedEvent(showDesktop);
moel@176
   129
        }
moel@176
   130
      }
moel@176
   131
    }
moel@176
   132
moel@176
   133
    public static ShowDesktop Instance {
moel@176
   134
      get { return instance; }
moel@176
   135
    }
moel@176
   136
moel@176
   137
    // notify when the "show desktop" mode is changed
moel@176
   138
    public event ShowDesktopChangedEventHandler ShowDesktopChanged {
moel@176
   139
      add {
moel@176
   140
        // start the monitor timer when someone is listening
moel@176
   141
        if (ShowDesktopChangedEvent == null)           
moel@176
   142
          StartTimer();
moel@176
   143
        ShowDesktopChangedEvent += value;
moel@176
   144
      }
moel@176
   145
      remove {
moel@176
   146
        ShowDesktopChangedEvent -= value;
moel@176
   147
        // stop the monitor timer if nobody is interested
moel@176
   148
        if (ShowDesktopChangedEvent == null)
moel@176
   149
          StopTimer();
moel@176
   150
      }
moel@176
   151
    }
moel@176
   152
moel@176
   153
    private static class NativeMethods {
moel@176
   154
      private const string USER = "user32.dll";
moel@176
   155
moel@176
   156
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   157
      public static extern bool SetWindowPos(IntPtr hWnd,
moel@176
   158
        IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
moel@176
   159
moel@176
   160
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   161
      public static extern IntPtr FindWindowEx(IntPtr hwndParent,
moel@176
   162
        IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
moel@176
   163
moel@176
   164
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   165
      public static extern IntPtr GetShellWindow();
moel@176
   166
moel@176
   167
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   168
      public static extern int GetWindowThreadProcessId(IntPtr hWnd,
moel@176
   169
        out int processId);
moel@176
   170
    }  
moel@176
   171
  }
moel@176
   172
}