GUI/GadgetWindow.cs
author moel.mich
Sat, 25 Jun 2011 14:46:28 +0000
changeset 304 16a86362c2ca
parent 244 99f16e21cdc8
child 344 3145aadca3d2
permissions -rw-r--r--
Changed the maximum buffer size for double buffering of controls that isn't disposed after each draw call to the size of the screen. This should reduce the memory allocation and disposing on each sensor update. Also page faults are no longer increasing with this change.
moel@202
     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@302
    19
  Portions created by the Initial Developer are Copyright (C) 2010-2011
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.Drawing;
moel@302
    40
using System.Drawing.Drawing2D;
moel@302
    41
using System.Drawing.Text;
moel@176
    42
using System.Reflection;
moel@176
    43
using System.Runtime.InteropServices;
moel@176
    44
using System.Windows.Forms;
moel@176
    45
moel@176
    46
namespace OpenHardwareMonitor.GUI {
moel@183
    47
moel@302
    48
  public class GadgetWindow : NativeWindow, IDisposable {
moel@176
    49
moel@176
    50
    private bool visible = false;
moel@183
    51
    private bool lockPositionAndSize = false;
moel@176
    52
    private bool alwaysOnTop = false;
moel@176
    53
    private byte opacity = 255;
moel@176
    54
    private Point location = new Point(100, 100);
moel@176
    55
    private Size size = new Size(130, 84);
moel@176
    56
    private ContextMenu contextMenu = null;
moel@176
    57
    private MethodInfo commandDispatch;
moel@302
    58
    private IntPtr handleBitmapDC;
moel@302
    59
    private Size bufferSize;
moel@302
    60
    private Graphics graphics;
moel@176
    61
moel@176
    62
    public GadgetWindow() {
moel@176
    63
      Type commandType = 
moel@176
    64
        typeof(Form).Assembly.GetType("System.Windows.Forms.Command");
moel@176
    65
      commandDispatch = commandType.GetMethod("DispatchID", 
moel@176
    66
        BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, 
moel@176
    67
        null, new Type[]{ typeof(int) }, null);
moel@176
    68
moel@176
    69
      this.CreateHandle(CreateParams);
moel@176
    70
moel@176
    71
      // move window to the bottom
moel@176
    72
      MoveToBottom(Handle);
moel@176
    73
moel@176
    74
      // prevent window from fading to a glass sheet when peek is invoked
moel@176
    75
      try {
moel@176
    76
        bool value = true;
moel@202
    77
        NativeMethods.DwmSetWindowAttribute(Handle,
moel@176
    78
          WindowAttribute.DWMWA_EXCLUDED_FROM_PEEK, ref value,
moel@176
    79
          Marshal.SizeOf(value));
moel@176
    80
      } catch (DllNotFoundException) { } catch (EntryPointNotFoundException) { }
moel@302
    81
moel@302
    82
      CreateBuffer();
moel@176
    83
    }
moel@176
    84
moel@176
    85
    private void ShowDesktopChanged(bool showDesktop) {
moel@176
    86
      if (showDesktop) {
moel@176
    87
        MoveToTopMost(Handle);
moel@176
    88
      } else {
moel@176
    89
        MoveToBottom(Handle);
moel@176
    90
      }
moel@176
    91
    }
moel@176
    92
moel@176
    93
    private void MoveToBottom(IntPtr handle) {
moel@176
    94
      NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0,
moel@176
    95
        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
moel@176
    96
    }
moel@176
    97
moel@176
    98
    private void MoveToTopMost(IntPtr handle) {
moel@176
    99
      NativeMethods.SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0,
moel@176
   100
        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
moel@176
   101
    }
moel@176
   102
moel@176
   103
    private void ShowContextMenu(Point position) {
moel@176
   104
      NativeMethods.TrackPopupMenuEx(contextMenu.Handle, 
moel@176
   105
        TPM_RIGHTBUTTON | TPM_VERTICAL, position.X,
moel@176
   106
        position.Y, Handle, IntPtr.Zero);
moel@176
   107
    }
moel@176
   108
moel@176
   109
    protected virtual CreateParams CreateParams {
moel@176
   110
      get {
moel@183
   111
        CreateParams cp = new CreateParams();        
moel@183
   112
        cp.Width = 4096;
moel@183
   113
        cp.Height = 4096;
moel@176
   114
        cp.X = location.X;
moel@176
   115
        cp.Y = location.Y;
moel@176
   116
        cp.ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW;
moel@176
   117
        return cp;
moel@176
   118
      }
moel@176
   119
    }
moel@176
   120
moel@176
   121
    protected override void WndProc(ref Message message) {
moel@176
   122
      switch (message.Msg) {
moel@183
   123
        case WM_COMMAND: {
moel@183
   124
            // need to dispatch the message for the context menu
moel@183
   125
            if (message.LParam == IntPtr.Zero)
moel@183
   126
              commandDispatch.Invoke(null, new object[] { 
moel@183
   127
              message.WParam.ToInt32() & 0xFFFF });
moel@183
   128
          } break;
moel@183
   129
        case WM_NCHITTEST: {
moel@183
   130
            message.Result = (IntPtr)HitResult.Caption;
moel@183
   131
            if (HitTest != null) {
moel@183
   132
              Point p = new Point(
paulwerelds@208
   133
                Macros.GET_X_LPARAM(message.LParam) - location.X,
paulwerelds@208
   134
                Macros.GET_Y_LPARAM(message.LParam) - location.Y
paulwerelds@208
   135
              );
moel@183
   136
              HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption);
moel@183
   137
              HitTest(this, e);
moel@183
   138
              message.Result = (IntPtr)e.HitResult;
moel@183
   139
            }
moel@183
   140
          } break;
moel@183
   141
        case WM_NCLBUTTONDBLCLK: {
moel@244
   142
            if (MouseDoubleClick != null) {
moel@244
   143
              MouseDoubleClick(this, new MouseEventArgs(MouseButtons.Left, 2,
moel@244
   144
                Macros.GET_X_LPARAM(message.LParam) - location.X,
moel@244
   145
                Macros.GET_Y_LPARAM(message.LParam) - location.Y, 0));
moel@244
   146
            }
moel@183
   147
            message.Result = IntPtr.Zero;
moel@183
   148
          } break;
moel@183
   149
        case WM_NCRBUTTONDOWN: {
moel@183
   150
            message.Result = IntPtr.Zero;
moel@183
   151
          } break;
moel@183
   152
        case WM_NCRBUTTONUP: {
moel@183
   153
            if (contextMenu != null)
moel@183
   154
              ShowContextMenu(new Point(
paulwerelds@209
   155
                Macros.GET_X_LPARAM(message.LParam),
paulwerelds@209
   156
                Macros.GET_Y_LPARAM(message.LParam)
paulwerelds@209
   157
              ));
moel@183
   158
            message.Result = IntPtr.Zero;
moel@183
   159
          } break;
moel@183
   160
        case WM_WINDOWPOSCHANGING: {
moel@183
   161
            WindowPos wp = (WindowPos)Marshal.PtrToStructure(
moel@183
   162
              message.LParam, typeof(WindowPos));
moel@183
   163
            
moel@183
   164
            if (!lockPositionAndSize) {
moel@183
   165
              // prevent the window from leaving the screen
moel@183
   166
              if ((wp.flags & SWP_NOMOVE) == 0) {
moel@243
   167
                Rectangle rect = Screen.GetWorkingArea(
moel@243
   168
                  new Rectangle(wp.x, wp.y, wp.cx, wp.cy));
moel@183
   169
                const int margin = 16;
moel@183
   170
                wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
moel@183
   171
                wp.x = Math.Min(wp.x, rect.Right - margin);
moel@183
   172
                wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
moel@183
   173
                wp.y = Math.Min(wp.y, rect.Bottom - margin);
moel@183
   174
              }
moel@176
   175
moel@183
   176
              // update location and fire event
moel@183
   177
              if ((wp.flags & SWP_NOMOVE) == 0) {
moel@183
   178
                if (location.X != wp.x || location.Y != wp.y) {
moel@183
   179
                  location = new Point(wp.x, wp.y);
moel@183
   180
                  if (LocationChanged != null)
moel@183
   181
                    LocationChanged(this, EventArgs.Empty);
moel@183
   182
                }
moel@183
   183
              }
moel@176
   184
moel@183
   185
              // update size and fire event
moel@183
   186
              if ((wp.flags & SWP_NOSIZE) == 0) {
moel@183
   187
                if (size.Width != wp.cx || size.Height != wp.cy) {
moel@183
   188
                  size = new Size(wp.cx, wp.cy);
moel@183
   189
                  if (SizeChanged != null)
moel@183
   190
                    SizeChanged(this, EventArgs.Empty);
moel@183
   191
                }
moel@183
   192
              } 
moel@176
   193
moel@183
   194
              // update the size of the layered window
moel@183
   195
              if ((wp.flags & SWP_NOSIZE) == 0) {
moel@183
   196
                NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero,
moel@183
   197
                  IntPtr.Zero, ref size, IntPtr.Zero, IntPtr.Zero, 0,
moel@183
   198
                  IntPtr.Zero, 0);                
moel@183
   199
              }
moel@183
   200
moel@183
   201
              // update the position of the layered window
moel@183
   202
              if ((wp.flags & SWP_NOMOVE) == 0) {
moel@183
   203
                NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
moel@183
   204
                  location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | 
moel@183
   205
                  SWP_NOZORDER | SWP_NOSENDCHANGING);
moel@183
   206
              }
moel@176
   207
            }
moel@183
   208
            
moel@183
   209
            // do not forward any move or size messages
moel@243
   210
            wp.flags |= SWP_NOSIZE | SWP_NOMOVE;
moel@243
   211
moel@243
   212
            // suppress any frame changed events
moel@243
   213
            wp.flags &= ~SWP_FRAMECHANGED;
moel@243
   214
moel@183
   215
            Marshal.StructureToPtr(wp, message.LParam, false);                      
moel@183
   216
            message.Result = IntPtr.Zero;
moel@183
   217
          } break;
moel@183
   218
        default: {
moel@183
   219
            base.WndProc(ref message);
moel@183
   220
          } break;
moel@176
   221
      }      
