2006-12-01 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / XplatUIWin32.cs
index bb5ed94c06c1668c3ad255c65cb2471fc7142315..af4ef6bbc03a42658c5f550c57ce76f6f4abc741 100644 (file)
@@ -61,6 +61,7 @@ namespace System.Windows.Forms {
                private static IntPtr           clip_magic = new IntPtr(27051977);
                private static int              scroll_width;
                private static int              scroll_height;
+               private static Hashtable        wm_nc_registered;
 
                private static Win32DnD         DnD;
                #endregion      // Local Variables
@@ -147,6 +148,7 @@ namespace System.Windows.Forms {
                private enum TMEFlags {
                        TME_HOVER               = 0x00000001,
                        TME_LEAVE               = 0x00000002,
+                       TME_NONCLIENT           = 0x00000010,
                        TME_QUERY               = unchecked((int)0x40000000),
                        TME_CANCEL              = unchecked((int)0x80000000)
                }
@@ -1211,7 +1213,18 @@ namespace System.Windows.Forms {
                        Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle);
                }
 
-               
+               internal override double GetWindowTransparency(IntPtr handle)
+               {
+                       LayeredWindowAttributes lwa;
+                       COLORREF clrRef;
+                       byte alpha;
+
+                       if (0 == Win32GetLayeredWindowAttributes (handle, out clrRef, out alpha, out lwa))
+                               return 1.0;
+
+                       return ((double)alpha) / 255.0;
+               }
+
                internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) {
                        LayeredWindowAttributes lwa = LayeredWindowAttributes.LWA_ALPHA;
                        byte opacity = (byte)(transparency*255);
@@ -1228,9 +1241,39 @@ namespace System.Windows.Forms {
                        Win32SetLayeredWindowAttributes(handle, clrRef, opacity, lwa);
                }
 
-               internal override bool SupportsTransparency() {
-                       // We might check with the OS, but I think we're only >=W2k
-                       return true;
+               TransparencySupport support;
+               bool queried_transparency_support;
+               internal override TransparencySupport SupportsTransparency() {
+                       if (queried_transparency_support)
+                               return support;
+
+                       bool flag;
+                       support = TransparencySupport.None;
+
+                       flag = true;
+                       try {
+                               Win32SetLayeredWindowAttributes (IntPtr.Zero, new COLORREF (), 255, LayeredWindowAttributes.LWA_ALPHA);
+                       }
+                       catch (EntryPointNotFoundException) { flag = false; }
+                       catch { /* swallow everything else */ }
+
+                       if (flag) support |= TransparencySupport.Set;
+
+                       flag = true;
+                       try {
+                               LayeredWindowAttributes lwa;
+                               COLORREF clrRef;
+                               byte alpha;
+
+                               Win32GetLayeredWindowAttributes (IntPtr.Zero, out clrRef, out alpha, out lwa);
+                       }
+                       catch (EntryPointNotFoundException) { flag = false; }
+                       catch { /* swallow everything else */ }
+
+                       if (flag) support |= TransparencySupport.Get;
+
+                       queried_transparency_support = true;
+                       return support;
                }
 
                internal override void UpdateWindow(IntPtr handle) {
@@ -1255,47 +1298,52 @@ namespace System.Windows.Forms {
                                if (Win32GetUpdateRect(handle, ref rect, false)) {
                                        hdc = Win32BeginPaint(handle, ref ps);
 
-                                       hwnd.user_data = (object)ps;
+                                       hwnd.drawing_stack.Push (ps);
 
                                        clip_rect = new Rectangle(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top);
                                } else {
                                        hdc = Win32GetDC(handle);
                                        // FIXME: Add the DC to internal list
+
+                                       hwnd.drawing_stack.Push (null);
+
                                        clip_rect = new Rectangle(rect.top, rect.left, rect.right-rect.left, rect.bottom-rect.top);
                                }
                        } else {
                                hdc = Win32GetWindowDC (handle);
-                               hwnd.user_data = (object)hdc;
+
+                               hwnd.drawing_stack.Push (hdc);
 
                                // HACK this in for now
                                Win32GetWindowRect (handle, out rect);
                                clip_rect = new Rectangle(0, 0, rect.right-rect.left, rect.bottom-rect.top);
                        }
 
-                       hwnd.client_dc = Graphics.FromHdc(hdc);
-                       paint_event = new PaintEventArgs(hwnd.client_dc, clip_rect);
+                       Graphics dc = Graphics.FromHdc(hdc);
+                       hwnd.drawing_stack.Push (dc);
+
+                       paint_event = new PaintEventArgs(dc, clip_rect);
 
                        return paint_event;
                }
 
                internal override void PaintEventEnd(IntPtr handle, bool client) {
                        Hwnd            hwnd;
-                       PAINTSTRUCT     ps;
 
                        hwnd = Hwnd.ObjectFromHandle(handle);
-                       hwnd.client_dc.Dispose();
+
+                       Graphics dc = (Graphics)hwnd.drawing_stack.Pop();
+                       dc.Dispose ();
 
                        if (client) {
-                               if (hwnd.user_data != null) {
-                                       ps = (PAINTSTRUCT)hwnd.user_data;
+                               object o = hwnd.drawing_stack.Pop();
+                               if (o != null) {
+                                       PAINTSTRUCT ps = (PAINTSTRUCT)o;
                                        Win32EndPaint(handle, ref ps);
-                                       hwnd.user_data = null;
                                }
                        } else {
-                               if (hwnd.user_data != null) {
-                                       Win32ReleaseDC(handle, (IntPtr)hwnd.user_data);
-                                       hwnd.user_data = null;
-                               }
+                               IntPtr hdc = (IntPtr)hwnd.drawing_stack.Pop();
+                               Win32ReleaseDC(handle, hdc);
                        }
                }
 
@@ -1343,6 +1391,20 @@ namespace System.Windows.Forms {
                        Win32InvalidateRect(handle, ref rect, clear);
                }
 
+
+               internal override void InvalidateNC (IntPtr handle)
+               {
+                       // found this gem at
+                       // http://www.dotnet247.com/247reference/msgs/58/292037.aspx
+                       Win32SetWindowPos(handle, IntPtr.Zero,
+                                         0, 0, 0, 0,
+                                         SetWindowPosFlags.SWP_NOMOVE |
+                                         SetWindowPosFlags.SWP_NOSIZE |
+                                         SetWindowPosFlags.SWP_NOZORDER |
+                                         SetWindowPosFlags.SWP_NOACTIVATE |
+                                         SetWindowPosFlags.SWP_DRAWFRAME);
+               }
+
                internal override IntPtr DefWndProc(ref Message msg) {
                        msg.Result=Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam);
                        return msg.Result;
@@ -1375,6 +1437,30 @@ namespace System.Windows.Forms {
                        Win32PostQuitMessage(exitCode);
                }
 
+               internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave)
+               {
+                       if (wm_nc_registered == null)
+                               wm_nc_registered = new Hashtable ();
+                               
+                       TMEFlags flags = TMEFlags.TME_NONCLIENT;
+                       if (hover)
+                               flags |= TMEFlags.TME_HOVER;
+                       if (leave)
+                               flags |= TMEFlags.TME_LEAVE;
+
+                       if (flags == TMEFlags.TME_NONCLIENT) {
+                               if (wm_nc_registered.Contains (hwnd)) {
+                                       wm_nc_registered.Remove (hwnd);
+                               }
+                       } else {
+                               if (!wm_nc_registered.Contains (hwnd)) {
+                                       wm_nc_registered.Add (hwnd, flags);
+                               } else {
+                                       wm_nc_registered [hwnd] = flags;
+                               }
+                       }
+               }
+
                internal override void RequestNCRecalc(IntPtr handle) {
                        Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOMOVE);
                }
@@ -1469,6 +1555,20 @@ namespace System.Windows.Forms {
                                        break;
                                }
 
+                               case Msg.WM_NCMOUSEMOVE: {
+                                       if (wm_nc_registered == null || !wm_nc_registered.Contains (msg.hwnd))
+                                               break;
+                                               
+                                       TRACKMOUSEEVENT tme;
+
+                                       tme = new TRACKMOUSEEVENT ();
+                                       tme.size = Marshal.SizeOf(tme);
+                                       tme.hWnd = msg.hwnd;
+                                       tme.dwFlags = (TMEFlags)wm_nc_registered[msg.hwnd];
+                                       Win32TrackMouseEvent (ref tme);
+                                       return result;
+                               }
+
                                case Msg.WM_DROPFILES: {
                                        return Win32DnD.HandleWMDropFiles(ref msg);
                                }
@@ -1537,22 +1637,34 @@ namespace System.Windows.Forms {
                        return true;
                }
 
-               internal override bool SetVisible(IntPtr handle, bool visible) {
+               internal override bool SetVisible (IntPtr handle, bool visible, bool activate)
+               {
                        if (visible) {
-                               if (Control.FromHandle(handle) is Form) {
+                               if (Control.FromHandle (handle) is Form) {
                                        Form f;
 
-                                       f = (Form)Control.FromHandle(handle);
+                                       f = (Form)Control.FromHandle (handle);
+                                       WindowPlacementFlags flags = WindowPlacementFlags.SW_SHOWNORMAL;
                                        switch (f.WindowState) {
-                                               case FormWindowState.Normal:    Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNORMAL); break;
-                                               case FormWindowState.Minimized: Win32ShowWindow(handle, WindowPlacementFlags.SW_MINIMIZE); break;
-                                               case FormWindowState.Maximized: Win32ShowWindow(handle, WindowPlacementFlags.SW_MAXIMIZE); break;
+                                               case FormWindowState.Normal: flags = WindowPlacementFlags.SW_SHOWNORMAL; break;
+                                               case FormWindowState.Minimized: flags = WindowPlacementFlags.SW_MINIMIZE; break;
+                                               case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break;
                                        }
-                               } else {
-                                       Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNORMAL);
+                                       
+                                       if (Hwnd.ObjectFromHandle (handle).no_activate)
+                                               flags |= WindowPlacementFlags.SW_SHOWNOACTIVATE;
+                                               
+                                       Win32ShowWindow (handle, flags);
                                }
-                       } else {
-                               Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE);
+                               else {
+                                       if (Hwnd.ObjectFromHandle (handle).no_activate)
+                                               Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNOACTIVATE);
+                                       else
+                                               Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNORMAL);
+                               }
+                       }
+                       else {
+                               Win32ShowWindow (handle, WindowPlacementFlags.SW_HIDE);
                        }
                        return true;
                }
