aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Internal/NativeWindow.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Internal/NativeWindow.cs')
-rw-r--r--source/ShiftUI/Internal/NativeWindow.cs324
1 files changed, 324 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/NativeWindow.cs b/source/ShiftUI/Internal/NativeWindow.cs
new file mode 100644
index 0000000..4657276
--- /dev/null
+++ b/source/ShiftUI/Internal/NativeWindow.cs
@@ -0,0 +1,324 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2008 Novell, Inc.
+//
+// Authors:
+// Peter Dennis Bartok [email protected]
+// Ivan N. Zlatev <[email protected]>
+//
+
+
+// COMPLETE
+
+#define ExternalExceptionHandler
+
+using System.Runtime.Remoting;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Collections;
+using System.Diagnostics;
+using System.Drawing;
+using System;
+
+namespace ShiftUI
+{
+ public class NativeWindow : MarshalByRefObject, IWin32Window
+ {
+ IntPtr window_handle = IntPtr.Zero;
+ static Hashtable window_collection = new Hashtable();
+
+ [ThreadStatic]
+ static NativeWindow WindowCreating;
+
+ #region Public Constructors
+ public NativeWindow()
+ {
+ window_handle=IntPtr.Zero;
+ }
+ #endregion // Public Constructors
+
+ #region Public Instance Properties
+ public IntPtr Handle {
+ get {
+ return window_handle;
+ }
+ }
+ #endregion // Public Instance Properties
+
+ #region Public Static Methods
+ public static NativeWindow FromHandle(IntPtr handle)
+ {
+ return FindFirstInTable (handle);
+ }
+ #endregion // Public Static Methods
+
+ #region Private and Internal Methods
+ internal void InvalidateHandle()
+ {
+ RemoveFromTable (this);
+ window_handle = IntPtr.Zero;
+ }
+ #endregion
+
+ #region Public Instance Methods
+ public void AssignHandle(IntPtr handle)
+ {
+ RemoveFromTable (this);
+ window_handle = handle;
+ AddToTable (this);
+ OnHandleChange();
+ }
+
+ private static void AddToTable (NativeWindow window)
+ {
+ IntPtr handle = window.Handle;
+ if (handle == IntPtr.Zero)
+ return;
+
+ lock (window_collection) {
+ object current = window_collection[handle];
+ if (current == null) {
+ window_collection.Add (handle, window);
+ } else {
+ NativeWindow currentWindow = current as NativeWindow;
+ if (currentWindow != null) {
+ if (currentWindow != window) {
+ ArrayList windows = new ArrayList ();
+ windows.Add (currentWindow);
+ windows.Add (window);
+ window_collection[handle] = windows;
+ }
+ } else { // list of windows
+ ArrayList windows = (ArrayList) window_collection[handle];
+ if (!windows.Contains (window))
+ windows.Add (window);
+ }
+ }
+ }
+ }
+
+ private static void RemoveFromTable (NativeWindow window)
+ {
+ IntPtr handle = window.Handle;
+ if (handle == IntPtr.Zero)
+ return;
+
+ lock (window_collection) {
+ object current = window_collection[handle];
+ if (current != null) {
+ NativeWindow currentWindow = current as NativeWindow;
+ if (currentWindow != null) {
+ window_collection.Remove (handle);
+ } else { // list of windows
+ ArrayList windows = (ArrayList) window_collection[handle];
+ windows.Remove (window);
+ if (windows.Count == 0)
+ window_collection.Remove (handle);
+ else if (windows.Count == 1)
+ window_collection[handle] = windows[0];
+ }
+ }
+ }
+ }
+
+ private static NativeWindow FindFirstInTable (IntPtr handle)
+ {
+ if (handle == IntPtr.Zero)
+ return null;
+
+ NativeWindow window = null;
+ lock (window_collection) {
+ object current = window_collection[handle];
+ if (current != null) {
+ window = current as NativeWindow;
+ if (window == null) {
+ ArrayList windows = (ArrayList) current;
+ if (windows.Count > 0)
+ window = (NativeWindow) windows[0];
+ }
+ }
+ }
+ return window;
+ }
+
+ public virtual void CreateHandle(CreateParams cp)
+ {
+ if (cp != null) {
+ WindowCreating = this;
+ window_handle=XplatUI.CreateWindow(cp);
+ WindowCreating = null;
+
+ if (window_handle != IntPtr.Zero)
+ AddToTable (this);
+ }
+
+ }
+
+ public void DefWndProc(ref Message m)
+ {
+ m.Result=XplatUI.DefWndProc(ref m);
+ }
+
+ public virtual void DestroyHandle()
+ {
+ if (window_handle != IntPtr.Zero) {
+ XplatUI.DestroyWindow(window_handle);
+ }
+ }
+
+ public virtual void ReleaseHandle()
+ {
+ RemoveFromTable (this);
+ window_handle=IntPtr.Zero;
+ OnHandleChange();
+ }
+
+ #endregion // Public Instance Methods
+
+ #region Protected Instance Methods
+ ~NativeWindow()
+ {
+ }
+
+ protected virtual void OnHandleChange()
+ {
+ }
+
+ protected virtual void OnThreadException(Exception e)
+ {
+ Application.OnThreadException(e);
+ }
+
+ protected virtual void WndProc(ref Message m)
+ {
+ DefWndProc(ref m);
+ }
+
+ internal static IntPtr WndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam)
+ {
+ IntPtr result = IntPtr.Zero;
+ Message m = new Message();
+ m.HWnd = hWnd;
+ m.Msg = (int)msg;
+ m.WParam = wParam;
+ m.LParam = lParam;
+ m.Result = IntPtr.Zero;
+
+#if debug
+ Console.WriteLine("NativeWindow.cs ({0}, {1}, {2}, {3}): result {4}", hWnd, msg, wParam, lParam, m.Result);
+#endif
+ NativeWindow window = null;
+
+ try {
+ object current = null;
+ lock (window_collection) {
+ current = window_collection[hWnd];
+ }
+
+ window = current as NativeWindow;
+ if (current == null)
+ window = EnsureCreated (window, hWnd);
+
+ if (window != null) {
+ window.WndProc (ref m);
+ result = m.Result;
+ } else if (current is ArrayList) {
+ ArrayList windows = (ArrayList) current;
+ lock (windows) {
+ if (windows.Count > 0) {
+ window = EnsureCreated ((NativeWindow)windows[0], hWnd);
+ window.WndProc (ref m);
+ // the first one is the Widget's one. all others are synthetic,
+ // so we want only the result from the Widget
+ result = m.Result;
+ for (int i=1; i < windows.Count; i++)
+ ((NativeWindow)windows[i]).WndProc (ref m);
+ }
+ }
+ } else {
+ result = XplatUI.DefWndProc (ref m);
+ }
+ }
+ catch (Exception ex) {
+#if !ExternalExceptionHandler
+ if (window != null) {
+ if (msg == Msg.WM_PAINT && window is Widget.WidgetNativeWindow) {
+ // Replace Widget with a red cross
+ var Widget = ((Widget.WidgetNativeWindow)window).Owner;
+ Widget.Hide ();
+ var redCross = new Widget (Widget.Parent, string.Empty);
+ redCross.BackColor = Color.White;
+ redCross.ForeColor = Color.Red;
+ redCross.Bounds = Widget.Bounds;
+ redCross.Paint += HandleRedCrossPaint;
+ }
+ window.OnThreadException (ex);
+ }
+#else
+ throw ex;
+#endif
+ }
+ #if debug
+ Console.WriteLine("NativeWindow.cs: Message {0}, result {1}", msg, m.Result);
+ #endif
+
+ return result;
+ }
+
+ private static void HandleRedCrossPaint (object sender, PaintEventArgs e)
+ {
+ var Widget = sender as Widget;
+ using (var pen = new Pen (Widget.ForeColor, 2)) {
+ var paintRect = Widget.DisplayRectangle;
+ e.Graphics.DrawRectangle (pen, paintRect.Left + 1,
+ paintRect.Top + 1, paintRect.Width - 1, paintRect.Height - 1);
+ // NOTE: .NET's drawing of the red cross seems to have a bug
+ // that draws the bottom and right of the rectangle only 1 pixel
+ // wide. We would get a nicer rectangle using the following code,
+ // but that runs into a problem with libgdiplus.
+ //var paintRect = Widget.DisplayRectangle;
+ //paintRect.Inflate (-1, -1);
+ //e.Graphics.DrawRectangle (pen, paintRect);
+ e.Graphics.DrawLine (pen, paintRect.Location,
+ paintRect.Location + paintRect.Size);
+ e.Graphics.DrawLine (pen, new Point (paintRect.Left, paintRect.Bottom),
+ new Point (paintRect.Right, paintRect.Top));
+ }
+ }
+
+ private static NativeWindow EnsureCreated (NativeWindow window, IntPtr hWnd)
+ {
+ // we need to do this AssignHandle here instead of relying on
+ // Widget.WndProc to do it, because subclasses can override
+ // WndProc, install their own WM_CREATE block, and look at
+ // this.Handle, and it needs to be set. Otherwise, we end up
+ // recursively creating windows and emitting WM_CREATE.
+ if (window == null && WindowCreating != null) {
+ window = WindowCreating;
+ WindowCreating = null;
+ if (window.Handle == IntPtr.Zero)
+ window.AssignHandle (hWnd);
+ }
+ return window;
+ }
+ #endregion // Protected Instance Methods
+ }
+}