moel@176
   222
    }
moel@176
   223
moel@176
   224
    private BlendFunction CreateBlendFunction() {
moel@176
   225
      BlendFunction blend = new BlendFunction();
moel@176
   226
      blend.BlendOp = AC_SRC_OVER;
moel@176
   227
      blend.BlendFlags = 0;
moel@176
   228
      blend.SourceConstantAlpha = opacity;
moel@176
   229
      blend.AlphaFormat = AC_SRC_ALPHA;
moel@176
   230
      return blend;
moel@176
   231
    }
moel@176
   232
moel@302
   233
    private void CreateBuffer() {      
moel@302
   234
      IntPtr handleScreenDC = NativeMethods.GetDC(IntPtr.Zero);
moel@302
   235
      handleBitmapDC = NativeMethods.CreateCompatibleDC(handleScreenDC);
moel@302
   236
      NativeMethods.ReleaseDC(IntPtr.Zero, handleScreenDC);
moel@302
   237
      bufferSize = size;
moel@176
   238
moel@302
   239
      BitmapInfo info = new BitmapInfo();
moel@302
   240
      info.Size = Marshal.SizeOf(info);
moel@302
   241
      info.Width = size.Width;
moel@302
   242
      info.Height = -size.Height;
moel@302
   243
      info.BitCount = 32;
moel@302
   244
      info.Planes = 1;
moel@302
   245
moel@302
   246
      IntPtr ptr;
moel@302
   247
      IntPtr hBmp = NativeMethods.CreateDIBSection(handleBitmapDC, ref info, 0, 
moel@302
   248
        out ptr, IntPtr.Zero, 0);
moel@302
   249
      IntPtr hBmpOld = NativeMethods.SelectObject(handleBitmapDC, hBmp);
moel@302
   250
      NativeMethods.DeleteObject(hBmpOld);
moel@302
   251
      
moel@302
   252
      graphics = Graphics.FromHdc(handleBitmapDC);
moel@302
   253
moel@302
   254
      if (Environment.OSVersion.Version.Major > 5) {
moel@302
   255
        this.graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
moel@302
   256
        this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@302
   257
      } 
moel@302
   258
    }