@@ -1566,9 +1678,22 @@ namespace System.Windows.Forms {
                }
 
                internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
-                       return Win32SetParent(handle, parent);
+                       Control c = Control.FromHandle (handle);
+                       if (parent == IntPtr.Zero) {
+                               if (!(c is Form)) {
+                                       Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE);
+                               }
+                       }
+                       else
+                               SetVisible (handle, c.is_visible, true);
+                               
+                       if (parent == IntPtr.Zero)
+                               return Win32SetParent (handle, FosterParent);
+                       else
+                               return Win32SetParent(handle, parent);
                }
 
+               // If we ever start using this, we should probably replace FosterParent with IntPtr.Zero
                internal override IntPtr GetParent(IntPtr handle) {
                        return Win32GetParent(handle);
                }
@@ -2260,7 +2385,12 @@ namespace System.Windows.Forms {
                        Win32SetROP2(hdc, ROP2DrawMode.R2_NOT);
                        oldpen = Win32SelectObject(hdc, pen);
 
-                       // We might need to add clipping to the WindowRect of 'handle' - right now we're drawing on the desktop
+                       Control c = Control.FromHandle (handle);
+                       if (c != null) {
+                               Region r = new Region(new Rectangle(c.PointToScreen (c.Location), c.Size));
+
+                               Win32ExtSelectClipRgn(hdc, r.GetHrgn (Graphics.FromHdc (hdc)), (int) ClipCombineMode.RGN_AND);
+                       }
 
                        Win32MoveToEx(hdc, pt.x + rect.Left, pt.y + rect.Top, IntPtr.Zero);
                        if ((rect.Width > 0) && (rect.Height > 0)) {
@@ -2278,6 +2408,9 @@ namespace System.Windows.Forms {
 
                        Win32SelectObject(hdc, oldpen);
                        Win32DeleteObject(pen);
+                       if (c != null)
+                               Win32ExtSelectClipRgn(hdc, IntPtr.Zero, (int) ClipCombineMode.RGN_COPY);
+
                        Win32ReleaseDC(IntPtr.Zero, hdc);
                }
 
@@ -2326,10 +2459,6 @@ namespace System.Windows.Forms {
                
                internal override event EventHandler Idle;
 
-               // Santa's little helper
-               static void Where() {
-                       Console.WriteLine("Here: {0}", new StackTrace().ToString());
-               }
                #endregion      // Public Static Methods
 
                #region Win32 Imports
@@ -2486,6 +2615,9 @@ namespace System.Windows.Forms {
                [DllImport ("user32.dll", EntryPoint="SetLayeredWindowAttributes", CallingConvention=CallingConvention.StdCall)]
                private extern static uint Win32SetLayeredWindowAttributes (IntPtr hwnd, COLORREF crKey, byte bAlpha, LayeredWindowAttributes dwFlags);
 
+               [DllImport ("user32.dll", EntryPoint="GetLayeredWindowAttributes", CallingConvention=CallingConvention.StdCall)]
+               private extern static uint Win32GetLayeredWindowAttributes (IntPtr hwnd, out COLORREF pcrKey, out byte pbAlpha, out LayeredWindowAttributes pwdFlags);
+
                [DllImport ("gdi32.dll", EntryPoint="DeleteObject", CallingConvention=CallingConvention.StdCall)]
                private extern static bool Win32DeleteObject(IntPtr o);
 
@@ -2660,6 +2792,12 @@ namespace System.Windows.Forms {
                [DllImport ("gdi32.dll", EntryPoint="CreateHatchBrush", CallingConvention=CallingConvention.StdCall)]
                internal extern static IntPtr Win32CreateHatchBrush(HatchStyle fnStyle, ref COLORREF color);
 
+               [DllImport("gdi32.dll", EntryPoint = "ExcludeClipRect", CallingConvention = CallingConvention.StdCall)]
+               internal extern static int Win32ExcludeClipRect (IntPtr hdc, int left, int top,  int right, int bottom);
+
+               [DllImport ("gdi32.dll", EntryPoint="ExtSelectClipRgn", CallingConvention=CallingConvention.StdCall)]
+               internal extern static int Win32ExtSelectClipRgn(IntPtr hdc, IntPtr hrgn, int mode);
+
                [DllImport ("winmm.dll", EntryPoint="PlaySoundW", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)]
                internal extern static IntPtr Win32PlaySound(string pszSound, IntPtr hmod, SndFlags fdwSound);