diff options
| author | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
|---|---|---|
| committer | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
| commit | d40fed5ce2bc806a91245adb18039634eac13ed0 (patch) | |
| tree | f1d7168aee6db109ac2c738ad18c9db667a6ba69 /source/ShiftUI/Internal/XplatUICarbon.cs | |
| parent | f1856e8ed30ed882229fd3fa2a4038122a5fb441 (diff) | |
| download | shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.gz shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.tar.bz2 shiftos-c--d40fed5ce2bc806a91245adb18039634eac13ed0.zip | |
Move ShiftUI source code to ShiftOS
This'll be a lot easier to work on.
Diffstat (limited to 'source/ShiftUI/Internal/XplatUICarbon.cs')
| -rw-r--r-- | source/ShiftUI/Internal/XplatUICarbon.cs | 2432 |
1 files changed, 2432 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/XplatUICarbon.cs b/source/ShiftUI/Internal/XplatUICarbon.cs new file mode 100644 index 0000000..ec1b53a --- /dev/null +++ b/source/ShiftUI/Internal/XplatUICarbon.cs @@ -0,0 +1,2432 @@ +// 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-2007 Novell, Inc. +// +// Authors: +// Geoff Norton <[email protected]> +// +// + +using System; +using System.Threading; +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using Carbon = ShiftUI.CarbonInternal; + +/// Carbon Version +using ShiftUI; + + +namespace ShiftUI { + internal delegate Rectangle [] HwndDelegate (IntPtr handle); + + internal class XplatUICarbon : XplatUIDriver { + #region Local Variables + // General driver variables + private static XplatUICarbon Instance; + private static int RefCount; + private static bool themes_enabled; + + // Internal members available to the event handler sub-system + internal static IntPtr FocusWindow; + internal static IntPtr ActiveWindow; + internal static IntPtr UnactiveWindow; + internal static IntPtr ReverseWindow; + internal static IntPtr CaretWindow; + + internal static Hwnd MouseHwnd; + + internal static MouseButtons MouseState; + internal static Carbon.Hover Hover; + + internal static HwndDelegate HwndDelegate = new HwndDelegate (GetClippingRectangles); + // Instance members + internal Point mouse_position; + + // Event handlers + internal Carbon.ApplicationHandler ApplicationHandler; + internal Carbon.WidgetHandler WidgetHandler; + internal Carbon.HIObjectHandler HIObjectHandler; + internal Carbon.KeyboardHandler KeyboardHandler; + internal Carbon.MouseHandler MouseHandler; + internal Carbon.WindowHandler WindowHandler; + + // Carbon Specific + internal static GrabStruct Grab; + internal static Carbon.Caret Caret; + private static Carbon.Dnd Dnd; + private static Hashtable WindowMapping; + private static Hashtable HandleMapping; + private static IntPtr FosterParent; + private static IntPtr Subclass; + private static int MenuBarHeight; + internal static ArrayList UtilityWindows; + + // Message loop + private static Queue MessageQueue; + private static bool GetMessageResult; + + private static bool ReverseWindowMapped; + + // Timers + private ArrayList TimerList; + private static bool in_doevents; + + static readonly object instancelock = new object (); + static readonly object queuelock = new object (); + + // Event Handlers + internal override event EventHandler Idle; + #endregion + + #region Constructors + private XplatUICarbon() { + + RefCount = 0; + TimerList = new ArrayList (); + in_doevents = false; + MessageQueue = new Queue (); + + Initialize (); + } + + ~XplatUICarbon() { + // FIXME: Clean up the FosterParent here. + } + #endregion + + #region Singleton specific code + public static XplatUICarbon GetInstance() { + lock (instancelock) { + if (Instance == null) { + Instance = new XplatUICarbon (); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal methods + internal void AddExpose (Hwnd hwnd, bool client, Carbon.HIRect rect) { + AddExpose (hwnd, client, (int) rect.origin.x, (int) rect.origin.y, (int) rect.size.width, (int) rect.size.height); + } + + internal void AddExpose (Hwnd hwnd, bool client, Rectangle rect) { + AddExpose (hwnd, client, (int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height); + } + + internal void FlushQueue () { + CheckTimers (DateTime.UtcNow); + lock (queuelock) { + while (MessageQueue.Count > 0) { + object queueobj = MessageQueue.Dequeue (); + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + } else { + MSG msg = (MSG)queueobj; + NativeWindow.WndProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + } + } + } + + internal static Rectangle [] GetClippingRectangles (IntPtr handle) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + return null; + if (hwnd.Handle != handle) + return new Rectangle [] {hwnd.ClientRect}; + + return (Rectangle []) hwnd.GetClippingRectangles ().ToArray (typeof (Rectangle)); + } + + internal IntPtr GetMousewParam(int Delta) { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Widget) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + + internal IntPtr HandleToWindow (IntPtr handle) { + if (HandleMapping [handle] != null) + return (IntPtr) HandleMapping [handle]; + return IntPtr.Zero; + } + + internal void Initialize () { + if (Marshal.SizeOf<IntPtr> () == 8){ + Console.Error.WriteLine ("WARNING: The Carbon driver has not been ported to 64bits, and very few parts of Windows.Forms will work properly, or at all"); + } + // Initialize the event handlers + Carbon.EventHandler.Driver = this; + ApplicationHandler = new Carbon.ApplicationHandler (this); + WidgetHandler = new Carbon.WidgetHandler (this); + HIObjectHandler = new Carbon.HIObjectHandler (this); + KeyboardHandler = new Carbon.KeyboardHandler (this); + MouseHandler = new Carbon.MouseHandler (this); + WindowHandler = new Carbon.WindowHandler (this); + + // Initilize the mouse Widgets + Hover.Interval = 500; + Hover.Timer = new Timer (); + Hover.Timer.Enabled = false; + Hover.Timer.Interval = Hover.Interval; + Hover.Timer.Tick += new EventHandler (HoverCallback); + Hover.X = -1; + Hover.Y = -1; + MouseState = MouseButtons.None; + mouse_position = Point.Empty; + + // Initialize the Caret + Caret.Timer = new Timer (); + Caret.Timer.Interval = 500; + Caret.Timer.Tick += new EventHandler (CaretCallback); + + // Initialize the D&D + Dnd = new Carbon.Dnd (); + + // Initialize the Carbon Specific stuff + WindowMapping = new Hashtable (); + HandleMapping = new Hashtable (); + UtilityWindows = new ArrayList (); + + // Initialize the FosterParent + Carbon.Rect rect = new Carbon.Rect (); + SetRect (ref rect, (short)0, (short)0, (short)0, (short)0); + Carbon.ProcessSerialNumber psn = new Carbon.ProcessSerialNumber(); + + GetCurrentProcess( ref psn ); + TransformProcessType (ref psn, 1); + SetFrontProcess (ref psn); + + HIObjectRegisterSubclass (__CFStringMakeConstantString ("com.novell.mwfview"), __CFStringMakeConstantString ("com.apple.hiview"), 0, Carbon.EventHandler.EventHandlerDelegate, (uint)Carbon.EventHandler.HIObjectEvents.Length, Carbon.EventHandler.HIObjectEvents, IntPtr.Zero, ref Subclass); + + Carbon.EventHandler.InstallApplicationHandler (); + + CreateNewWindow (Carbon.WindowClass.kDocumentWindowClass, Carbon.WindowAttributes.kWindowStandardHandlerAttribute | Carbon.WindowAttributes.kWindowCloseBoxAttribute | Carbon.WindowAttributes.kWindowFullZoomAttribute | Carbon.WindowAttributes.kWindowCollapseBoxAttribute | Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowCompositingAttribute, ref rect, ref FosterParent); + + CreateNewWindow (Carbon.WindowClass.kOverlayWindowClass, Carbon.WindowAttributes.kWindowNoUpdatesAttribute | Carbon.WindowAttributes.kWindowNoActivatesAttribute, ref rect, ref ReverseWindow); + CreateNewWindow (Carbon.WindowClass.kOverlayWindowClass, Carbon.WindowAttributes.kWindowNoUpdatesAttribute | Carbon.WindowAttributes.kWindowNoActivatesAttribute, ref rect, ref CaretWindow); + + // Get some values about bar heights + Carbon.Rect structRect = new Carbon.Rect (); + Carbon.Rect contentRect = new Carbon.Rect (); + GetWindowBounds (FosterParent, 32, ref structRect); + GetWindowBounds (FosterParent, 33, ref contentRect); + + MenuBarHeight = GetMBarHeight (); + + // Focus + FocusWindow = IntPtr.Zero; + + // Message loop + GetMessageResult = true; + + ReverseWindowMapped = false; + } + + internal void PerformNCCalc(Hwnd hwnd) { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height); + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS(); + ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr(ncp, ptr, true); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal(ptr); + + + rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + hwnd.ClientRect = rect; + + rect = TranslateClientRectangleToQuartzClientRectangle (hwnd); + + if (hwnd.visible) { + Carbon.HIRect r = new Carbon.HIRect (rect.X, rect.Y, rect.Width, rect.Height); + HIViewSetFrame (hwnd.client_window, ref r); + } + + AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height); + } + + internal void ScreenToClient(IntPtr handle, ref Carbon.QDPoint point) { + int x = (int) point.x; + int y = (int) point.y; + + ScreenToClient (handle, ref x, ref y); + + point.x = (short) x; + point.y = (short) y; + } + + internal static Rectangle TranslateClientRectangleToQuartzClientRectangle (Hwnd hwnd) { + return TranslateClientRectangleToQuartzClientRectangle (hwnd, Widget.FromHandle (hwnd.Handle)); + } + + internal static Rectangle TranslateClientRectangleToQuartzClientRectangle (Hwnd hwnd, Widget ctrl) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Rectangle rect = hwnd.ClientRect; + Form form = ctrl as Form; + CreateParams cp = null; + + if (form != null) + cp = form.GetCreateParams (); + + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Rectangle qrect = rect; + + qrect.Y -= borders.top; + qrect.X -= borders.left; + qrect.Width += borders.left + borders.right; + qrect.Height += borders.top + borders.bottom; + + rect = qrect; + } + + if (rect.Width < 1 || rect.Height < 1) { + rect.Width = 1; + rect.Height = 1; + rect.X = -5; + rect.Y = -5; + } + + return rect; + } + + internal static Size TranslateWindowSizeToQuartzWindowSize (CreateParams cp) { + return TranslateWindowSizeToQuartzWindowSize (cp, new Size (cp.Width, cp.Height)); + } + + internal static Size TranslateWindowSizeToQuartzWindowSize (CreateParams cp, Size size) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Form form = cp.control as Form; + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size qsize = size; + + qsize.Width -= borders.left + borders.right; + qsize.Height -= borders.top + borders.bottom; + + size = qsize; + } + + if (size.Height == 0) + size.Height = 1; + if (size.Width == 0) + size.Width = 1; + return size; + } + + internal static Size TranslateQuartzWindowSizeToWindowSize (CreateParams cp, int width, int height) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Size size = new Size (width, height); + Form form = cp.control as Form; + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size qsize = size; + + qsize.Width += borders.left + borders.right; + qsize.Height += borders.top + borders.bottom; + + size = qsize; + } + + return size; + } + #endregion + + #region Callbacks + private void CaretCallback (object sender, EventArgs e) { + if (Caret.Paused) { + return; + } + + if (!Caret.On) { + ShowCaret (); + } else { + HideCaret (); + } + } + + private void HoverCallback (object sender, EventArgs e) { + if ((Hover.X == mouse_position.X) && (Hover.Y == mouse_position.Y)) { + MSG msg = new MSG (); + msg.hwnd = Hover.Hwnd; + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam (0); + msg.lParam = (IntPtr)((ushort)Hover.X << 16 | (ushort)Hover.X); + EnqueueMessage (msg); + } + } + #endregion + + #region Private Methods + private Point ConvertScreenPointToClient (IntPtr handle, Point point) { + Point converted_point = new Point (); + Carbon.Rect window_bounds = new Carbon.Rect (); + Carbon.CGPoint native_point = new Carbon.CGPoint (); + + GetWindowBounds (HIViewGetWindow (handle), 32, ref window_bounds); + + native_point.x = (point.X - window_bounds.left); + native_point.y = (point.Y - window_bounds.top); + + HIViewConvertPoint (ref native_point, IntPtr.Zero, handle); + + converted_point.X = (int)native_point.x; + converted_point.Y = (int)native_point.y; + + return converted_point; + } + + private Point ConvertClientPointToScreen (IntPtr handle, Point point) { + Point converted_point = new Point (); + Carbon.Rect window_bounds = new Carbon.Rect (); + Carbon.CGPoint native_point = new Carbon.CGPoint (); + + GetWindowBounds (HIViewGetWindow (handle), 32, ref window_bounds); + + native_point.x = point.X; + native_point.y = point.Y; + + HIViewConvertPoint (ref native_point, handle, IntPtr.Zero); + + converted_point.X = (int)(native_point.x + window_bounds.left); + converted_point.Y = (int)(native_point.y + window_bounds.top); + + return converted_point; + } + + private double NextTimeout () { + DateTime now = DateTime.UtcNow; + int timeout = 0x7FFFFFF; + lock (TimerList) { + foreach (Timer timer in TimerList) { + int next = (int) (timer.Expires - now).TotalMilliseconds; + if (next < 0) + return 0; + if (next < timeout) + timeout = next; + } + } + if (timeout < Timer.Minimum) + timeout = Timer.Minimum; + + return (double)((double)timeout/1000); + } + + private void CheckTimers (DateTime now) { + lock (TimerList) { + int count = TimerList.Count; + if (count == 0) + return; + for (int i = 0; i < TimerList.Count; i++) { + Timer timer = (Timer) TimerList [i]; + if (timer.Enabled && timer.Expires <= now) { + // Timer ticks: + // - Before MainForm.OnLoad if DoEvents () is called. + // - After MainForm.OnLoad if not. + // + if (in_doevents || + (Application.MWFThread.Current.Context != null && + Application.MWFThread.Current.Context.MainForm != null && + Application.MWFThread.Current.Context.MainForm.IsLoaded)) { + timer.FireTick (); + timer.Update (now); + } + } + } + } + } + + private void WaitForHwndMessage (Hwnd hwnd, Msg message) { + MSG msg = new MSG (); + + bool done = false; + do { + if (GetMessage(null, ref msg, IntPtr.Zero, 0, 0)) { + if ((Msg)msg.message == Msg.WM_QUIT) { + PostQuitMessage (0); + done = true; + } + else { + if (msg.hwnd == hwnd.Handle) { + if ((Msg)msg.message == message) + break; + else if ((Msg)msg.message == Msg.WM_DESTROY) + done = true; + } + + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + } + } while (!done); + } + + private void SendParentNotify(IntPtr child, Msg cause, int x, int y) { + Hwnd hwnd; + + if (child == IntPtr.Zero) { + return; + } + + hwnd = Hwnd.GetObjectFromWindow (child); + + if (hwnd == null) { + return; + } + + if (hwnd.Handle == IntPtr.Zero) { + return; + } + + if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) { + return; + } + + if (hwnd.Parent == null) { + return; + } + + if (hwnd.Parent.Handle == IntPtr.Zero) { + return; + } + + if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), child); + } else { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Widget.MakeParam(x, y)); + } + + SendParentNotify (hwnd.Parent.Handle, cause, x, y); + } + + private bool StyleSet (int s, WindowStyles ws) { + return (s & (int)ws) == (int)ws; + } + + private bool ExStyleSet (int ex, WindowExStyles exws) { + return (ex & (int)exws) == (int)exws; + } + + private void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, out TitleStyle title_style, out int caption_height, out int tool_caption_height) { + + caption_height = 0; + tool_caption_height = 0; + border_static = false; + + if (StyleSet (Style, WindowStyles.WS_CHILD)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.None; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + caption_height = 0; + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) { + caption_height = 0; + + if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) || + ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = (FormBorderStyle) 0xFFFF; + } else { + border_style = FormBorderStyle.None; + } + } + + } else { + title_style = TitleStyle.None; + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + border_style = FormBorderStyle.None; + + if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.SizableToolWindow; + } else { + border_style = FormBorderStyle.Sizable; + } + } else { + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) { + border_style = FormBorderStyle.FixedDialog; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.FixedToolWindow; + } else if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } else { + if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } + } + } + } + + private void SetHwndStyles(Hwnd hwnd, CreateParams cp) { + DeriveStyles(cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.border_static, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height); + } + + private void ShowCaret () { + if (Caret.On) + return; + Caret.On = true; + ShowWindow (CaretWindow); + Graphics g = Graphics.FromHwnd (HIViewGetRoot (CaretWindow)); + + g.FillRectangle (new SolidBrush (Color.Black), new Rectangle (0, 0, Caret.Width, Caret.Height)); + + g.Dispose (); + } + + private void HideCaret () { + if (!Caret.On) + return; + Caret.On = false; + HideWindow (CaretWindow); + } + + private void AccumulateDestroyedHandles (Widget c, ArrayList list) { + if (c != null) { + Widget[] Widgets = c.Widgets.GetAllWidgets (); + + if (c.IsHandleCreated && !c.IsDisposed) { + Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle); + + list.Add (hwnd); + CleanupCachedWindows (hwnd); + } + + for (int i = 0; i < Widgets.Length; i ++) { + AccumulateDestroyedHandles (Widgets[i], list); + } + } + + } + + private void CleanupCachedWindows (Hwnd hwnd) { + if (ActiveWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + ActiveWindow = IntPtr.Zero; + } + + if (FocusWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + FocusWindow = IntPtr.Zero; + } + + if (Grab.Hwnd == hwnd.Handle) { + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + + DestroyCaret (hwnd.Handle); + } + + private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) { + // Don't waste time + if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) { + return; + } + + // Keep the invalid area as small as needed + if ((x + width) > hwnd.width) { + width = hwnd.width - x; + } + + if ((y + height) > hwnd.height) { + height = hwnd.height - y; + } + + if (client) { + hwnd.AddInvalidArea(x, y, width, height); + if (!hwnd.expose_pending && hwnd.visible) { + MSG msg = new MSG (); + msg.message = Msg.WM_PAINT; + msg.hwnd = hwnd.Handle; + EnqueueMessage (msg); + hwnd.expose_pending = true; + } + } else { + hwnd.AddNcInvalidArea (x, y, width, height); + if (!hwnd.nc_expose_pending && hwnd.visible) { + MSG msg = new MSG (); + Region rgn = new Region (hwnd.Invalid); + IntPtr hrgn = rgn.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn; + msg.refobject = rgn; + msg.hwnd = hwnd.Handle; + EnqueueMessage (msg); + hwnd.nc_expose_pending = true; + + } + } + } + #endregion + + #region Public Methods + internal void EnqueueMessage (MSG msg) { + lock (queuelock) { + MessageQueue.Enqueue (msg); + } + } + + internal override void RaiseIdle (EventArgs e) + { + if (Idle != null) + Idle (this, e); + } + + internal override IntPtr InitializeDriver() { + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) { + } + + internal override void EnableThemes() { + themes_enabled = true; + } + + internal override void Activate(IntPtr handle) { + if (ActiveWindow != IntPtr.Zero) { + UnactiveWindow = ActiveWindow; + ActivateWindow (HIViewGetWindow (ActiveWindow), false); + } + ActivateWindow (HIViewGetWindow (handle), true); + ActiveWindow = handle; + } + + internal override void AudibleAlert(AlertType alert) { + AlertSoundPlay (); + } + + internal override void BeginMoveResize (IntPtr handle) { + } + + internal override void CaretVisible (IntPtr hwnd, bool visible) { + if (Caret.Hwnd == hwnd) { + if (visible) { + if (Caret.Visible < 1) { + Caret.Visible++; + Caret.On = false; + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } else { + Caret.Visible--; + if (Caret.Visible == 0) { + Caret.Timer.Stop (); + HideCaret (); + } + } + } + } + + internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) { + WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect); + return true; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertClientPointToScreen (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertClientPointToScreen (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) { + ArrayList list = new ArrayList (); + DataFormats.Format f = DataFormats.Format.List; + + while (f != null) { + list.Add (f.Id); + f = f.Next; + } + + return (int [])list.ToArray (typeof (int)); + } + + internal override void ClipboardClose(IntPtr handle) { + } + + //TODO: Map our internal formats to the right os code where we can + internal override int ClipboardGetID(IntPtr handle, string format) { + return (int)__CFStringMakeConstantString (format); + } + + internal override IntPtr ClipboardOpen(bool primary_selection) { + if (primary_selection) + return Carbon.Pasteboard.Primary; + return Carbon.Pasteboard.Application; + } + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) { + return Carbon.Pasteboard.Retrieve (handle, type); + } + + internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) { + Carbon.Pasteboard.Store (handle, obj, type); + } + + internal override void CreateCaret (IntPtr hwnd, int width, int height) { + if (Caret.Hwnd != IntPtr.Zero) + DestroyCaret (Caret.Hwnd); + + Caret.Hwnd = hwnd; + Caret.Width = width; + Caret.Height = height; + Caret.Visible = 0; + Caret.On = false; + } + + internal override IntPtr CreateWindow(CreateParams cp) { + Hwnd hwnd; + Hwnd parent_hwnd = null; + int X; + int Y; + int Width; + int Height; + IntPtr ParentHandle; + IntPtr WindowHandle; + IntPtr WholeWindow; + IntPtr ClientWindow; + IntPtr WholeWindowTracking; + IntPtr ClientWindowTracking; + + hwnd = new Hwnd (); + + X = cp.X; + Y = cp.Y; + Width = cp.Width; + Height = cp.Height; + ParentHandle = IntPtr.Zero; + WindowHandle = IntPtr.Zero; + WholeWindow = IntPtr.Zero; + ClientWindow = IntPtr.Zero; + WholeWindowTracking = IntPtr.Zero; + ClientWindowTracking = IntPtr.Zero; + + if (Width < 1) Width = 1; + if (Height < 1) Height = 1; + + if (cp.Parent != IntPtr.Zero) { + parent_hwnd = Hwnd.ObjectFromHandle (cp.Parent); + ParentHandle = parent_hwnd.client_window; + } else { + if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + HIViewFindByID (HIViewGetRoot (FosterParent), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref ParentHandle); + } + } + + Point next; + if (cp.control is Form) { + next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd); + X = next.X; + Y = next.Y; + } + + hwnd.x = X; + hwnd.y = Y; + hwnd.width = Width; + hwnd.height = Height; + hwnd.Parent = Hwnd.ObjectFromHandle (cp.Parent); + hwnd.initial_style = cp.WindowStyle; + hwnd.initial_ex_style = cp.WindowExStyle; + hwnd.visible = false; + + if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) { + hwnd.enabled = false; + } + + ClientWindow = IntPtr.Zero; + + Size QWindowSize = TranslateWindowSizeToQuartzWindowSize (cp); + Rectangle QClientRect = TranslateClientRectangleToQuartzClientRectangle (hwnd, cp.control); + + SetHwndStyles(hwnd, cp); +/* FIXME */ + if (ParentHandle == IntPtr.Zero) { + IntPtr WindowView = IntPtr.Zero; + IntPtr GrowBox = IntPtr.Zero; + Carbon.WindowClass windowklass = Carbon.WindowClass.kOverlayWindowClass; + Carbon.WindowAttributes attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) { + attributes |= Carbon.WindowAttributes.kWindowCollapseBoxAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowHorizontalZoomAttribute | Carbon.WindowAttributes.kWindowVerticalZoomAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) { + attributes |= Carbon.WindowAttributes.kWindowCloseBoxAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + windowklass = Carbon.WindowClass.kDocumentWindowClass; + } + if (hwnd.border_style == FormBorderStyle.FixedToolWindow) { + windowklass = Carbon.WindowClass.kUtilityWindowClass; + } else if (hwnd.border_style == FormBorderStyle.SizableToolWindow) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute; + windowklass = Carbon.WindowClass.kUtilityWindowClass; + } + if (windowklass == Carbon.WindowClass.kOverlayWindowClass) { + attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + } + attributes |= Carbon.WindowAttributes.kWindowLiveResizeAttribute; + + Carbon.Rect rect = new Carbon.Rect (); + if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) { + SetRect (ref rect, (short)X, (short)(Y), (short)(X + QWindowSize.Width), (short)(Y + QWindowSize.Height)); + } else { + SetRect (ref rect, (short)X, (short)(Y + MenuBarHeight), (short)(X + QWindowSize.Width), (short)(Y + MenuBarHeight + QWindowSize.Height)); + } + + CreateNewWindow (windowklass, attributes, ref rect, ref WindowHandle); + + Carbon.EventHandler.InstallWindowHandler (WindowHandle); + HIViewFindByID (HIViewGetRoot (WindowHandle), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref WindowView); + HIViewFindByID (HIViewGetRoot (WindowHandle), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 7), ref GrowBox); + HIGrowBoxViewSetTransparent (GrowBox, true); + SetAutomaticWidgetDragTrackingEnabledForWindow (WindowHandle, true); + ParentHandle = WindowView; + } + + HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref WholeWindow); + HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref ClientWindow); + + Carbon.EventHandler.InstallWidgetHandler (WholeWindow); + Carbon.EventHandler.InstallWidgetHandler (ClientWindow); + + // Enable embedding on Widgets + HIViewChangeFeatures (WholeWindow, 1<<1, 0); + HIViewChangeFeatures (ClientWindow, 1<<1, 0); + + HIViewNewTrackingArea (WholeWindow, IntPtr.Zero, (UInt64)WholeWindow, ref WholeWindowTracking); + HIViewNewTrackingArea (ClientWindow, IntPtr.Zero, (UInt64)ClientWindow, ref ClientWindowTracking); + Carbon.HIRect WholeRect; + if (WindowHandle != IntPtr.Zero) { + WholeRect = new Carbon.HIRect (0, 0, QWindowSize.Width, QWindowSize.Height); + } else { + WholeRect = new Carbon.HIRect (X, Y, QWindowSize.Width, QWindowSize.Height); + } + Carbon.HIRect ClientRect = new Carbon.HIRect (QClientRect.X, QClientRect.Y, QClientRect.Width, QClientRect.Height); + HIViewSetFrame (WholeWindow, ref WholeRect); + HIViewSetFrame (ClientWindow, ref ClientRect); + + HIViewAddSubview (ParentHandle, WholeWindow); + HIViewAddSubview (WholeWindow, ClientWindow); + + hwnd.WholeWindow = WholeWindow; + hwnd.ClientWindow = ClientWindow; + + if (WindowHandle != IntPtr.Zero) { + WindowMapping [hwnd.Handle] = WindowHandle; + HandleMapping [WindowHandle] = hwnd.Handle; + if (hwnd.border_style == FormBorderStyle.FixedToolWindow || hwnd.border_style == FormBorderStyle.SizableToolWindow) { + UtilityWindows.Add (WindowHandle); + } + } + + // Allow dnd on Widgets + Dnd.SetAllowDrop (hwnd, true); + + Text (hwnd.Handle, cp.Caption); + + SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); + SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue); + + if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { + if (WindowHandle != IntPtr.Zero) { + if (Widget.FromHandle(hwnd.Handle) is Form) { + Form f = Widget.FromHandle(hwnd.Handle) as Form; + if (f.WindowState == FormWindowState.Normal) { + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + ShowWindow (WindowHandle); + WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW); + } + HIViewSetVisible (WholeWindow, true); + HIViewSetVisible (ClientWindow, true); + hwnd.visible = true; + if (!(Widget.FromHandle(hwnd.Handle) is Form)) { + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Minimized); + } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Maximized); + } + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName=XplatUI.GetDefaultClassName (GetType ()); + create_params.ClassStyle = 0; + create_params.ExStyle=0; + create_params.Parent=IntPtr.Zero; + create_params.Param=0; + + return CreateWindow(create_params); + } + + internal override Bitmap DefineStdCursorBitmap (StdCursor id) { + return Carbon.Cursor.DefineStdCursorBitmap (id); + } + + internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + return Carbon.Cursor.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot); + } + + internal override IntPtr DefineStdCursor (StdCursor id) { + return Carbon.Cursor.DefineStdCursor (id); + } + + internal override IntPtr DefWndProc(ref Message msg) { + Hwnd hwnd = Hwnd.ObjectFromHandle (msg.HWnd); + switch ((Msg)msg.Msg) { + case Msg.WM_IME_COMPOSITION: + string s = KeyboardHandler.ComposedString; + foreach (char c in s) + SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam); + break; + case Msg.WM_IME_CHAR: + // On Windows API it sends two WM_CHAR messages for each byte, but + // I wonder if it is worthy to emulate it (also no idea how to + // reconstruct those bytes into chars). + SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam); + return IntPtr.Zero; + case Msg.WM_QUIT: { + if (WindowMapping [hwnd.Handle] != null) + + Exit (); + break; + } + case Msg.WM_PAINT: { + hwnd.expose_pending = false; + break; + } + case Msg.WM_NCPAINT: { + hwnd.nc_expose_pending = false; + break; + } + case Msg.WM_NCCALCSIZE: { + if (msg.WParam == (IntPtr)1) { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS)); + + // Add all the stuff X is supposed to draw. + Widget ctrl = Widget.FromHandle (hwnd.Handle); + if (ctrl != null) { + Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null); + + ncp.rgrc1.top += rect.top; + ncp.rgrc1.bottom -= rect.bottom; + ncp.rgrc1.left += rect.left; + ncp.rgrc1.right -= rect.right; + + Marshal.StructureToPtr (ncp, msg.LParam, true); + } + } + break; + } + case Msg.WM_SETCURSOR: { + // Pass to parent window first + while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) { + hwnd = hwnd.parent; + msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam); + } + + if (msg.Result == IntPtr.Zero) { + IntPtr handle; + + switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) { + case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break; + case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) { + //FIXME: AudibleAlert(); + } + handle = Cursors.Default.handle; + break; + + case HitTest.HTHELP: handle = Cursors.Help.handle; break; + case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break; + case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break; + + #if SameAsDefault + case HitTest.HTGROWBOX: + case HitTest.HTSIZE: + case HitTest.HTZOOM: + case HitTest.HTVSCROLL: + case HitTest.HTSYSMENU: + case HitTest.HTREDUCE: + case HitTest.HTNOWHERE: + case HitTest.HTMAXBUTTON: + case HitTest.HTMINBUTTON: + case HitTest.HTMENU: + case HitTest.HSCROLL: + case HitTest.HTBOTTOM: + case HitTest.HTCAPTION: + case HitTest.HTCLIENT: + case HitTest.HTCLOSE: + #endif + default: handle = Cursors.Default.handle; break; + } + SetCursor(msg.HWnd, handle); + } + return (IntPtr)1; + } + } + return IntPtr.Zero; + } + + internal override void DestroyCaret (IntPtr hwnd) { + if (Caret.Hwnd == hwnd) { + if (Caret.Visible == 1) { + Caret.Timer.Stop (); + HideCaret (); + } + Caret.Hwnd = IntPtr.Zero; + Caret.Visible = 0; + Caret.On = false; + } + } + + [MonoTODO] + internal override void DestroyCursor(IntPtr cursor) { + throw new NotImplementedException (); + } + + internal override void DestroyWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue); + + CleanupCachedWindows (hwnd); + + ArrayList windows = new ArrayList (); + + AccumulateDestroyedHandles (Widget.WidgetNativeWindow.WidgetFromHandle(hwnd.Handle), windows); + + + foreach (Hwnd h in windows) { + SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + h.zombie = true; + } + + // TODO: This is crashing swf-messageboxes + /* + if (false && hwnd.whole_window != IntPtr.Zero) + CFRelease (hwnd.whole_window); + if (false && hwnd.client_window != IntPtr.Zero) + CFRelease (hwnd.client_window); + */ + + if (WindowMapping [hwnd.Handle] != null) { + DisposeWindow ((IntPtr)(WindowMapping [hwnd.Handle])); + WindowMapping.Remove (hwnd.Handle); + } + } + + internal override IntPtr DispatchMessage(ref MSG msg) { + return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + internal override void DoEvents() { + MSG msg = new MSG (); + + in_doevents = true; + while (PeekMessage (null, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + in_doevents = false; + + } + + internal override void EnableWindow(IntPtr handle, bool Enable) { + //Like X11 we need not do anything here + } + + internal override void EndLoop(Thread thread) { + } + + internal void Exit () { + GetMessageResult = false; + } + + internal override IntPtr GetActive() { + return ActiveWindow; + } + + internal override Region GetClipRegion(IntPtr hwnd) { + return null; + } + + [MonoTODO] + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) { + width = 12; + height = 12; + hotspot_x = 0; + hotspot_y = 0; + } + + internal override void GetDisplaySize(out Size size) { + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + size = new Size ((int)bounds.size.width, (int)bounds.size.height); + } + + internal override IntPtr GetParent(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null && hwnd.Parent != null) { + return hwnd.Parent.Handle; + } + return IntPtr.Zero; + } + + internal override IntPtr GetPreviousWindow(IntPtr handle) { + return HIViewGetPreviousView(handle); + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) { + Carbon.QDPoint pt = new Carbon.QDPoint (); + GetGlobalMouse (ref pt); + x = pt.x; + y = pt.y; + } + + internal override IntPtr GetFocus() { + return FocusWindow; + } + + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) { + FontFamily ff = font.FontFamily; + ascent = ff.GetCellAscent (font.Style); + descent = ff.GetCellDescent (font.Style); + return true; + } + + internal override Point GetMenuOrigin(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + return hwnd.MenuOrigin; + } + return Point.Empty; + } + + internal override bool GetMessage(object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) { + IntPtr evtRef = IntPtr.Zero; + IntPtr target = GetEventDispatcherTarget(); + CheckTimers (DateTime.UtcNow); + ReceiveNextEvent (0, IntPtr.Zero, 0, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + + object queueobj; + loop: + lock (queuelock) { + + if (MessageQueue.Count <= 0) { + if (Idle != null) + Idle (this, EventArgs.Empty); + else if (TimerList.Count == 0) { + ReceiveNextEvent (0, IntPtr.Zero, 0.15, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + } else { + ReceiveNextEvent (0, IntPtr.Zero, NextTimeout (), true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + } + msg.hwnd = IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return GetMessageResult; + } + queueobj = MessageQueue.Dequeue (); + } + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + goto loop; + } else { + msg = (MSG)queueobj; + } + return GetMessageResult; + } + + [MonoTODO] + internal override bool GetText(IntPtr handle, out string text) { + throw new NotImplementedException (); + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + x = hwnd.x; + y = hwnd.y; + width = hwnd.width; + height = hwnd.height; + + PerformNCCalc(hwnd); + + client_width = hwnd.ClientRect.Width; + client_height = hwnd.ClientRect.Height; + + return; + } + + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + + internal override FormWindowState GetWindowState(IntPtr hwnd) { + IntPtr window = HIViewGetWindow (hwnd); + + if (IsWindowCollapsed (window)) + return FormWindowState.Minimized; + if (IsWindowInStandardState (window, IntPtr.Zero, IntPtr.Zero)) + return FormWindowState.Maximized; + + return FormWindowState.Normal; + } + + internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) { + Grab.Hwnd = handle; + Grab.Confined = confine_to_handle != IntPtr.Zero; + /* FIXME: Set the Grab.Area */ + } + + internal override void UngrabWindow(IntPtr hwnd) { + bool was_grabbed = Grab.Hwnd != IntPtr.Zero; + + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + + if (was_grabbed) { + // lparam should be the handle to the window gaining the mouse capture, + // but we dont have that information like X11. + // Also only generate WM_CAPTURECHANGED if the window actually was grabbed. + SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void HandleException(Exception e) { + StackTrace st = new StackTrace(e); + Console.WriteLine("Exception '{0}'", e.Message+st.ToString()); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void Invalidate (IntPtr handle, Rectangle rc, bool clear) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (clear) { + AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height); + } else { + AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height); + } + } + + internal override void InvalidateNC (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height); + } + + internal override bool IsEnabled(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).Enabled; + } + + internal override bool IsVisible(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).visible; + } + + internal override void KillTimer(Timer timer) { + lock (TimerList) { + TimerList.Remove(timer); + } + } + + + internal override void OverrideCursor(IntPtr cursor) { + } + + internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) { + PaintEventArgs paint_event; + Hwnd hwnd; + Hwnd paint_hwnd; + + hwnd = Hwnd.ObjectFromHandle(msg.HWnd); + if (msg.HWnd == handle) { + paint_hwnd = hwnd; + } else { + paint_hwnd = Hwnd.ObjectFromHandle (handle); + } + + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret(); + } + + Graphics dc; + + if (client) { + dc = Graphics.FromHwnd (paint_hwnd.client_window); + + Region clip_region = new Region (); + clip_region.MakeEmpty(); + + foreach (Rectangle r in hwnd.ClipRectangles) { + /* Expand the region slightly. + * See bug 464464. + */ + Rectangle r2 = Rectangle.FromLTRB (r.Left, r.Top, r.Right, r.Bottom + 1); + clip_region.Union (r2); + } + + if (hwnd.UserClip != null) { + clip_region.Intersect(hwnd.UserClip); + } + + // FIXME: Clip region is hosed + dc.Clip = clip_region; + paint_event = new PaintEventArgs(dc, hwnd.Invalid); + hwnd.expose_pending = false; + hwnd.ClearInvalidArea(); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + } else { + dc = Graphics.FromHwnd (paint_hwnd.whole_window); + + if (!hwnd.nc_invalid.IsEmpty) { + // FIXME: Clip region is hosed + dc.SetClip (hwnd.nc_invalid); + paint_event = new PaintEventArgs(dc, hwnd.nc_invalid); + } else { + paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height)); + } + hwnd.nc_expose_pending = false; + hwnd.ClearNcInvalidArea (); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + } + + return paint_event; + } + + internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + // FIXME: Pop is causing invalid stack ops sometimes; race condition? + try { + Graphics dc = (Graphics)hwnd.drawing_stack.Pop(); + dc.Flush (); + dc.Dispose (); + + PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop(); + pe.SetGraphics (null); + pe.Dispose (); + } catch {} + + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Paused = false; + } + } + + internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) { + IntPtr evtRef = IntPtr.Zero; + IntPtr target = GetEventDispatcherTarget(); + CheckTimers (DateTime.UtcNow); + ReceiveNextEvent (0, IntPtr.Zero, 0, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + + lock (queuelock) { + if (MessageQueue.Count <= 0) { + return false; + } else { + object queueobj; + if (flags == (uint)PeekMessageFlags.PM_REMOVE) + queueobj = MessageQueue.Dequeue (); + else + queueobj = MessageQueue.Peek (); + + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + return false; + } + msg = (MSG)queueobj; + return true; + } + } + } + + internal override bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + MSG msg = new MSG(); + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + EnqueueMessage (msg); + return true; + } + + internal override void PostQuitMessage(int exitCode) { + PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + } + + internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave) { + } + + internal override void RequestNCRecalc(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + PerformNCCalc(hwnd); + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + InvalidateNC(handle); + } + + [MonoTODO] + internal override void ResetMouseHover(IntPtr handle) { + throw new NotImplementedException(); + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertScreenPointToClient (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertScreenPointToClient (hwnd.WholeWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool clear) { + /* + * This used to use a HIViewScrollRect but this causes issues with the fact that we dont coalesce + * updates properly with our short-circuiting of the window manager. For now we'll do a less + * efficient invalidation of the entire handle which appears to fix the problem + * see bug #381084 + */ + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false); + } + + + internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool clear) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false); + } + + [MonoTODO] + internal override void SendAsyncMethod (AsyncMethodData method) { + // Fake async + lock (queuelock) { + MessageQueue.Enqueue (GCHandle.Alloc (method)); + } + } + + [MonoTODO] + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + return NativeWindow.WndProc(hwnd, message, wParam, lParam); + } + + internal override int SendInput(IntPtr hwnd, Queue keys) { + return 0; + } + + + internal override void SetCaretPos (IntPtr hwnd, int x, int y) { + if (hwnd != IntPtr.Zero && hwnd == Caret.Hwnd) { + Caret.X = x; + Caret.Y = y; + ClientToScreen (hwnd, ref x, ref y); + SizeWindow (new Rectangle (x, y, Caret.Width, Caret.Height), CaretWindow); + Caret.Timer.Stop (); + HideCaret (); + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } + + internal override void SetClipRegion(IntPtr hwnd, Region region) { + throw new NotImplementedException(); + } + + internal override void SetCursor(IntPtr window, IntPtr cursor) { + Hwnd hwnd = Hwnd.ObjectFromHandle (window); + + hwnd.Cursor = cursor; + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) { + CGDisplayMoveCursorToPoint (CGMainDisplayID (), new Carbon.CGPoint (x, y)); + } + + internal override void SetFocus(IntPtr handle) { + if (FocusWindow != IntPtr.Zero) { + PostMessage(FocusWindow, Msg.WM_KILLFOCUS, handle, IntPtr.Zero); + } + PostMessage(handle, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + FocusWindow = handle; + } + + internal override void SetIcon(IntPtr handle, Icon icon) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + // FIXME: we need to map the icon for active window switches + if (WindowMapping [hwnd.Handle] != null) { + if (icon == null) { + RestoreApplicationDockTileImage (); + } else { + Bitmap bitmap; + int size; + IntPtr[] data; + int index; + + bitmap = new Bitmap (128, 128); + using (Graphics g = Graphics.FromImage (bitmap)) { + g.DrawImage (icon.ToBitmap (), 0, 0, 128, 128); + } + index = 0; + size = bitmap.Width * bitmap.Height; + data = new IntPtr[size]; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + int pixel = bitmap.GetPixel (x, y).ToArgb (); + if (BitConverter.IsLittleEndian) { + byte a = (byte) ((pixel >> 24) & 0xFF); + byte r = (byte) ((pixel >> 16) & 0xFF); + byte g = (byte) ((pixel >> 8) & 0xFF); + byte b = (byte) (pixel & 0xFF); + data[index++] = (IntPtr)(a + (r << 8) + (g << 16) + (b << 24)); + } else { + data[index++] = (IntPtr)pixel; + } + } + } + + IntPtr provider = CGDataProviderCreateWithData (IntPtr.Zero, data, size*4, IntPtr.Zero); + IntPtr image = CGImageCreate (128, 128, 8, 32, 4*128, CGColorSpaceCreateDeviceRGB (), 4, provider, IntPtr.Zero, 0, 0); + SetApplicationDockTileImage (image); + } + } + } + + + internal override void SetModal(IntPtr handle, bool Modal) { + IntPtr hWnd = HIViewGetWindow (Hwnd.ObjectFromHandle (handle).WholeWindow); + if (Modal) + BeginAppModalStateForWindow (hWnd); + else + EndAppModalStateForWindow (hWnd); + return; + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) { + IntPtr ParentHandle = IntPtr.Zero; + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + hwnd.Parent = Hwnd.ObjectFromHandle (parent); + if (HIViewGetSuperview (hwnd.whole_window) != IntPtr.Zero) { + HIViewRemoveFromSuperview (hwnd.whole_window); + } + if (hwnd.parent == null) + HIViewFindByID (HIViewGetRoot (FosterParent), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref ParentHandle); + HIViewAddSubview (hwnd.parent == null ? ParentHandle : hwnd.Parent.client_window, hwnd.whole_window); + HIViewPlaceInSuperviewAt (hwnd.whole_window, hwnd.X, hwnd.Y); + HIViewAddSubview (hwnd.whole_window, hwnd.client_window); + HIViewPlaceInSuperviewAt (hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y); + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) { + lock (TimerList) { + TimerList.Add (timer); + } + } + + internal override bool SetTopmost(IntPtr hWnd, bool Enabled) { + HIViewSetZOrder (hWnd, 1, IntPtr.Zero); + return true; + } + + internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) { + // TODO: Set window owner. + return true; + } + + internal override bool SetVisible(IntPtr handle, bool visible, bool activate) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + object window = WindowMapping [hwnd.Handle]; + if (window != null) + if (visible) + ShowWindow ((IntPtr)window); + else + HideWindow ((IntPtr)window); + + if (visible) + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + HIViewSetVisible (hwnd.whole_window, visible); + HIViewSetVisible (hwnd.client_window, visible); + + hwnd.visible = visible; + hwnd.Mapped = true; + return true; + } + + internal override void SetAllowDrop (IntPtr handle, bool value) { + // Like X11 we allow drop on al windows and filter in our handler + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.client_window, data, allowed_effects); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) { + Form form = Widget.FromHandle (handle) as Form; + if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow || + border_style == FormBorderStyle.SizableToolWindow)) { + form.window_manager = new ToolWindowManager (form); + } + + RequestNCRecalc(handle); + } + + internal override void SetMenu(IntPtr handle, Menu menu) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.menu = menu; + + RequestNCRecalc(handle); + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) { + } + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) { + return; + } + + // Win32 automatically changes negative width/height to 0. + if (width < 0) + width = 0; + if (height < 0) + height = 0; + + // X requires a sanity check for width & height; otherwise it dies + if (hwnd.zero_sized && width > 0 && height > 0) { + if (hwnd.visible) { + HIViewSetVisible(hwnd.WholeWindow, true); + } + hwnd.zero_sized = false; + } + + if ((width < 1) || (height < 1)) { + hwnd.zero_sized = true; + HIViewSetVisible(hwnd.WholeWindow, false); + } + + // Save a server roundtrip (and prevent a feedback loop) + if ((hwnd.x == x) && (hwnd.y == y) && (hwnd.width == width) && (hwnd.height == height)) { + return; + } + + if (!hwnd.zero_sized) { + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + Widget ctrl = Widget.FromHandle (handle); + CreateParams cp = ctrl.GetCreateParams (); + Size TranslatedSize = TranslateWindowSizeToQuartzWindowSize (cp, new Size (width, height)); + Carbon.Rect rect = new Carbon.Rect (); + + if (WindowMapping [hwnd.Handle] != null) { + if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) { + SetRect (ref rect, (short)x, (short)y, (short)(x+TranslatedSize.Width), (short)(y+TranslatedSize.Height)); + } else { + SetRect (ref rect, (short)x, (short)(y+MenuBarHeight), (short)(x+TranslatedSize.Width), (short)(y+MenuBarHeight+TranslatedSize.Height)); + } + SetWindowBounds ((IntPtr) WindowMapping [hwnd.Handle], 33, ref rect); + Carbon.HIRect frame_rect = new Carbon.HIRect (0, 0, TranslatedSize.Width, TranslatedSize.Height); + HIViewSetFrame (hwnd.whole_window, ref frame_rect); + SetCaretPos (Caret.Hwnd, Caret.X, Caret.Y); + } else { + Carbon.HIRect frame_rect = new Carbon.HIRect (x, y, TranslatedSize.Width, TranslatedSize.Height); + HIViewSetFrame (hwnd.whole_window, ref frame_rect); + } + PerformNCCalc(hwnd); + } + + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + } + + internal override void SetWindowState(IntPtr handle, FormWindowState state) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + IntPtr window = HIViewGetWindow (handle); + + switch (state) { + case FormWindowState.Minimized: { + CollapseWindow (window, true); + break; + } + case FormWindowState.Normal: { + ZoomWindow (window, 7, false); + break; + } + case FormWindowState.Maximized: { + Form form = Widget.FromHandle (hwnd.Handle) as Form; + if (form != null && form.FormBorderStyle == FormBorderStyle.None) { + Carbon.Rect rect = new Carbon.Rect (); + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + SetRect (ref rect, (short)0, (short)0, (short)bounds.size.width, (short)bounds.size.height); + SetWindowBounds ((IntPtr) WindowMapping [hwnd.Handle], 33, ref rect); + HIViewSetFrame (hwnd.whole_window, ref bounds); + } else { + ZoomWindow (window, 8, false); + } + break; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + SetHwndStyles(hwnd, cp); + + if (WindowMapping [hwnd.Handle] != null) { + Carbon.WindowAttributes attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowCollapseBoxAttribute; + } + if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowHorizontalZoomAttribute | Carbon.WindowAttributes.kWindowVerticalZoomAttribute; + } + if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowCloseBoxAttribute; + } + if ((cp.ExStyle & ((int)WindowExStyles.WS_EX_TOOLWINDOW)) != 0) { + attributes = Carbon.WindowAttributes.kWindowStandardHandlerAttribute | Carbon.WindowAttributes.kWindowCompositingAttribute; + } + attributes |= Carbon.WindowAttributes.kWindowLiveResizeAttribute; + + Carbon.WindowAttributes outAttributes = Carbon.WindowAttributes.kWindowNoAttributes; + GetWindowAttributes ((IntPtr)WindowMapping [hwnd.Handle], ref outAttributes); + ChangeWindowAttributes ((IntPtr)WindowMapping [hwnd.Handle], attributes, outAttributes); + } + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) { + } + + internal override double GetWindowTransparency(IntPtr handle) + { + return 1.0; + } + + internal override TransparencySupport SupportsTransparency() { + return TransparencySupport.None; + } + + internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool Top, bool Bottom) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (Top) { + HIViewSetZOrder (hwnd.whole_window, 2, IntPtr.Zero); + return true; + } else if (!Bottom) { + Hwnd after_hwnd = Hwnd.ObjectFromHandle (after_handle); + HIViewSetZOrder (hwnd.whole_window, 2, (after_handle == IntPtr.Zero ? IntPtr.Zero : after_hwnd.whole_window)); + } else { + HIViewSetZOrder (hwnd.whole_window, 1, IntPtr.Zero); + return true; + } + return false; + } + + internal override void ShowCursor(bool show) { + if (show) + CGDisplayShowCursor (CGMainDisplayID ()); + else + CGDisplayHideCursor (CGMainDisplayID ()); + } + + internal override object StartLoop(Thread thread) { + return new object (); + } + + [MonoTODO] + internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon) + { + throw new NotImplementedException (); + } + + internal override bool Text(IntPtr handle, string text) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + if (WindowMapping [hwnd.Handle] != null) { + SetWindowTitleWithCFString ((IntPtr)(WindowMapping [hwnd.Handle]), __CFStringMakeConstantString (text)); + } + SetWidgetTitleWithCFString (hwnd.whole_window, __CFStringMakeConstantString (text)); + SetWidgetTitleWithCFString (hwnd.client_window, __CFStringMakeConstantString (text)); + return true; + } + + internal override void UpdateWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (!hwnd.visible || !HIViewIsVisible (handle)) { + return; + } + + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + } + + internal override bool TranslateMessage(ref MSG msg) { + return Carbon.EventHandler.TranslateMessage (ref msg); + } + + #region Reversible regions + /* + * Quartz has no concept of XOR drawing due to its compositing nature + * We fake this by mapping a overlay window on the first draw and mapping it on the second. + * This has some issues with it because its POSSIBLE for WidgetPaint.DrawReversible* to actually + * reverse two regions at once. We dont do this in MWF, but this behaviour woudn't work. + * We could in theory cache the Rectangle/Color combination to handle this behaviour. + * + * PROBLEMS: This has some flicker / banding + */ + internal void SizeWindow (Rectangle rect, IntPtr window) { + Carbon.Rect qrect = new Carbon.Rect (); + + SetRect (ref qrect, (short)rect.X, (short)rect.Y, (short)(rect.X+rect.Width), (short)(rect.Y+rect.Height)); + + SetWindowBounds (window, 33, ref qrect); + } + + internal override void DrawReversibleLine(Point start, Point end, Color backColor) { +// throw new NotImplementedException(); + } + + internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) { +// throw new NotImplementedException(); + } + + internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) { +// throw new NotImplementedException(); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) { + Rectangle size_rect = rect; + int new_x = 0; + int new_y = 0; + + if (ReverseWindowMapped) { + HideWindow (ReverseWindow); + ReverseWindowMapped = false; + } else { + ClientToScreen(handle, ref new_x, ref new_y); + + size_rect.X += new_x; + size_rect.Y += new_y; + + SizeWindow (size_rect, ReverseWindow); + ShowWindow (ReverseWindow); + + rect.X = 0; + rect.Y = 0; + rect.Width -= 1; + rect.Height -= 1; + + Graphics g = Graphics.FromHwnd (HIViewGetRoot (ReverseWindow)); + + for (int i = 0; i < line_width; i++) { + g.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (Color.Black), rect); + rect.X += 1; + rect.Y += 1; + rect.Width -= 1; + rect.Height -= 1; + } + + g.Flush (); + g.Dispose (); + + ReverseWindowMapped = true; + } + } + #endregion + + internal override SizeF GetAutoScaleSize(Font font) { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromImage (new Bitmap (1, 1)); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override Point MousePosition { + get { + return mouse_position; + } + } + #endregion + + #region System information + internal override int KeyboardSpeed { get{ throw new NotImplementedException(); } } + internal override int KeyboardDelay { get{ throw new NotImplementedException(); } } + + internal override int CaptionHeight { + get { + return 19; + } + } + + internal override Size CursorSize { get{ throw new NotImplementedException(); } } + internal override bool DragFullWindows { get{ throw new NotImplementedException(); } } + internal override Size DragSize { + get { + return new Size(4, 4); + } + } + + internal override Size FrameBorderSize { + get { + return new Size (2, 2); + } + } + + internal override Size IconSize { get{ throw new NotImplementedException(); } } + internal override Size MaxWindowTrackSize { get{ throw new NotImplementedException(); } } + internal override bool MenuAccessKeysUnderlined { + get { + return false; + } + } + internal override Size MinimizedWindowSpacingSize { get{ throw new NotImplementedException(); } } + + internal override Size MinimumWindowSize { + get { + return new Size(110, 22); + } + } + + internal override Keys ModifierKeys { + get { + return KeyboardHandler.ModifierKeys; + } + } + internal override Size SmallIconSize { get{ throw new NotImplementedException(); } } + internal override int MouseButtonCount { get{ throw new NotImplementedException(); } } + internal override bool MouseButtonsSwapped { get{ throw new NotImplementedException(); } } + internal override bool MouseWheelPresent { get{ throw new NotImplementedException(); } } + + internal override MouseButtons MouseButtons { + get { + return MouseState; + } + } + + internal override Rectangle VirtualScreen { + get { + return WorkingArea; + } + } + + internal override Rectangle WorkingArea { + get { + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + return new Rectangle ((int)bounds.origin.x, (int)bounds.origin.y, (int)bounds.size.width, (int)bounds.size.height); + } + } + + [MonoTODO] + internal override Screen[] AllScreens { + get { + return null; + } + } + + internal override bool ThemesEnabled { + get { + return XplatUICarbon.themes_enabled; + } + } + + + #endregion + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewConvertPoint (ref Carbon.CGPoint point, IntPtr pView, IntPtr cView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewChangeFeatures (IntPtr aView, ulong bitsin, ulong bitsout); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewFindByID (IntPtr rootWnd, Carbon.HIViewID id, ref IntPtr outPtr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIGrowBoxViewSetTransparent (IntPtr GrowBox, bool transparency); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetRoot (IntPtr hWnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIObjectCreate (IntPtr cfStr, uint what, ref IntPtr hwnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIObjectRegisterSubclass (IntPtr classid, IntPtr superclassid, uint options, Carbon.EventDelegate upp, uint count, Carbon.EventTypeSpec [] list, IntPtr state, ref IntPtr cls); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewPlaceInSuperviewAt (IntPtr view, float x, float y); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewAddSubview (IntPtr parentHnd, IntPtr childHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetPreviousView (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetSuperview (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewRemoveFromSuperview (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetVisible (IntPtr vHnd, bool visible); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool HIViewIsVisible (IntPtr vHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewGetBounds (IntPtr vHnd, ref Carbon.HIRect r); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewScrollRect (IntPtr vHnd, ref Carbon.HIRect rect, float x, float y); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetZOrder (IntPtr hWnd, int cmd, IntPtr oHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewNewTrackingArea (IntPtr inView, IntPtr inShape, UInt64 inID, ref IntPtr outRef); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetWindow (IntPtr aView); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetFrame (IntPtr view_handle, ref Carbon.HIRect bounds); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int HIViewSetNeedsDisplayInRect (IntPtr view_handle, ref Carbon.HIRect rect, bool needs_display); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void SetRect (ref Carbon.Rect r, short left, short top, short right, short bottom); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int ActivateWindow (IntPtr windowHnd, bool inActivate); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern bool IsWindowActive (IntPtr windowHnd); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int SetAutomaticWidgetDragTrackingEnabledForWindow (IntPtr window, bool enabled); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr GetEventDispatcherTarget (); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SendEventToEventTarget (IntPtr evt, IntPtr target); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ReleaseEvent (IntPtr evt); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ReceiveNextEvent (uint evtCount, IntPtr evtTypes, double timeout, bool processEvt, ref IntPtr evt); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool IsWindowCollapsed (IntPtr hWnd); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool IsWindowInStandardState (IntPtr hWnd, IntPtr a, IntPtr b); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CollapseWindow (IntPtr hWnd, bool collapse); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void ZoomWindow (IntPtr hWnd, short partCode, bool front); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetWindowAttributes (IntPtr hWnd, ref Carbon.WindowAttributes outAttributes); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ChangeWindowAttributes (IntPtr hWnd, Carbon.WindowAttributes inAttributes, Carbon.WindowAttributes outAttributes); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int GetGlobalMouse (ref Carbon.QDPoint outData); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int BeginAppModalStateForWindow (IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int EndAppModalStateForWindow (IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int CreateNewWindow (Carbon.WindowClass klass, Carbon.WindowAttributes attributes, ref Carbon.Rect r, ref IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int DisposeWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int ShowWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int HideWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static bool IsWindowVisible (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWindowBounds (IntPtr wHnd, uint reg, ref Carbon.Rect rect); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetWindowBounds (IntPtr wHnd, uint reg, ref Carbon.Rect rect); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWidgetTitleWithCFString (IntPtr hWnd, IntPtr titleCFStr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWindowTitleWithCFString (IntPtr hWnd, IntPtr titleCFStr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static IntPtr __CFStringMakeConstantString (string cString); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int CFRelease (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static short GetMBarHeight (); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void AlertSoundPlay (); + + #region Cursor imports + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static Carbon.HIRect CGDisplayBounds (IntPtr displayID); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGMainDisplayID (); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayShowCursor (IntPtr display); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayHideCursor (IntPtr display); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayMoveCursorToPoint (IntPtr display, Carbon.CGPoint point); + #endregion + + #region Process imports + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetCurrentProcess (ref Carbon.ProcessSerialNumber psn); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int TransformProcessType (ref Carbon.ProcessSerialNumber psn, uint type); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetFrontProcess (ref Carbon.ProcessSerialNumber psn); + #endregion + + #region Dock tile imports + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGColorSpaceCreateDeviceRGB(); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGDataProviderCreateWithData (IntPtr info, IntPtr [] data, int size, IntPtr releasefunc); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGImageCreate (int width, int height, int bitsPerComponent, int bitsPerPixel, int bytesPerRow, IntPtr colorspace, uint bitmapInfo, IntPtr provider, IntPtr decode, int shouldInterpolate, int intent); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void SetApplicationDockTileImage(IntPtr imageRef); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void RestoreApplicationDockTileImage(); + #endregion + } +} |