moel@302
   259
moel@302
   260
    private void DisposeBuffer() {
moel@302
   261
      graphics.Dispose();
moel@302
   262
      NativeMethods.DeleteDC(handleBitmapDC);
moel@302
   263
    }
moel@302
   264
moel@302
   265
    public virtual void Dispose() {
moel@302
   266
      DisposeBuffer();
moel@302
   267
    } 
moel@302
   268
moel@302
   269
    public PaintEventHandler Paint; 
moel@302
   270
moel@302
   271
    public void Redraw() {
moel@302
   272
      if (!visible || Paint == null)
moel@302
   273
        return;
moel@302
   274
moel@302
   275
      if (size != bufferSize) {
moel@302
   276
        DisposeBuffer();
moel@302
   277
        CreateBuffer();
moel@302
   278
      }
moel@302
   279
moel@302
   280
      Paint(this, 
moel@302
   281
        new PaintEventArgs(graphics, new Rectangle(Point.Empty, size))); 
moel@176
   282
moel@176
   283
        Point pointSource = Point.Empty;
moel@183
   284
        BlendFunction blend = CreateBlendFunction();
moel@176
   285
moel@302
   286
        NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@302
   287
          ref size, handleBitmapDC, ref pointSource, 0, ref blend, ULW_ALPHA);
