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