1.1 --- a/GUI/GadgetWindow.cs Wed Sep 08 19:29:58 2010 +0000
1.2 +++ b/GUI/GadgetWindow.cs Mon Sep 13 22:34:08 2010 +0000
1.3 @@ -42,10 +42,11 @@
1.4 using System.Windows.Forms;
1.5
1.6 namespace OpenHardwareMonitor.GUI {
1.7 +
1.8 public class GadgetWindow : NativeWindow {
1.9
1.10 private bool visible = false;
1.11 - private bool lockPosition = false;
1.12 + private bool lockPositionAndSize = false;
1.13 private bool alwaysOnTop = false;
1.14 private byte opacity = 255;
1.15 private Point location = new Point(100, 100);
1.16 @@ -100,9 +101,9 @@
1.17
1.18 protected virtual CreateParams CreateParams {
1.19 get {
1.20 - CreateParams cp = new CreateParams();
1.21 - cp.Width = size.Width;
1.22 - cp.Height = size.Height;
1.23 + CreateParams cp = new CreateParams();
1.24 + cp.Width = 4096;
1.25 + cp.Height = 4096;
1.26 cp.X = location.X;
1.27 cp.Y = location.Y;
1.28 cp.ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW;
1.29 @@ -112,57 +113,92 @@
1.30
1.31 protected override void WndProc(ref Message message) {
1.32 switch (message.Msg) {
1.33 - case WM_COMMAND:
1.34 - // need to dispatch the message for the context menu
1.35 - if (message.LParam == IntPtr.Zero)
1.36 - commandDispatch.Invoke(null, new object[] {
1.37 - message.WParam.ToInt32() & 0xFFFF });
1.38 - break;
1.39 - case WM_NCHITTEST:
1.40 - // all pixels of the form belong to the caption
1.41 - message.Result = HTCAPTION;
1.42 - break;
1.43 - case WM_NCLBUTTONDBLCLK:
1.44 - message.Result = IntPtr.Zero; break;
1.45 - case WM_NCRBUTTONDOWN:
1.46 - message.Result = IntPtr.Zero; break;
1.47 - case WM_NCRBUTTONUP:
1.48 - if (contextMenu != null)
1.49 - ShowContextMenu(new Point(
1.50 - (int)((uint)message.LParam & 0xFFFF),
1.51 - (int)(((uint)message.LParam >>16) & 0xFFFF)));
1.52 - message.Result = IntPtr.Zero;
1.53 - break;
1.54 - case WM_WINDOWPOSCHANGING:
1.55 - WindowPos wp = (WindowPos)Marshal.PtrToStructure(
1.56 - message.LParam, typeof(WindowPos));
1.57 + case WM_COMMAND: {
1.58 + // need to dispatch the message for the context menu
1.59 + if (message.LParam == IntPtr.Zero)
1.60 + commandDispatch.Invoke(null, new object[] {
1.61 + message.WParam.ToInt32() & 0xFFFF });
1.62 + } break;
1.63 + case WM_NCHITTEST: {
1.64 + message.Result = (IntPtr)HitResult.Caption;
1.65 + if (HitTest != null) {
1.66 + Point p = new Point(
1.67 + (int)((uint)message.LParam & 0xFFFF) - location.X,
1.68 + (int)(((uint)message.LParam >> 16) & 0xFFFF) - location.Y);
1.69 + HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption);
1.70 + HitTest(this, e);
1.71 + message.Result = (IntPtr)e.HitResult;
1.72 + }
1.73 + } break;
1.74 + case WM_NCLBUTTONDBLCLK: {
1.75 + message.Result = IntPtr.Zero;
1.76 + } break;
1.77 + case WM_NCRBUTTONDOWN: {
1.78 + message.Result = IntPtr.Zero;
1.79 + } break;
1.80 + case WM_NCRBUTTONUP: {
1.81 + if (contextMenu != null)
1.82 + ShowContextMenu(new Point(
1.83 + (int)((uint)message.LParam & 0xFFFF),
1.84 + (int)(((uint)message.LParam >> 16) & 0xFFFF)));
1.85 + message.Result = IntPtr.Zero;
1.86 + } break;
1.87 + case WM_WINDOWPOSCHANGING: {
1.88 + WindowPos wp = (WindowPos)Marshal.PtrToStructure(
1.89 + message.LParam, typeof(WindowPos));
1.90 +
1.91 + if (!lockPositionAndSize) {
1.92 + // prevent the window from leaving the screen
1.93 + if ((wp.flags & SWP_NOMOVE) == 0) {
1.94 + Rectangle rect = Screen.GetWorkingArea(new Point(wp.x, wp.y));
1.95 + const int margin = 16;
1.96 + wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
1.97 + wp.x = Math.Min(wp.x, rect.Right - margin);
1.98 + wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
1.99 + wp.y = Math.Min(wp.y, rect.Bottom - margin);
1.100 + }
1.101
1.102 - // add the nomove flag if position is locked
1.103 - if (lockPosition)
1.104 - wp.flags |= SWP_NOMOVE;
1.105 + // update location and fire event
1.106 + if ((wp.flags & SWP_NOMOVE) == 0) {
1.107 + if (location.X != wp.x || location.Y != wp.y) {
1.108 + location = new Point(wp.x, wp.y);
1.109 + if (LocationChanged != null)
1.110 + LocationChanged(this, EventArgs.Empty);
1.111 + }
1.112 + }
1.113
1.114 - // prevent the window from leaving the screen
1.115 - if ((wp.flags & SWP_NOMOVE) == 0) {
1.116 - Rectangle rect = Screen.GetWorkingArea(new Point(wp.x, wp.y));
1.117 - const int margin = 20;
1.118 - wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
1.119 - wp.x = Math.Min(wp.x, rect.Right - margin);
1.120 - wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
1.121 - wp.y = Math.Min(wp.y, rect.Bottom - margin);
1.122 + // update size and fire event
1.123 + if ((wp.flags & SWP_NOSIZE) == 0) {
1.124 + if (size.Width != wp.cx || size.Height != wp.cy) {
1.125 + size = new Size(wp.cx, wp.cy);
1.126 + if (SizeChanged != null)
1.127 + SizeChanged(this, EventArgs.Empty);
1.128 + }
1.129 + }
1.130
1.131 - // raise the event if location changed
1.132 - if (location.X != wp.x || location.Y != wp.y) {
1.133 - location = new Point(wp.x, wp.y);
1.134 - if (LocationChanged != null)
1.135 - LocationChanged(this, EventArgs.Empty);
1.136 + // update the size of the layered window
1.137 + if ((wp.flags & SWP_NOSIZE) == 0) {
1.138 + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero,
1.139 + IntPtr.Zero, ref size, IntPtr.Zero, IntPtr.Zero, 0,
1.140 + IntPtr.Zero, 0);
1.141 + }
1.142 +
1.143 + // update the position of the layered window
1.144 + if ((wp.flags & SWP_NOMOVE) == 0) {
1.145 + NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
1.146 + location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE |
1.147 + SWP_NOZORDER | SWP_NOSENDCHANGING);
1.148 + }
1.149 }
1.150 - }
1.151 -
1.152 - Marshal.StructureToPtr(wp, message.LParam, false);
1.153 - message.Result = IntPtr.Zero;
1.154 - break;
1.155 - default:
1.156 - base.WndProc(ref message); break;
1.157 +
1.158 + // do not forward any move or size messages
1.159 + wp.flags |= SWP_NOSIZE | SWP_NOMOVE;
1.160 + Marshal.StructureToPtr(wp, message.LParam, false);
1.161 + message.Result = IntPtr.Zero;
1.162 + } break;
1.163 + default: {
1.164 + base.WndProc(ref message);
1.165 + } break;
1.166 }
1.167 }
1.168
1.169 @@ -185,20 +221,24 @@
1.170 newHBitmap = bitmap.GetHbitmap(Color.Black);
1.171 oldHBitmap = NativeMethods.SelectObject(memory, newHBitmap);
1.172
1.173 - Size size = bitmap.Size;
1.174 Point pointSource = Point.Empty;
1.175 - Point topPos = Location;
1.176 + BlendFunction blend = CreateBlendFunction();
1.177
1.178 - BlendFunction blend = CreateBlendFunction();
1.179 - NativeMethods.UpdateLayeredWindow(Handle, screen, ref topPos,
1.180 + NativeMethods.UpdateLayeredWindow(Handle, screen, IntPtr.Zero,
1.181 ref size, memory, ref pointSource, 0, ref blend, ULW_ALPHA);
1.182 - } finally {
1.183 - NativeMethods.ReleaseDC(IntPtr.Zero, screen);
1.184 +
1.185 + // make sure the window is at the right location
1.186 + NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
1.187 + location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE |
1.188 + SWP_NOZORDER | SWP_NOSENDCHANGING);
1.189 +
1.190 + } finally {
1.191 if (newHBitmap != IntPtr.Zero) {
1.192 NativeMethods.SelectObject(memory, oldHBitmap);
1.193 NativeMethods.DeleteObject(newHBitmap);
1.194 }
1.195 NativeMethods.DeleteDC(memory);
1.196 + NativeMethods.ReleaseDC(IntPtr.Zero, screen);
1.197 }
1.198 }
1.199
1.200 @@ -237,13 +277,13 @@
1.201 }
1.202 }
1.203
1.204 - // if locked, the window can not be moved
1.205 - public bool LockPosition {
1.206 + // if locked, the window can not be moved or resized
1.207 + public bool LockPositionAndSize {
1.208 get {
1.209 - return lockPosition;
1.210 + return lockPositionAndSize;
1.211 }
1.212 set {
1.213 - lockPosition = value;
1.214 + lockPositionAndSize = value;
1.215 }
1.216 }
1.217
1.218 @@ -274,23 +314,29 @@
1.219 set {
1.220 if (size != value) {
1.221 size = value;
1.222 - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, size.Width,
1.223 - size.Height, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER |
1.224 - SWP_NOSENDCHANGING);
1.225 + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
1.226 + ref size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0);
1.227 + if (SizeChanged != null)
1.228 + SizeChanged(this, EventArgs.Empty);
1.229 }
1.230 }
1.231 }
1.232
1.233 + public event EventHandler SizeChanged;
1.234 +
1.235 public Point Location {
1.236 get {
1.237 return location;
1.238 }
1.239 set {
1.240 - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, value.X, value.Y, 0,
1.241 - 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);
1.242 - location = value;
1.243 - if (LocationChanged != null)
1.244 - LocationChanged(this, EventArgs.Empty);
1.245 + if (location != value) {
1.246 + location = value;
1.247 + NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
1.248 + location.X, location.Y, 0, 0,
1.249 + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);
1.250 + if (LocationChanged != null)
1.251 + LocationChanged(this, EventArgs.Empty);
1.252 + }
1.253 }
1.254 }
1.255
1.256 @@ -305,6 +351,8 @@
1.257 }
1.258 }
1.259
1.260 + public event HitTestEventHandler HitTest;
1.261 +
1.262 [StructLayout(LayoutKind.Sequential, Pack = 1)]
1.263 private struct BlendFunction {
1.264 public byte BlendOp;
1.265 @@ -357,8 +405,6 @@
1.266 public const int TPM_RIGHTBUTTON = 0x0002;
1.267 public const int TPM_VERTICAL = 0x0040;
1.268
1.269 - public readonly IntPtr HTCAPTION = (IntPtr)2;
1.270 -
1.271 private enum WindowAttribute : int {
1.272 DWMWA_NCRENDERING_ENABLED = 1,
1.273 DWMWA_NCRENDERING_POLICY,
1.274 @@ -382,8 +428,14 @@
1.275
1.276 [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
1.277 [return: MarshalAs(UnmanagedType.Bool)]
1.278 + public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
1.279 + IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc,
1.280 + int crKey, IntPtr pblend, int dwFlags);
1.281 +
1.282 + [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
1.283 + [return: MarshalAs(UnmanagedType.Bool)]
1.284 public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
1.285 - ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc,
1.286 + IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc,
1.287 int crKey, ref BlendFunction pblend, int dwFlags);
1.288
1.289 [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
1.290 @@ -425,4 +477,31 @@
1.291 WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute);
1.292 }
1.293 }
1.294 +
1.295 + public enum HitResult {
1.296 + Transparent = -1,
1.297 + Nowhere = 0,
1.298 + Client = 1,
1.299 + Caption = 2,
1.300 + Left = 10,
1.301 + Right = 11,
1.302 + Top = 12,
1.303 + TopLeft = 13,
1.304 + TopRight = 14,
1.305 + Bottom = 15,
1.306 + BottomLeft = 16,
1.307 + BottomRight = 17,
1.308 + Border = 18
1.309 + }
1.310 +
1.311 + public delegate void HitTestEventHandler(object sender, HitTestEventArgs e);
1.312 +
1.313 + public class HitTestEventArgs : EventArgs {
1.314 + public HitTestEventArgs(Point location, HitResult hitResult) {
1.315 + Location = location;
1.316 + HitResult = hitResult;
1.317 + }
1.318 + public Point Location { get; private set; }
1.319 + public HitResult HitResult { get; set; }
1.320 + }
1.321 }