moel@183
   288
moel@183
   289
        // make sure the window is at the right location
moel@302
   290
        NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
moel@302
   291
          location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE |
moel@183
   292
          SWP_NOZORDER | SWP_NOSENDCHANGING);
moel@176
   293
    }
moel@176
   294
moel@176
   295
    public byte Opacity {
moel@176
   296
      get {
moel@176
   297
        return opacity;
moel@176
   298
      }
moel@176
   299
      set {
moel@176
   300
        if (opacity != value) {
moel@176
   301
          opacity = value;
moel@176
   302
          BlendFunction blend = CreateBlendFunction();
moel@176
   303
          NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@176
   304
            IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, ULW_ALPHA);
moel@176
   305
        }
moel@176
   306
      }
moel@176
   307
    }
moel@176
   308
moel@176
   309
    public bool Visible {
moel@176
   310
      get {
moel@176
   311
        return visible;
moel@176
   312
      }
moel@176
   313
      set {
moel@176
   314
        if (visible != value) {
moel@176
   315
          visible = value;
moel@176
   316
          NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0,
moel@176
   317
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
moel@176
   318
            (value ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
moel@180
   319
          if (value) {
moel@180
   320
            if (!alwaysOnTop)
moel@180
   321
              ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
moel@180
   322
          } else {
moel@180
   323
            if (!alwaysOnTop)
moel@180
   324
              ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
moel@180
   325
          }
moel@176
   326
        }
moel@176
   327
      }
moel@176
   328
    }
moel@176
   329
moel@183
   330
    // if locked, the window can not be moved or resized
moel@183
   331
    public bool LockPositionAndSize {
moel@176
   332
      get {
moel@183
   333
        return lockPositionAndSize;
moel@176
   334
      }
moel@176
   335
      set {
moel@183
   336
        lockPositionAndSize = value;
moel@176
   337
      }
moel@176
   338
    }
moel@176
   339
moel@176
   340
    public bool AlwaysOnTop {
moel@176
   341
      get {
moel@176
   342
        return alwaysOnTop;
moel@176
   343
      }
moel@176
   344
      set {
moel@176
   345
        if (value != alwaysOnTop) {
moel@176
   346
          alwaysOnTop = value;
moel@176
   347
          if (alwaysOnTop) {
moel@180
   348
            if (visible)
moel@180
   349
              ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
moel@176
   350
            MoveToTopMost(Handle);            
moel@176
   351
          } else {
moel@176
   352
            MoveToBottom(Handle);
moel@180
   353
            if (visible)
moel@180
   354
              ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
moel@176
   355
          }
moel@176
   356
        }
moel@176
   357
      }
moel@176
   358
    }
moel@176
   359
moel@176
   360
    public Size Size {
moel@176
   361
      get {
moel@176
   362
        return size; 
moel@176
   363
      }
moel@176
   364
      set {
moel@176
   365
        if (size != value) {
moel@176
   366
          size = value;
moel@183
   367
          NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@183
   368
            ref size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0);                    
moel@183
   369
          if (SizeChanged != null)
moel@183
   370
            SizeChanged(this, EventArgs.Empty);
moel@176
   371
        }
moel@176
   372
      }
moel@176
   373
    }
moel@176
   374
moel@183
   375
    public event EventHandler SizeChanged;
moel@183
   376
moel@176
   377
    public Point Location {
moel@176
   378
      get {
moel@176
   379
        return location;
moel@176
   380
      }
moel@176
   381
      set {
moel@183
   382
        if (location != value) {
moel@183
   383
          location = value;
moel@183
   384
          NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
moel@183
   385
            location.X, location.Y, 0, 0, 
moel@183
   386
            SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);          
moel@183
   387
          if (LocationChanged != null)
moel@183
   388
            LocationChanged(this, EventArgs.Empty);
moel@183
   389
        }
moel@176
   390
      }
moel@176
   391
    }
moel@176
   392
moel@176
   393
    public event EventHandler LocationChanged;
moel@176
   394
moel@176
   395
    public ContextMenu ContextMenu {
moel@176
   396
      get {
moel@176
   397
        return contextMenu;
moel@176
   398
      }
moel@176
   399
      set {
moel@176
   400
        this.contextMenu = value;
moel@176
   401
      }
moel@176
   402
    }
moel@176
   403
moel@183
   404
    public event HitTestEventHandler HitTest;
moel@183
   405
moel@244
   406
    public event MouseEventHandler MouseDoubleClick;
moel@244
   407
moel@176
   408
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@176
   409
    private struct BlendFunction {
moel@176
   410
      public byte BlendOp;
moel@176
   411
      public byte BlendFlags;
moel@176
   412
      public byte SourceConstantAlpha;
moel@176
   413
      public byte AlphaFormat;
moel@176
   414
    }
moel@176
   415
moel@176
   416
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@176
   417
    private struct WindowPos {
moel@176
   418
      public IntPtr hwnd;
moel@176
   419
      public IntPtr hwndInsertAfter;
moel@176
   420
      public int x;
moel@176
   421
      public int y;
moel@176
   422
      public int cx;
moel@176
   423
      public int cy;
moel@176
   424
      public uint flags;
moel@176
   425
    }
moel@176
   426
moel@302
   427
    [StructLayout(LayoutKind.Sequential)]
moel@302
   428
    public struct BitmapInfo {
moel@302
   429
      public Int32 Size;
moel@302
   430
      public Int32 Width;
moel@302
   431
      public Int32 Height;
moel@302
   432
      public Int16 Planes;
moel@302
   433
      public Int16 BitCount;
moel@302
   434
      public Int32 Compression;
moel@302
   435
      public Int32 SizeImage;
moel@302
   436
      public Int32 XPelsPerMeter;
moel@302
   437
      public Int32 YPelsPerMeter;
moel@302
   438
      public Int32 ClrUsed;
moel@302
   439
      public Int32 ClrImportant;
moel@302
   440
      public Int32 Colors;
moel@302
   441
    }
moel@302
   442
moel@176
   443
    public static readonly IntPtr HWND_BOTTOM = (IntPtr)1;
moel@176
   444
    public static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);
moel@176
   445
moel@176
   446
    public const int WS_EX_LAYERED = 0x00080000;
moel@176
   447
    public const int WS_EX_TOOLWINDOW = 0x00000080;
moel@176
   448
moel@176
   449
    public const uint SWP_NOSIZE = 0x0001;
moel@176
   450
    public const uint SWP_NOMOVE = 0x0002;
moel@176
   451
    public const uint SWP_NOACTIVATE = 0x0010;
moel@243
   452
    public const uint SWP_FRAMECHANGED = 0x0020;
moel@176
   453
    public const uint SWP_HIDEWINDOW = 0x0080;
moel@176
   454
    public const uint SWP_SHOWWINDOW = 0x0040;
moel@176
   455
    public const uint SWP_NOZORDER = 0x0004;
moel@176
   456
    public const uint SWP_NOSENDCHANGING = 0x0400;
moel@176
   457
moel@176
   458
    public const int ULW_COLORKEY = 0x00000001;
moel@176
   459
    public const int ULW_ALPHA = 0x00000002;
moel@176
   460
    public const int ULW_OPAQUE = 0x00000004;
moel@176
   461
moel@176
   462
    public const byte AC_SRC_OVER = 0x00;
moel@176
   463
    public const byte AC_SRC_ALPHA = 0x01;
moel@176
   464
moel@176
   465
    public const int WM_NCHITTEST = 0x0084;
moel@176
   466
    public const int WM_NCLBUTTONDBLCLK = 0x00A3;
moel@176
   467
    public const int WM_NCLBUTTONDOWN = 0x00A1;
moel@176
   468
    public const int WM_NCLBUTTONUP = 0x00A2;
moel@176
   469
    public const int WM_NCRBUTTONDOWN = 0x00A4;
moel@176
   470
    public const int WM_NCRBUTTONUP = 0x00A5;
moel@176
   471
    public const int WM_WINDOWPOSCHANGING = 0x0046;
moel@176
   472
    public const int WM_COMMAND = 0x0111;
moel@176
   473
moel@176
   474
    public const int TPM_RIGHTBUTTON = 0x0002;
moel@176
   475
    public const int TPM_VERTICAL = 0x0040;
moel@176
   476
moel@176
   477
    private enum WindowAttribute : int {
moel@176
   478
      DWMWA_NCRENDERING_ENABLED = 1,
moel@176
   479
      DWMWA_NCRENDERING_POLICY,
moel@176
   480
      DWMWA_TRANSITIONS_FORCEDISABLED,
moel@176
   481
      DWMWA_ALLOW_NCPAINT,
moel@176
   482
      DWMWA_CAPTION_BUTTON_BOUNDS,
moel@176
   483
      DWMWA_NONCLIENT_RTL_LAYOUT,
moel@176
   484
      DWMWA_FORCE_ICONIC_REPRESENTATION,
moel@176
   485
      DWMWA_FLIP3D_POLICY,
moel@176
   486
      DWMWA_EXTENDED_FRAME_BOUNDS,
moel@176
   487
      DWMWA_HAS_ICONIC_BITMAP,
moel@176
   488
      DWMWA_DISALLOW_PEEK,
moel@176
   489
      DWMWA_EXCLUDED_FROM_PEEK,
moel@176
   490
      DWMWA_LAST
moel@176
   491
    }
moel@176
   492
paulwerelds@208
   493
    /// <summary>
paulwerelds@208
   494
    /// Some macros imported and converted from the Windows SDK
paulwerelds@208
   495
    /// </summary>
paulwerelds@208
   496
    private static class Macros {
paulwerelds@210
   497
      public static ushort LOWORD(IntPtr l) {
paulwerelds@210
   498
        return (ushort) ((ulong)l & 0xFFFF);
paulwerelds@208
   499
      }
paulwerelds@208
   500
      
paulwerelds@208
   501
      public static UInt16 HIWORD(IntPtr l) {
paulwerelds@210
   502
        return (ushort) (((ulong)l >> 16) & 0xFFFF);
paulwerelds@208
   503
      }
paulwerelds@208
   504
paulwerelds@208
   505
      public static int GET_X_LPARAM(IntPtr lp) {
paulwerelds@210
   506
        return (short) LOWORD(lp);
paulwerelds@208
   507
      }
paulwerelds@208
   508
paulwerelds@208
   509
      public static int GET_Y_LPARAM(IntPtr lp) {
paulwerelds@210
   510
        return (short) HIWORD(lp);
paulwerelds@208
   511
      }
paulwerelds@208
   512
    }
paulwerelds@208
   513
paulwerelds@208
   514
    /// <summary>
paulwerelds@208
   515
    /// Imported native methods
paulwerelds@208
   516
    /// </summary>
moel@176
   517
    private static class NativeMethods {
moel@176
   518
      private const string USER = "user32.dll";
moel@176
   519
      private const string GDI = "gdi32.dll";
moel@176
   520
      public const string DWMAPI = "dwmapi.dll";
moel@176
   521
moel@176
   522
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   523
      [return: MarshalAs(UnmanagedType.Bool)]
moel@183
   524
      public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
moel@183
   525
        IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc,
moel@183
   526
        int crKey, IntPtr pblend, int dwFlags);
moel@183
   527
moel@183
   528
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@183
   529
      [return: MarshalAs(UnmanagedType.Bool)]
moel@176
   530
      public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, 
moel@183
   531
        IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, 
moel@176
   532
        int crKey, ref BlendFunction pblend, int dwFlags);
moel@176
   533
moel@176
   534
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   535
      [return: MarshalAs(UnmanagedType.Bool)]
moel@176
   536
      public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
moel@176
   537
        IntPtr pptDst, IntPtr psize, IntPtr hdcSrc, IntPtr pprSrc,
moel@176
   538
        int crKey, ref BlendFunction pblend, int dwFlags);  
moel@176
   539
moel@176
   540
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   541
      public static extern IntPtr GetDC(IntPtr hWnd);
moel@176
   542
moel@176
   543
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   544
      public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
moel@176
   545
moel@176
   546
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   547
      public static extern bool SetWindowPos(IntPtr hWnd,
moel@176
   548
        IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
moel@176
   549
moel@176
   550
      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176
   551
      public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, 
moel@176
   552
        int x, int y, IntPtr hWnd, IntPtr tpmParams);
moel@176
   553
moel@176
   554
      [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176
   555
      public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
moel@176
   556
moel@176
   557
      [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@302
   558
      public static extern IntPtr CreateDIBSection(IntPtr hdc, 
moel@302
   559
        [In] ref BitmapInfo pbmi, uint pila, out IntPtr ppvBits, 
moel@302
   560
        IntPtr hSection, uint dwOffset);
moel@302
   561
moel@302
   562
      [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176
   563
      [return: MarshalAs(UnmanagedType.Bool)]
moel@176
   564
      public static extern bool DeleteDC(IntPtr hdc);
moel@176
   565
      
moel@176
   566
      [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176
   567
      public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
moel@176
   568
moel@176
   569
      [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176
   570
      [return: MarshalAs(UnmanagedType.Bool)]
moel@176
   571
      public static extern bool DeleteObject(IntPtr hObject);
moel@176
   572
moel@176
   573
      [DllImport(DWMAPI, CallingConvention = CallingConvention.Winapi)]
moel@176
   574
      public static extern int DwmSetWindowAttribute(IntPtr hwnd,
moel@176
   575
        WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute);
moel@176
   576
    }    
moel@176
   577
  }
moel@183
   578
moel@183
   579
  public enum HitResult {
moel@183
   580
    Transparent = -1,
moel@183
   581
    Nowhere = 0,
moel@183
   582
    Client = 1,
moel@183
   583
    Caption = 2,
moel@183
   584
    Left = 10,
moel@183
   585
    Right = 11,
moel@183
   586
    Top = 12,
moel@183
   587
    TopLeft = 13,
moel@183
   588
    TopRight = 14,
moel@183
   589
    Bottom = 15,
moel@183
   590
    BottomLeft = 16,
moel@183
   591
    BottomRight = 17,
moel@183
   592
    Border = 18
moel@183
   593
  }
moel@183
   594
moel@183
   595
  public delegate void HitTestEventHandler(object sender, HitTestEventArgs e);
moel@183
   596
moel@183
   597
  public class HitTestEventArgs : EventArgs {
moel@183
   598
    public HitTestEventArgs(Point location, HitResult hitResult) {
moel@183
   599
      Location = location;
moel@183
   600
      HitResult = hitResult;
moel@183
   601
    }
moel@183
   602
    public Point Location { get; private set; }
moel@183
   603
    public HitResult HitResult { get; set; }
moel@183
   604
  }
moel@176
   605
}